refactor languages module to domain/controller and release 0.254 update package
This commit is contained in:
@@ -183,3 +183,29 @@ Uzytkownicy panelu administratora.
|
||||
**Uzywane w:** `Domain\User\UserRepository`, `admin\Controllers\UsersController`, `admin\factory\Users`
|
||||
|
||||
**Aktualizacja 2026-02-12:** uzycia `pp_users` sa prowadzone przez `Domain\\User\\UserRepository` (legacy `admin\\factory\\Users` usunieto).
|
||||
|
||||
## pp_langs
|
||||
Jezyki panelu i frontendu.
|
||||
|
||||
| Kolumna | Opis |
|
||||
|---------|------|
|
||||
| id | PK (2-literowe ID jezyka, np. pl, en) |
|
||||
| name | Nazwa jezyka |
|
||||
| status | 1 = aktywny, 0 = nieaktywny |
|
||||
| start | 1 = domyslny jezyk |
|
||||
| o | Kolejnosc |
|
||||
|
||||
**Uzywane w:** `Domain\\Languages\\LanguagesRepository`, `admin\\Controllers\\LanguagesController`, `admin\\factory\\Languages`, `front\\factory\\Languages`
|
||||
|
||||
## pp_langs_translations
|
||||
Slownik tlumaczen panelu/frontendu.
|
||||
|
||||
| Kolumna | Opis |
|
||||
|---------|------|
|
||||
| id | PK |
|
||||
| text | Klucz/tekst bazowy |
|
||||
| <lang_id> | Kolumny dynamiczne per jezyk (np. pl, en) |
|
||||
|
||||
**Uzywane w:** `Domain\\Languages\\LanguagesRepository`, `admin\\Controllers\\LanguagesController`, `front\\factory\\Languages`
|
||||
|
||||
**Aktualizacja 2026-02-12:** modul jezykow i tlumaczen (`pp_langs`, `pp_langs_translations`) obslugiwany przez `Domain\\Languages\\LanguagesRepository`.
|
||||
|
||||
@@ -391,3 +391,14 @@ Aktualnie w suite są też testy modułów `Dictionaries`, `Articles` i `Users`
|
||||
- Usuni<6E>to legacy klasy: `autoload/admin/controls/class.Users.php`, `autoload/admin/factory/class.Users.php`, `autoload/admin/view/class.Users.php`.
|
||||
- Walidacja: przy w<><77>czonym 2FA pole `twofa_email` jest wymagane.
|
||||
- Widoki users przeniesione na `components/table-list` i `components/form-edit`.
|
||||
- **NOWE:** `Domain\\Languages\\LanguagesRepository` - repozytorium jezykow i tlumaczen (lista, zapis, usuwanie, max_order)
|
||||
- **NOWE:** `admin\\Controllers\\LanguagesController` - kontroler DI (`list/view_list`, `language_*`, `translation_*`)
|
||||
- **UPDATE:** modul Languages przepiety z `grid/gridEdit` na `components/table-list` i `components/form-edit`
|
||||
- **CLEANUP:** usuniete legacy klasy `autoload/admin/controls/class.Languages.php`, `autoload/admin/view/class.Languages.php`
|
||||
- Testy: 130 tests, 301 assertions
|
||||
|
||||
## Aktualizacja 2026-02-12 (Languages final)
|
||||
- Dodano `Domain\\Languages\\LanguagesRepository` oraz `admin\\Controllers\\LanguagesController`.
|
||||
- Modul `/admin/languages/` (jezyki + tlumaczenia) dziala na nowym routingu DI.
|
||||
- Widoki jezykow przepiete na `components/table-list` i `components/form-edit`.
|
||||
- Usunieto legacy: `autoload/admin/controls/class.Languages.php`, `autoload/admin/view/class.Languages.php`.
|
||||
|
||||
@@ -574,3 +574,19 @@ Gdy `persist = true`:
|
||||
- `UsersController` obsluguje: `list/view_list`, `user_edit`, `user_save`, `user_delete`, `login_form`, `twofa`.
|
||||
- Dodano walidacje warunkowa: `twofa_email` wymagany gdy `twofa_enabled = 1`.
|
||||
- Widoki users migrowane z `grid/gridEdit` na `table-list` i `form-edit`.
|
||||
|
||||
## Aktualizacja 2026-02-12 - Languages
|
||||
- **NOWE:** `Domain\\Languages\\LanguagesRepository` (languages + translations CRUD/list)
|
||||
- **NOWE:** `admin\\Controllers\\LanguagesController` (DI)
|
||||
- **UPDATE:** `admin\\Site` - nowy kontroler DI dla modulu `Languages`
|
||||
- **UPDATE:** `admin\\factory\\Languages` jako fasada delegujaca do repozytorium
|
||||
- **UPDATE:** widoki `languages/*` migrowane na `components/table-list` i `components/form-edit`
|
||||
- **CLEANUP:** usunieto legacy `admin\\controls\\Languages` i `admin\\view\\Languages`
|
||||
- Testy po zmianie: 130 tests, 301 assertions
|
||||
|
||||
## Aktualizacja 2026-02-12 (Languages final)
|
||||
- **NOWE:** `Domain\\Languages\\LanguagesRepository` (list/save/delete dla jezykow i tlumaczen)
|
||||
- **NOWE:** `admin\\Controllers\\LanguagesController` (DI) dla akcji `view_list/list`, `language_*`, `translation_*`
|
||||
- **UPDATE:** `admin\\factory\\Languages` jako fasada delegujaca do repozytorium
|
||||
- **CLEANUP:** usunieto legacy `admin\\controls\\Languages` oraz `admin\\view\\Languages`
|
||||
- **UPDATE:** poprawki globalne `components/table-list` dla krotkich kolumn/filtr<74>w
|
||||
|
||||
20
TESTING.md
20
TESTING.md
@@ -164,3 +164,23 @@ Ostatnio zweryfikowano: 2026-02-12
|
||||
```text
|
||||
OK (120 tests, 262 assertions)
|
||||
```
|
||||
|
||||
Aktualizacja po migracji Languages (2026-02-12):
|
||||
```text
|
||||
OK (130 tests, 301 assertions)
|
||||
```
|
||||
|
||||
Nowe testy dodane 2026-02-12:
|
||||
- `tests/Unit/Domain/Languages/LanguagesRepositoryTest.php`
|
||||
- `tests/Unit/admin/Controllers/LanguagesControllerTest.php`
|
||||
|
||||
## Aktualizacja suite (release 0.254)
|
||||
Ostatnio zweryfikowano: 2026-02-12
|
||||
|
||||
```text
|
||||
OK (130 tests, 301 assertions)
|
||||
```
|
||||
|
||||
Nowe testy dodane 2026-02-12:
|
||||
- `tests/Unit/Domain/Languages/LanguagesRepositoryTest.php`
|
||||
- `tests/Unit/admin/Controllers/LanguagesControllerTest.php`
|
||||
|
||||
@@ -23,11 +23,11 @@ $isCompactColumn = function(array $column): bool {
|
||||
$key = strtolower(trim((string)($column['key'] ?? '')));
|
||||
$label = strtolower(trim((string)($column['label'] ?? '')));
|
||||
|
||||
if (in_array($key, ['status', 'active', 'enabled', 'is_active'], true)) {
|
||||
if (in_array($key, ['status', 'active', 'enabled', 'is_active', 'start', 'default'], true)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (in_array($label, ['status', 'aktywny', 'aktywnosc', 'active'], true)) {
|
||||
if (in_array($label, ['status', 'aktywny', 'aktywnosc', 'active', 'domyslny', 'domyślny', 'default'], true)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -277,9 +277,9 @@ $isCompactColumn = function(array $column): bool {
|
||||
}
|
||||
|
||||
.js-table-filters-form .js-filter-compact-select {
|
||||
width: auto;
|
||||
min-width: 110px;
|
||||
max-width: 140px;
|
||||
width: 100%;
|
||||
min-width: 0;
|
||||
max-width: none;
|
||||
}
|
||||
|
||||
.table-list-table th.table-col-compact,
|
||||
|
||||
@@ -1,101 +1,2 @@
|
||||
<?
|
||||
global $db;
|
||||
<?= \Tpl::view('components/form-edit', ['form' => $this->form]); ?>
|
||||
|
||||
ob_start();
|
||||
?>
|
||||
<?
|
||||
if ( $this -> language['id'] )
|
||||
{
|
||||
echo \Html::input(
|
||||
array(
|
||||
'type' => 'hidden',
|
||||
'name' => 'id',
|
||||
'value' => $this -> language['id']
|
||||
)
|
||||
);
|
||||
echo \Html::input(
|
||||
array(
|
||||
'type' => 'hidden',
|
||||
'name' => 'o',
|
||||
'value' => $this -> language['o']
|
||||
)
|
||||
);
|
||||
echo \Html::input(
|
||||
array(
|
||||
'label' => 'Język',
|
||||
'type' => 'text',
|
||||
'class' => 'require',
|
||||
'name' => 'name',
|
||||
'value' => $this -> language['name']
|
||||
)
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
echo \Html::input(
|
||||
array(
|
||||
'type' => 'hidden',
|
||||
'name' => 'o',
|
||||
'value' => $this -> order + 1
|
||||
)
|
||||
);
|
||||
echo \Html::input(
|
||||
array(
|
||||
'label' => 'Język',
|
||||
'type' => 'text',
|
||||
'class' => 'require',
|
||||
'name' => 'name'
|
||||
)
|
||||
);
|
||||
echo \Html::input(
|
||||
array(
|
||||
'label' => 'ID (2 znaki)',
|
||||
'class' => 'require',
|
||||
'type' => 'text',
|
||||
'name' => 'id'
|
||||
)
|
||||
);
|
||||
}
|
||||
?>
|
||||
<?= \Html::input_switch(
|
||||
array(
|
||||
'label' => 'Aktywny',
|
||||
'name' => 'status',
|
||||
'checked' => $this -> language['status'] == 1 ? true : false
|
||||
)
|
||||
);?>
|
||||
<?= \Html::input_switch(
|
||||
array(
|
||||
'label' => 'Domyślny',
|
||||
'name' => 'start',
|
||||
'checked' => $this -> language['start'] == 1 ? true : false
|
||||
)
|
||||
);?>
|
||||
<?
|
||||
$out = ob_get_clean();
|
||||
|
||||
$grid = new \gridEdit;
|
||||
$grid -> id = 'language-edit';
|
||||
$grid -> gdb_opt = $gdb;
|
||||
$grid -> include_plugins = true;
|
||||
$grid -> title = 'Edycja języka';
|
||||
$grid -> external_code = $out;
|
||||
$grid -> actions = [
|
||||
'save' => [ 'url' => '/admin/languages/language_save/', 'back_url' => '/admin/languages/view_list/' ],
|
||||
'cancel' => [ 'url' => '/admin/languages/view_list/' ]
|
||||
];
|
||||
$grid -> persist_edit = true;
|
||||
$grid -> id_param = 'id';
|
||||
echo $grid -> draw();
|
||||
?>
|
||||
<script type="text/javascript">
|
||||
$( function()
|
||||
{
|
||||
disable_menu();
|
||||
|
||||
$( 'input[type="text"].date' ).datetimepicker({
|
||||
format: "YYYY-MM-DD",
|
||||
pickTime: false
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@@ -1,58 +1,2 @@
|
||||
<?php
|
||||
global $gdb;
|
||||
<?= \Tpl::view('components/table-list', ['list' => $this->viewModel]); ?>
|
||||
|
||||
$grid = new \grid( 'pp_langs' );
|
||||
$grid -> gdb_opt = $gdb;
|
||||
$grid -> order = [ 'column' => 'o', 'type' => 'ASC' ];
|
||||
$grid -> search = [
|
||||
[ 'name' => 'Język', 'db' => 'name', 'type' => 'text' ],
|
||||
[ 'name' => 'Aktywny', 'db' => 'status', 'type' => 'select', 'replace' => [ 'array' => [ 0 => 'nie', 1 => 'tak' ] ] ],
|
||||
[ 'name' => 'Domyślny', 'db' => 'start', 'type' => 'select', 'replace' => [ 'array' => [ 0 => 'nie', 1 => 'tak' ] ] ]
|
||||
];
|
||||
$grid -> columns_view = [
|
||||
[
|
||||
'name' => 'Lp.',
|
||||
'th' => [ 'class' => 'g-lp' ],
|
||||
'td' => [ 'class' => 'g-center' ],
|
||||
'autoincrement' => true
|
||||
],
|
||||
[
|
||||
'name' => 'Domyślny',
|
||||
'db' => 'start',
|
||||
'th' => [ 'class' => 'g-center', 'style' => 'width: 150px;' ],
|
||||
'td' => [ 'class' => 'g-center' ],
|
||||
'php' => 'if ( [start] ) echo "<span class=\'text-system\'>tak</span>"; else echo "nie";'
|
||||
],
|
||||
[
|
||||
'name' => 'Aktywny',
|
||||
'db' => 'status',
|
||||
'replace' => [ 'array' => [ 0 => '<span style="color: #FF0000;">nie</span>', 1 => 'tak' ] ],
|
||||
'th' => [ 'class' => 'g-center', 'style' => 'width: 150px;' ],
|
||||
'td' => [ 'class' => 'g-center' ]
|
||||
],
|
||||
[
|
||||
'name' => 'Język',
|
||||
'db' => 'name'
|
||||
],
|
||||
[
|
||||
'name' => 'Edytuj',
|
||||
'action' => [ 'type' => 'edit', 'url' => '/admin/languages/language_edit/id=[id]' ],
|
||||
'th' => [ 'class' => 'g-center', 'style' => 'width: 70px;' ],
|
||||
'td' => [ 'class' => 'g-center' ]
|
||||
],
|
||||
[
|
||||
'name' => 'Usuń',
|
||||
'action' => [ 'type' => 'delete', 'url' => '/admin/languages/language_delete/id=[id]' ],
|
||||
'th' => [ 'class' => 'g-center', 'style' => 'width: 70px;' ],
|
||||
'td' => [ 'class' => 'g-center' ]
|
||||
]
|
||||
];
|
||||
$grid -> buttons = [
|
||||
[
|
||||
'label' => 'Dodaj język',
|
||||
'url' => '/admin/languages/language_edit/',
|
||||
'icon' => 'fa-plus-circle',
|
||||
'class' => 'btn-success'
|
||||
]
|
||||
];
|
||||
echo $grid -> draw();
|
||||
@@ -1,60 +1,2 @@
|
||||
<?
|
||||
global $db;
|
||||
<?= \Tpl::view('components/form-edit', ['form' => $this->form]); ?>
|
||||
|
||||
ob_start();
|
||||
?>
|
||||
<?
|
||||
echo \Html::input(
|
||||
array(
|
||||
'type' => 'text',
|
||||
'label' => 'Tekst',
|
||||
'name' => 'text',
|
||||
'class' => 'require',
|
||||
'value' => $this -> translation['text']
|
||||
)
|
||||
);
|
||||
|
||||
if ( is_array( $this -> languages ) ): foreach ( $this -> languages as $language ):
|
||||
echo \Html::input(
|
||||
array(
|
||||
'type' => 'text',
|
||||
'label' => $language['name'],
|
||||
'name' => $language['id'],
|
||||
'value' => $this -> translation[$language['id']]
|
||||
) );
|
||||
endforeach;
|
||||
endif;
|
||||
$out = ob_get_clean();
|
||||
|
||||
$grid = new \gridEdit;
|
||||
$grid -> id = 'translation-edit';
|
||||
$grid -> gdb_opt = $gdb;
|
||||
$grid -> include_plugins = true;
|
||||
$grid -> title = 'Edycja tłumaczenia';
|
||||
$grid -> fields = [
|
||||
[
|
||||
'db' => 'id',
|
||||
'type' => 'hidden',
|
||||
'value' => $this -> translation['id']
|
||||
]
|
||||
];
|
||||
$grid -> external_code = $out;
|
||||
$grid -> actions = [
|
||||
'save' => [ 'url' => '/admin/languages/translation_save/', 'back_url' => '/admin/languages/translation_list/' ],
|
||||
'cancel' => [ 'url' => '/admin/languages/translation_list/' ]
|
||||
];
|
||||
$grid -> persist_edit = true;
|
||||
$grid -> id_param = 'id';
|
||||
echo $grid -> draw();
|
||||
?>
|
||||
<script type="text/javascript">
|
||||
$(function ()
|
||||
{
|
||||
disable_menu();
|
||||
|
||||
$('input[type="text"].date').datetimepicker({
|
||||
format: "YYYY-MM-DD",
|
||||
pickTime: false
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@@ -1,44 +1,2 @@
|
||||
<?php
|
||||
global $gdb;
|
||||
<?= \Tpl::view('components/table-list', ['list' => $this->viewModel]); ?>
|
||||
|
||||
$grid = new \grid( 'pp_langs_translations' );
|
||||
$grid -> gdb_opt = $gdb;
|
||||
$grid -> order = [ 'column' => 'text', 'type' => 'ASC' ];
|
||||
$grid -> search = [
|
||||
[ 'name' => 'Tekst', 'db' => 'text', 'type' => 'text' ]
|
||||
];
|
||||
$grid -> columns_view = [
|
||||
[
|
||||
'name' => 'Lp.',
|
||||
'th' => [ 'class' => 'g-lp' ],
|
||||
'td' => [ 'class' => 'g-center' ],
|
||||
'autoincrement' => true
|
||||
],
|
||||
[
|
||||
'name' => 'Tekst',
|
||||
'db' => 'text',
|
||||
'php' => 'echo "<a href=\'/admin/languages/translation_edit/id=[id]\'>[text]</a>";',
|
||||
'sort' => true
|
||||
],
|
||||
[
|
||||
'name' => 'Edytuj',
|
||||
'action' => [ 'type' => 'edit', 'url' => '/admin/languages/translation_edit/id=[id]' ],
|
||||
'th' => [ 'class' => 'g-center', 'style' => 'width: 70px;' ],
|
||||
'td' => [ 'class' => 'g-center' ]
|
||||
],
|
||||
[
|
||||
'name' => 'Usuń',
|
||||
'action' => [ 'type' => 'delete', 'url' => '/admin/languages/translation_delete/id=[id]' ],
|
||||
'th' => [ 'class' => 'g-center', 'style' => 'width: 70px;' ],
|
||||
'td' => [ 'class' => 'g-center' ]
|
||||
]
|
||||
];
|
||||
$grid -> buttons = [
|
||||
[
|
||||
'label' => 'Dodaj tłumaczenie',
|
||||
'url' => '/admin/languages/translation_edit/',
|
||||
'icon' => 'fa-plus-circle',
|
||||
'class' => 'btn-success'
|
||||
]
|
||||
];
|
||||
echo $grid -> draw();
|
||||
330
autoload/Domain/Languages/LanguagesRepository.php
Normal file
330
autoload/Domain/Languages/LanguagesRepository.php
Normal file
@@ -0,0 +1,330 @@
|
||||
<?php
|
||||
namespace Domain\Languages;
|
||||
|
||||
class LanguagesRepository
|
||||
{
|
||||
private const MAX_PER_PAGE = 100;
|
||||
|
||||
private $db;
|
||||
|
||||
public function __construct($db)
|
||||
{
|
||||
$this->db = $db;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array{items: array<int, array<string, mixed>>, total: int}
|
||||
*/
|
||||
public function listForAdmin(
|
||||
array $filters,
|
||||
string $sortColumn = 'o',
|
||||
string $sortDir = 'ASC',
|
||||
int $page = 1,
|
||||
int $perPage = 15
|
||||
): array {
|
||||
$allowedSortColumns = [
|
||||
'id' => 'pl.id',
|
||||
'name' => 'pl.name',
|
||||
'status' => 'pl.status',
|
||||
'start' => 'pl.start',
|
||||
'o' => 'pl.o',
|
||||
];
|
||||
|
||||
$sortSql = $allowedSortColumns[$sortColumn] ?? 'pl.o';
|
||||
$sortDir = strtoupper(trim($sortDir)) === 'DESC' ? 'DESC' : 'ASC';
|
||||
$page = max(1, $page);
|
||||
$perPage = min(self::MAX_PER_PAGE, max(1, $perPage));
|
||||
$offset = ($page - 1) * $perPage;
|
||||
|
||||
$where = ['1 = 1'];
|
||||
$params = [];
|
||||
|
||||
$name = trim((string)($filters['name'] ?? ''));
|
||||
if ($name !== '') {
|
||||
if (strlen($name) > 255) {
|
||||
$name = substr($name, 0, 255);
|
||||
}
|
||||
$where[] = 'pl.name LIKE :name';
|
||||
$params[':name'] = '%' . $name . '%';
|
||||
}
|
||||
|
||||
$status = trim((string)($filters['status'] ?? ''));
|
||||
if ($status === '0' || $status === '1') {
|
||||
$where[] = 'pl.status = :status';
|
||||
$params[':status'] = (int)$status;
|
||||
}
|
||||
|
||||
$start = trim((string)($filters['start'] ?? ''));
|
||||
if ($start === '0' || $start === '1') {
|
||||
$where[] = 'pl.start = :start';
|
||||
$params[':start'] = (int)$start;
|
||||
}
|
||||
|
||||
$whereSql = implode(' AND ', $where);
|
||||
|
||||
$sqlCount = "
|
||||
SELECT COUNT(0)
|
||||
FROM pp_langs AS pl
|
||||
WHERE {$whereSql}
|
||||
";
|
||||
|
||||
$stmtCount = $this->db->query($sqlCount, $params);
|
||||
$countRows = $stmtCount ? $stmtCount->fetchAll() : [];
|
||||
$total = isset($countRows[0][0]) ? (int)$countRows[0][0] : 0;
|
||||
|
||||
$sql = "
|
||||
SELECT
|
||||
pl.id,
|
||||
pl.name,
|
||||
pl.status,
|
||||
pl.start,
|
||||
pl.o
|
||||
FROM pp_langs AS pl
|
||||
WHERE {$whereSql}
|
||||
ORDER BY {$sortSql} {$sortDir}, pl.o ASC, pl.id ASC
|
||||
LIMIT {$perPage} OFFSET {$offset}
|
||||
";
|
||||
|
||||
$stmt = $this->db->query($sql, $params);
|
||||
$items = $stmt ? $stmt->fetchAll() : [];
|
||||
|
||||
return [
|
||||
'items' => is_array($items) ? $items : [],
|
||||
'total' => $total,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array{items: array<int, array<string, mixed>>, total: int}
|
||||
*/
|
||||
public function listTranslationsForAdmin(
|
||||
array $filters,
|
||||
string $sortColumn = 'text',
|
||||
string $sortDir = 'ASC',
|
||||
int $page = 1,
|
||||
int $perPage = 15
|
||||
): array {
|
||||
$allowedSortColumns = [
|
||||
'id' => 'plt.id',
|
||||
'text' => 'plt.text',
|
||||
];
|
||||
|
||||
$sortSql = $allowedSortColumns[$sortColumn] ?? 'plt.text';
|
||||
$sortDir = strtoupper(trim($sortDir)) === 'DESC' ? 'DESC' : 'ASC';
|
||||
$page = max(1, $page);
|
||||
$perPage = min(self::MAX_PER_PAGE, max(1, $perPage));
|
||||
$offset = ($page - 1) * $perPage;
|
||||
|
||||
$where = ['1 = 1'];
|
||||
$params = [];
|
||||
|
||||
$text = trim((string)($filters['text'] ?? ''));
|
||||
if ($text !== '') {
|
||||
if (strlen($text) > 255) {
|
||||
$text = substr($text, 0, 255);
|
||||
}
|
||||
$where[] = 'plt.text LIKE :text';
|
||||
$params[':text'] = '%' . $text . '%';
|
||||
}
|
||||
|
||||
$whereSql = implode(' AND ', $where);
|
||||
|
||||
$sqlCount = "
|
||||
SELECT COUNT(0)
|
||||
FROM pp_langs_translations AS plt
|
||||
WHERE {$whereSql}
|
||||
";
|
||||
|
||||
$stmtCount = $this->db->query($sqlCount, $params);
|
||||
$countRows = $stmtCount ? $stmtCount->fetchAll() : [];
|
||||
$total = isset($countRows[0][0]) ? (int)$countRows[0][0] : 0;
|
||||
|
||||
$sql = "
|
||||
SELECT
|
||||
plt.id,
|
||||
plt.text
|
||||
FROM pp_langs_translations AS plt
|
||||
WHERE {$whereSql}
|
||||
ORDER BY {$sortSql} {$sortDir}, plt.id ASC
|
||||
LIMIT {$perPage} OFFSET {$offset}
|
||||
";
|
||||
|
||||
$stmt = $this->db->query($sql, $params);
|
||||
$items = $stmt ? $stmt->fetchAll() : [];
|
||||
|
||||
return [
|
||||
'items' => is_array($items) ? $items : [],
|
||||
'total' => $total,
|
||||
];
|
||||
}
|
||||
|
||||
public function languageDetails(string $languageId): ?array
|
||||
{
|
||||
$language = $this->db->get('pp_langs', '*', ['id' => $languageId]);
|
||||
return $language ?: null;
|
||||
}
|
||||
|
||||
public function translationDetails(int $translationId): ?array
|
||||
{
|
||||
$translation = $this->db->get('pp_langs_translations', '*', ['id' => $translationId]);
|
||||
return $translation ?: null;
|
||||
}
|
||||
|
||||
public function maxOrder(): int
|
||||
{
|
||||
$max = $this->db->max('pp_langs', 'o');
|
||||
return $max ? (int)$max : 0;
|
||||
}
|
||||
|
||||
public function languagesList(bool $onlyActive = false): array
|
||||
{
|
||||
$where = [];
|
||||
if ($onlyActive) {
|
||||
$where['status'] = 1;
|
||||
}
|
||||
|
||||
$rows = $this->db->select('pp_langs', '*', array_merge(['ORDER' => ['o' => 'ASC']], $where));
|
||||
return is_array($rows) ? $rows : [];
|
||||
}
|
||||
|
||||
public function deleteLanguage(string $languageId): bool
|
||||
{
|
||||
$languageId = $this->sanitizeLanguageId($languageId);
|
||||
if ($languageId === null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((int)$this->db->count('pp_langs') <= 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!$this->db->count('pp_langs', ['id' => $languageId])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$dropResult = $this->db->query('ALTER TABLE pp_langs_translations DROP COLUMN `' . $languageId . '`');
|
||||
if (!$dropResult) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$deleteResult = $this->db->delete('pp_langs', ['id' => $languageId]);
|
||||
if (!$deleteResult) {
|
||||
return false;
|
||||
}
|
||||
|
||||
\S::htacces();
|
||||
\S::delete_dir('../temp/');
|
||||
return true;
|
||||
}
|
||||
|
||||
public function saveLanguage(string $languageId, string $name, $status, $start, int $order): ?string
|
||||
{
|
||||
$languageId = $this->sanitizeLanguageId($languageId);
|
||||
if ($languageId === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$statusVal = $this->toSwitchValue($status);
|
||||
$startVal = $this->toSwitchValue($start);
|
||||
|
||||
$exists = (bool)$this->db->count('pp_langs', ['id' => $languageId]);
|
||||
|
||||
if ($startVal === 1) {
|
||||
$this->db->update('pp_langs', ['start' => 0], ['id[!]' => $languageId]);
|
||||
}
|
||||
|
||||
if ($exists) {
|
||||
$this->db->update('pp_langs', [
|
||||
'status' => $statusVal,
|
||||
'start' => $startVal,
|
||||
'name' => $name,
|
||||
'o' => $order,
|
||||
], [
|
||||
'id' => $languageId,
|
||||
]);
|
||||
} else {
|
||||
$addResult = $this->db->query('ALTER TABLE pp_langs_translations ADD COLUMN `' . $languageId . '` TEXT NULL DEFAULT NULL');
|
||||
if (!$addResult) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$insertResult = $this->db->insert('pp_langs', [
|
||||
'id' => $languageId,
|
||||
'name' => $name,
|
||||
'status' => $statusVal,
|
||||
'start' => $startVal,
|
||||
'o' => $order,
|
||||
]);
|
||||
if (!$insertResult) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
if (!(int)$this->db->count('pp_langs', ['start' => 1])) {
|
||||
$idTmp = (string)$this->db->get('pp_langs', 'id', ['ORDER' => ['o' => 'ASC']]);
|
||||
if ($idTmp !== '') {
|
||||
$this->db->update('pp_langs', ['start' => 1], ['id' => $idTmp]);
|
||||
}
|
||||
}
|
||||
|
||||
\S::htacces();
|
||||
\S::delete_dir('../temp/');
|
||||
return $languageId;
|
||||
}
|
||||
|
||||
public function deleteTranslation(int $translationId): bool
|
||||
{
|
||||
$result = $this->db->delete('pp_langs_translations', ['id' => $translationId]);
|
||||
return (bool)$result;
|
||||
}
|
||||
|
||||
public function saveTranslation(int $translationId, string $text, array $translations): ?int
|
||||
{
|
||||
if ($translationId > 0) {
|
||||
$this->db->update('pp_langs_translations', ['text' => $text], ['id' => $translationId]);
|
||||
} else {
|
||||
$insertResult = $this->db->insert('pp_langs_translations', ['text' => $text]);
|
||||
if (!$insertResult) {
|
||||
return null;
|
||||
}
|
||||
$translationId = (int)$this->db->id();
|
||||
}
|
||||
|
||||
if ($translationId <= 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
foreach ($translations as $languageId => $value) {
|
||||
$safeLanguageId = $this->sanitizeLanguageId((string)$languageId);
|
||||
if ($safeLanguageId === null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$this->db->update('pp_langs_translations', [
|
||||
$safeLanguageId => (string)$value,
|
||||
], [
|
||||
'id' => $translationId,
|
||||
]);
|
||||
}
|
||||
|
||||
\S::htacces();
|
||||
\S::delete_dir('../temp/');
|
||||
return $translationId;
|
||||
}
|
||||
|
||||
private function sanitizeLanguageId(string $languageId): ?string
|
||||
{
|
||||
$languageId = strtolower(trim($languageId));
|
||||
if (!preg_match('/^[a-z]{2}$/', $languageId)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $languageId;
|
||||
}
|
||||
|
||||
private function toSwitchValue($value): int
|
||||
{
|
||||
return ($value === 'on' || $value === 1 || $value === '1' || $value === true) ? 1 : 0;
|
||||
}
|
||||
}
|
||||
|
||||
560
autoload/admin/Controllers/LanguagesController.php
Normal file
560
autoload/admin/Controllers/LanguagesController.php
Normal file
@@ -0,0 +1,560 @@
|
||||
<?php
|
||||
namespace admin\Controllers;
|
||||
|
||||
use Domain\Languages\LanguagesRepository;
|
||||
use admin\ViewModels\Forms\FormAction;
|
||||
use admin\ViewModels\Forms\FormEditViewModel;
|
||||
use admin\ViewModels\Forms\FormField;
|
||||
use admin\Support\Forms\FormRequestHandler;
|
||||
|
||||
class LanguagesController
|
||||
{
|
||||
private LanguagesRepository $repository;
|
||||
private FormRequestHandler $formHandler;
|
||||
|
||||
public function __construct(LanguagesRepository $repository)
|
||||
{
|
||||
$this->repository = $repository;
|
||||
$this->formHandler = new FormRequestHandler();
|
||||
}
|
||||
|
||||
public function list(): string
|
||||
{
|
||||
$sortableColumns = ['o', 'name', 'status', 'start'];
|
||||
|
||||
$filterDefinitions = [
|
||||
[
|
||||
'key' => 'name',
|
||||
'label' => 'Jezyk',
|
||||
'type' => 'text',
|
||||
],
|
||||
[
|
||||
'key' => 'status',
|
||||
'label' => 'Aktywny',
|
||||
'type' => 'select',
|
||||
'options' => [
|
||||
'' => '- aktywny -',
|
||||
'1' => 'tak',
|
||||
'0' => 'nie',
|
||||
],
|
||||
],
|
||||
[
|
||||
'key' => 'start',
|
||||
'label' => 'Domyslny',
|
||||
'type' => 'select',
|
||||
'options' => [
|
||||
'' => '- domyslny -',
|
||||
'1' => 'tak',
|
||||
'0' => 'nie',
|
||||
],
|
||||
],
|
||||
];
|
||||
|
||||
$listRequest = \admin\Support\TableListRequestFactory::fromRequest(
|
||||
$filterDefinitions,
|
||||
$sortableColumns,
|
||||
'o'
|
||||
);
|
||||
|
||||
$sortDir = $listRequest['sortDir'];
|
||||
if (trim((string)\S::get('sort')) === '') {
|
||||
$sortDir = 'ASC';
|
||||
}
|
||||
|
||||
$result = $this->repository->listForAdmin(
|
||||
$listRequest['filters'],
|
||||
$listRequest['sortColumn'],
|
||||
$sortDir,
|
||||
$listRequest['page'],
|
||||
$listRequest['perPage']
|
||||
);
|
||||
|
||||
$rows = [];
|
||||
$lp = ($listRequest['page'] - 1) * $listRequest['perPage'] + 1;
|
||||
foreach ($result['items'] as $item) {
|
||||
$id = (string)($item['id'] ?? '');
|
||||
$name = trim((string)($item['name'] ?? ''));
|
||||
|
||||
$rows[] = [
|
||||
'lp' => $lp++ . '.',
|
||||
'start' => ((int)($item['start'] ?? 0) === 1) ? '<span class="text-system">tak</span>' : 'nie',
|
||||
'status' => ((int)($item['status'] ?? 0) === 1) ? 'tak' : '<span style="color: #FF0000;">nie</span>',
|
||||
'name' => '<a href="/admin/languages/language_edit/id=' . $id . '">' . htmlspecialchars($name, ENT_QUOTES, 'UTF-8') . '</a>',
|
||||
'_actions' => [
|
||||
[
|
||||
'label' => 'Edytuj',
|
||||
'url' => '/admin/languages/language_edit/id=' . $id,
|
||||
'class' => 'btn btn-xs btn-primary',
|
||||
],
|
||||
[
|
||||
'label' => 'Usun',
|
||||
'url' => '/admin/languages/language_delete/id=' . $id,
|
||||
'class' => 'btn btn-xs btn-danger',
|
||||
'confirm' => 'Na pewno chcesz usunac wybrany jezyk?',
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
$total = (int)$result['total'];
|
||||
$totalPages = max(1, (int)ceil($total / $listRequest['perPage']));
|
||||
|
||||
$viewModel = new \admin\ViewModels\Common\PaginatedTableViewModel(
|
||||
[
|
||||
['key' => 'lp', 'label' => 'Lp.', 'class' => 'text-center', 'sortable' => false],
|
||||
['key' => 'start', 'sort_key' => 'start', 'label' => 'Domyslny', 'class' => 'text-center', 'sortable' => true, 'raw' => true],
|
||||
['key' => 'status', 'sort_key' => 'status', 'label' => 'Aktywny', 'class' => 'text-center', 'sortable' => true, 'raw' => true],
|
||||
['key' => 'name', 'sort_key' => 'name', 'label' => 'Jezyk', 'sortable' => true, 'raw' => true],
|
||||
],
|
||||
$rows,
|
||||
$listRequest['viewFilters'],
|
||||
[
|
||||
'column' => $listRequest['sortColumn'],
|
||||
'dir' => $sortDir,
|
||||
],
|
||||
[
|
||||
'page' => $listRequest['page'],
|
||||
'per_page' => $listRequest['perPage'],
|
||||
'total' => $total,
|
||||
'total_pages' => $totalPages,
|
||||
],
|
||||
array_merge($listRequest['queryFilters'], [
|
||||
'sort' => $listRequest['sortColumn'],
|
||||
'dir' => $sortDir,
|
||||
'per_page' => $listRequest['perPage'],
|
||||
]),
|
||||
$listRequest['perPageOptions'],
|
||||
$sortableColumns,
|
||||
'/admin/languages/view_list/',
|
||||
'Brak danych w tabeli.',
|
||||
'/admin/languages/language_edit/',
|
||||
'Dodaj jezyk'
|
||||
);
|
||||
|
||||
return \Tpl::view('languages/languages-list', [
|
||||
'viewModel' => $viewModel,
|
||||
]);
|
||||
}
|
||||
|
||||
public function view_list(): string
|
||||
{
|
||||
return $this->list();
|
||||
}
|
||||
|
||||
public function language_edit(): string
|
||||
{
|
||||
$languageId = trim((string)\S::get('id'));
|
||||
$language = $this->repository->languageDetails($languageId) ?? [];
|
||||
$validationErrors = $_SESSION['form_errors'][$this->getLanguageFormId()] ?? null;
|
||||
if ($validationErrors) {
|
||||
unset($_SESSION['form_errors'][$this->getLanguageFormId()]);
|
||||
}
|
||||
|
||||
return \Tpl::view('languages/language-edit', [
|
||||
'form' => $this->buildLanguageFormViewModel($language, $this->repository->maxOrder(), $validationErrors),
|
||||
]);
|
||||
}
|
||||
|
||||
public function language_save(): void
|
||||
{
|
||||
$legacyValues = \S::get('values');
|
||||
if ($legacyValues) {
|
||||
$values = json_decode((string)$legacyValues, true);
|
||||
$response = ['status' => 'error', 'msg' => 'Podczas zapisywania jezyka wystapil blad.'];
|
||||
|
||||
if (is_array($values)) {
|
||||
$savedId = $this->repository->saveLanguage(
|
||||
(string)($values['id'] ?? ''),
|
||||
(string)($values['name'] ?? ''),
|
||||
$values['status'] ?? 0,
|
||||
$values['start'] ?? 0,
|
||||
(int)($values['o'] ?? 0)
|
||||
);
|
||||
if ($savedId) {
|
||||
$response = ['status' => 'ok', 'msg' => 'Jezyk zostal zapisany.', 'id' => $savedId];
|
||||
}
|
||||
}
|
||||
|
||||
echo json_encode($response);
|
||||
exit;
|
||||
}
|
||||
|
||||
$languageId = trim((string)\S::get('id'));
|
||||
$language = $this->repository->languageDetails($languageId) ?? [];
|
||||
$viewModel = $this->buildLanguageFormViewModel($language, $this->repository->maxOrder());
|
||||
|
||||
$result = $this->formHandler->handleSubmit($viewModel, $_POST);
|
||||
if (!$result['success']) {
|
||||
$_SESSION['form_errors'][$this->getLanguageFormId()] = $result['errors'];
|
||||
echo json_encode(['success' => false, 'errors' => $result['errors']]);
|
||||
exit;
|
||||
}
|
||||
|
||||
$data = $result['data'];
|
||||
$requestId = strtolower(trim((string)\S::get('id')));
|
||||
$idFromData = strtolower(trim((string)($data['id'] ?? '')));
|
||||
$id = $idFromData !== '' ? $idFromData : $requestId;
|
||||
if (!preg_match('/^[a-z]{2}$/', $id)) {
|
||||
echo json_encode([
|
||||
'success' => false,
|
||||
'errors' => ['id' => 'ID jezyka musi miec 2 litery (np. pl, en).'],
|
||||
]);
|
||||
exit;
|
||||
}
|
||||
|
||||
$savedId = $this->repository->saveLanguage(
|
||||
$id,
|
||||
trim((string)($data['name'] ?? '')),
|
||||
$data['status'] ?? 0,
|
||||
$data['start'] ?? 0,
|
||||
(int)($data['o'] ?? 0)
|
||||
);
|
||||
|
||||
if ($savedId) {
|
||||
echo json_encode([
|
||||
'success' => true,
|
||||
'id' => $savedId,
|
||||
'message' => 'Jezyk zostal zapisany.',
|
||||
]);
|
||||
exit;
|
||||
}
|
||||
|
||||
echo json_encode([
|
||||
'success' => false,
|
||||
'errors' => ['general' => 'Podczas zapisywania jezyka wystapil blad.'],
|
||||
]);
|
||||
exit;
|
||||
}
|
||||
|
||||
public function language_delete(): void
|
||||
{
|
||||
if ($this->repository->deleteLanguage((string)\S::get('id'))) {
|
||||
\S::alert('Jezyk zostal usuniety.');
|
||||
}
|
||||
|
||||
header('Location: /admin/languages/view_list/');
|
||||
exit;
|
||||
}
|
||||
|
||||
public function translation_list(): string
|
||||
{
|
||||
$sortableColumns = ['text', 'id'];
|
||||
$filterDefinitions = [
|
||||
[
|
||||
'key' => 'text',
|
||||
'label' => 'Tekst',
|
||||
'type' => 'text',
|
||||
],
|
||||
];
|
||||
|
||||
$listRequest = \admin\Support\TableListRequestFactory::fromRequest(
|
||||
$filterDefinitions,
|
||||
$sortableColumns,
|
||||
'text'
|
||||
);
|
||||
|
||||
$sortDir = $listRequest['sortDir'];
|
||||
if (trim((string)\S::get('sort')) === '') {
|
||||
$sortDir = 'ASC';
|
||||
}
|
||||
|
||||
$result = $this->repository->listTranslationsForAdmin(
|
||||
$listRequest['filters'],
|
||||
$listRequest['sortColumn'],
|
||||
$sortDir,
|
||||
$listRequest['page'],
|
||||
$listRequest['perPage']
|
||||
);
|
||||
|
||||
$rows = [];
|
||||
$lp = ($listRequest['page'] - 1) * $listRequest['perPage'] + 1;
|
||||
foreach ($result['items'] as $item) {
|
||||
$id = (int)($item['id'] ?? 0);
|
||||
$text = trim((string)($item['text'] ?? ''));
|
||||
|
||||
$rows[] = [
|
||||
'lp' => $lp++ . '.',
|
||||
'text' => '<a href="/admin/languages/translation_edit/id=' . $id . '">' . htmlspecialchars($text, ENT_QUOTES, 'UTF-8') . '</a>',
|
||||
'_actions' => [
|
||||
[
|
||||
'label' => 'Edytuj',
|
||||
'url' => '/admin/languages/translation_edit/id=' . $id,
|
||||
'class' => 'btn btn-xs btn-primary',
|
||||
],
|
||||
[
|
||||
'label' => 'Usun',
|
||||
'url' => '/admin/languages/translation_delete/id=' . $id,
|
||||
'class' => 'btn btn-xs btn-danger',
|
||||
'confirm' => 'Na pewno chcesz usunac wybrane tlumaczenie?',
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
$total = (int)$result['total'];
|
||||
$totalPages = max(1, (int)ceil($total / $listRequest['perPage']));
|
||||
|
||||
$viewModel = new \admin\ViewModels\Common\PaginatedTableViewModel(
|
||||
[
|
||||
['key' => 'lp', 'label' => 'Lp.', 'class' => 'text-center', 'sortable' => false],
|
||||
['key' => 'text', 'sort_key' => 'text', 'label' => 'Tekst', 'sortable' => true, 'raw' => true],
|
||||
],
|
||||
$rows,
|
||||
$listRequest['viewFilters'],
|
||||
[
|
||||
'column' => $listRequest['sortColumn'],
|
||||
'dir' => $sortDir,
|
||||
],
|
||||
[
|
||||
'page' => $listRequest['page'],
|
||||
'per_page' => $listRequest['perPage'],
|
||||
'total' => $total,
|
||||
'total_pages' => $totalPages,
|
||||
],
|
||||
array_merge($listRequest['queryFilters'], [
|
||||
'sort' => $listRequest['sortColumn'],
|
||||
'dir' => $sortDir,
|
||||
'per_page' => $listRequest['perPage'],
|
||||
]),
|
||||
$listRequest['perPageOptions'],
|
||||
$sortableColumns,
|
||||
'/admin/languages/translation_list/',
|
||||
'Brak danych w tabeli.',
|
||||
'/admin/languages/translation_edit/',
|
||||
'Dodaj tlumaczenie'
|
||||
);
|
||||
|
||||
return \Tpl::view('languages/translations-list', [
|
||||
'viewModel' => $viewModel,
|
||||
]);
|
||||
}
|
||||
|
||||
public function translation_edit(): string
|
||||
{
|
||||
$translationId = (int)\S::get('id');
|
||||
$translation = $this->repository->translationDetails($translationId) ?? [];
|
||||
$languages = $this->repository->languagesList();
|
||||
$validationErrors = $_SESSION['form_errors'][$this->getTranslationFormId()] ?? null;
|
||||
if ($validationErrors) {
|
||||
unset($_SESSION['form_errors'][$this->getTranslationFormId()]);
|
||||
}
|
||||
|
||||
return \Tpl::view('languages/translation-edit', [
|
||||
'form' => $this->buildTranslationFormViewModel($translation, $languages, $validationErrors),
|
||||
]);
|
||||
}
|
||||
|
||||
public function translation_save(): void
|
||||
{
|
||||
$legacyValues = \S::get('values');
|
||||
if ($legacyValues) {
|
||||
$values = json_decode((string)$legacyValues, true);
|
||||
$response = ['status' => 'error', 'msg' => 'Podczas zapisywania tlumaczenia wystapil blad.'];
|
||||
|
||||
if (is_array($values)) {
|
||||
$languagesMap = $this->extractLegacyTranslations($values, $this->repository->languagesList());
|
||||
$savedId = $this->repository->saveTranslation(
|
||||
(int)($values['id'] ?? 0),
|
||||
(string)($values['text'] ?? ''),
|
||||
$languagesMap
|
||||
);
|
||||
if ($savedId) {
|
||||
$this->clearLanguageSessions($this->repository->languagesList());
|
||||
$response = ['status' => 'ok', 'msg' => 'Tlumaczenie zostalo zapisane.', 'id' => $savedId];
|
||||
}
|
||||
}
|
||||
|
||||
echo json_encode($response);
|
||||
exit;
|
||||
}
|
||||
|
||||
$translationId = (int)\S::get('id');
|
||||
$translation = $this->repository->translationDetails($translationId) ?? [];
|
||||
$languages = $this->repository->languagesList();
|
||||
$viewModel = $this->buildTranslationFormViewModel($translation, $languages);
|
||||
|
||||
$result = $this->formHandler->handleSubmit($viewModel, $_POST);
|
||||
if (!$result['success']) {
|
||||
$_SESSION['form_errors'][$this->getTranslationFormId()] = $result['errors'];
|
||||
echo json_encode(['success' => false, 'errors' => $result['errors']]);
|
||||
exit;
|
||||
}
|
||||
|
||||
$data = $result['data'];
|
||||
$languagesMap = [];
|
||||
foreach ($languages as $language) {
|
||||
$langId = (string)($language['id'] ?? '');
|
||||
$key = 'lang_' . $langId;
|
||||
$languagesMap[$langId] = (string)($data[$key] ?? '');
|
||||
}
|
||||
|
||||
$savedId = $this->repository->saveTranslation(
|
||||
$translationId,
|
||||
(string)($data['text'] ?? ''),
|
||||
$languagesMap
|
||||
);
|
||||
|
||||
if ($savedId) {
|
||||
$this->clearLanguageSessions($languages);
|
||||
echo json_encode([
|
||||
'success' => true,
|
||||
'id' => $savedId,
|
||||
'message' => 'Tlumaczenie zostalo zapisane.',
|
||||
]);
|
||||
exit;
|
||||
}
|
||||
|
||||
echo json_encode([
|
||||
'success' => false,
|
||||
'errors' => ['general' => 'Podczas zapisywania tlumaczenia wystapil blad.'],
|
||||
]);
|
||||
exit;
|
||||
}
|
||||
|
||||
public function translation_delete(): void
|
||||
{
|
||||
if ($this->repository->deleteTranslation((int)\S::get('id'))) {
|
||||
\S::alert('Tlumaczenie zostalo usuniete.');
|
||||
}
|
||||
|
||||
header('Location: /admin/languages/translation_list/');
|
||||
exit;
|
||||
}
|
||||
|
||||
private function buildLanguageFormViewModel(array $language, int $maxOrder, ?array $errors = null): FormEditViewModel
|
||||
{
|
||||
$languageId = strtolower(trim((string)($language['id'] ?? '')));
|
||||
$isNew = $languageId === '';
|
||||
|
||||
$data = [
|
||||
'id' => $languageId,
|
||||
'name' => (string)($language['name'] ?? ''),
|
||||
'status' => (int)($language['status'] ?? 0),
|
||||
'start' => (int)($language['start'] ?? 0),
|
||||
'o' => (int)($language['o'] ?? ($maxOrder + 1)),
|
||||
];
|
||||
|
||||
$fields = [];
|
||||
if ($isNew) {
|
||||
$fields[] = FormField::text('id', [
|
||||
'label' => 'ID (2 znaki)',
|
||||
'required' => true,
|
||||
'attributes' => ['maxlength' => 2],
|
||||
]);
|
||||
}
|
||||
|
||||
$fields[] = FormField::text('name', [
|
||||
'label' => 'Jezyk',
|
||||
'required' => true,
|
||||
]);
|
||||
$fields[] = FormField::switch('status', [
|
||||
'label' => 'Aktywny',
|
||||
]);
|
||||
$fields[] = FormField::switch('start', [
|
||||
'label' => 'Domyslny',
|
||||
]);
|
||||
$fields[] = FormField::hidden('o', $data['o']);
|
||||
|
||||
$actionUrl = '/admin/languages/language_save/' . ($isNew ? '' : ('id=' . $languageId));
|
||||
$actions = [
|
||||
FormAction::save($actionUrl, '/admin/languages/view_list/'),
|
||||
FormAction::cancel('/admin/languages/view_list/'),
|
||||
];
|
||||
|
||||
return new FormEditViewModel(
|
||||
$this->getLanguageFormId(),
|
||||
$isNew ? 'Nowy jezyk' : 'Edycja jezyka',
|
||||
$data,
|
||||
$fields,
|
||||
[],
|
||||
$actions,
|
||||
'POST',
|
||||
$actionUrl,
|
||||
'/admin/languages/view_list/',
|
||||
true,
|
||||
$isNew ? [] : ['id' => $languageId],
|
||||
null,
|
||||
$errors
|
||||
);
|
||||
}
|
||||
|
||||
private function buildTranslationFormViewModel(array $translation, array $languages, ?array $errors = null): FormEditViewModel
|
||||
{
|
||||
$translationId = (int)($translation['id'] ?? 0);
|
||||
$isNew = $translationId <= 0;
|
||||
|
||||
$data = [
|
||||
'id' => $translationId,
|
||||
'text' => (string)($translation['text'] ?? ''),
|
||||
];
|
||||
|
||||
$fields = [
|
||||
FormField::text('text', [
|
||||
'label' => 'Tekst',
|
||||
'required' => true,
|
||||
]),
|
||||
];
|
||||
|
||||
foreach ($languages as $language) {
|
||||
$langId = (string)($language['id'] ?? '');
|
||||
$fieldName = 'lang_' . $langId;
|
||||
$data[$fieldName] = (string)($translation[$langId] ?? '');
|
||||
$fields[] = FormField::text($fieldName, [
|
||||
'label' => (string)($language['name'] ?? $langId),
|
||||
]);
|
||||
}
|
||||
|
||||
$actionUrl = '/admin/languages/translation_save/' . ($isNew ? '' : ('id=' . $translationId));
|
||||
$actions = [
|
||||
FormAction::save($actionUrl, '/admin/languages/translation_list/'),
|
||||
FormAction::cancel('/admin/languages/translation_list/'),
|
||||
];
|
||||
|
||||
return new FormEditViewModel(
|
||||
$this->getTranslationFormId(),
|
||||
$isNew ? 'Nowe tlumaczenie' : 'Edycja tlumaczenia',
|
||||
$data,
|
||||
$fields,
|
||||
[],
|
||||
$actions,
|
||||
'POST',
|
||||
$actionUrl,
|
||||
'/admin/languages/translation_list/',
|
||||
true,
|
||||
$isNew ? [] : ['id' => $translationId],
|
||||
null,
|
||||
$errors
|
||||
);
|
||||
}
|
||||
|
||||
private function extractLegacyTranslations(array $values, array $languages): array
|
||||
{
|
||||
$result = [];
|
||||
foreach ($languages as $language) {
|
||||
$langId = (string)($language['id'] ?? '');
|
||||
$result[$langId] = (string)($values[$langId] ?? '');
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
private function clearLanguageSessions(array $languages): void
|
||||
{
|
||||
foreach ($languages as $language) {
|
||||
if (!isset($language['id'])) {
|
||||
continue;
|
||||
}
|
||||
\S::delete_session('lang-' . (string)$language['id']);
|
||||
}
|
||||
}
|
||||
|
||||
private function getLanguageFormId(): string
|
||||
{
|
||||
return 'languages-language-edit';
|
||||
}
|
||||
|
||||
private function getTranslationFormId(): string
|
||||
{
|
||||
return 'languages-translation-edit';
|
||||
}
|
||||
}
|
||||
@@ -255,6 +255,13 @@ class Site
|
||||
new \Domain\User\UserRepository( $mdb )
|
||||
);
|
||||
},
|
||||
'Languages' => function() {
|
||||
global $mdb;
|
||||
|
||||
return new \admin\Controllers\LanguagesController(
|
||||
new \Domain\Languages\LanguagesRepository( $mdb )
|
||||
);
|
||||
},
|
||||
];
|
||||
|
||||
return self::$newControllers;
|
||||
|
||||
@@ -1,82 +0,0 @@
|
||||
<?
|
||||
namespace admin\controls;
|
||||
|
||||
class Languages
|
||||
{
|
||||
public static function language_delete()
|
||||
{
|
||||
if ( \admin\factory\Languages::language_delete( \S::get( 'id' ) ) )
|
||||
\S::alert( 'Język został usunięty.' );
|
||||
header( 'Location: /admin/languages/view_list/' );
|
||||
exit;
|
||||
}
|
||||
|
||||
public static function language_save()
|
||||
{
|
||||
$response = [ 'status' => 'error', 'msg' => 'Podczas zapisywania języka wystąpił błąd. Proszę spróbować ponownie.' ];
|
||||
$values = json_decode( \S::get( 'values' ), true );
|
||||
|
||||
if ( \admin\factory\Languages::language_save(
|
||||
$values['id'], $values['name'], $values['status'],
|
||||
$values['start'], $values['o'] ) )
|
||||
$response = [ 'status' => 'ok', 'msg' => 'Język został zapisany.', 'id' => $id ];
|
||||
|
||||
echo json_encode( $response );
|
||||
exit;
|
||||
}
|
||||
|
||||
public static function language_edit()
|
||||
{
|
||||
return \admin\view\Languages::language_edit(
|
||||
\admin\factory\Languages::language_details(
|
||||
\S::get( 'id' )
|
||||
), \admin\factory\Languages::max_order()
|
||||
);
|
||||
}
|
||||
|
||||
public static function view_list()
|
||||
{
|
||||
return \admin\view\Languages::languages_list();
|
||||
}
|
||||
|
||||
public static function translation_delete()
|
||||
{
|
||||
if ( \admin\factory\Languages::translation_delete( \S::get( 'id' ) ) )
|
||||
\S::alert( 'Tłumaczenie zostało usunięte.' );
|
||||
header( 'Location: /admin/languages/translation_list/' );
|
||||
exit;
|
||||
}
|
||||
|
||||
public static function translation_save()
|
||||
{
|
||||
$response = [ 'status' => 'error', 'msg' => 'Podczas zapisywania tłumaczenia wystąpił błąd. Proszę spróbować ponownie.' ];
|
||||
$values = json_decode( \S::get( 'values' ), true );
|
||||
|
||||
$languages_list = \admin\factory\Languages::languages_list();
|
||||
if ( is_array( $languages_list ) and !empty( $languages_list ) ) foreach ( $languages_list as $language )
|
||||
{
|
||||
\S::delete_session( 'lang-' . $language['id'] );
|
||||
$languages[ $language['id'] ] = $values[ $language['id'] ];
|
||||
}
|
||||
|
||||
if ( $id = \admin\factory\Languages::translation_save( $values['id'], $values['text'], $languages ) )
|
||||
$response = [ 'status' => 'ok', 'msg' => 'Tłumaczenie zostało zapisane.', 'id' => $id ];
|
||||
|
||||
echo json_encode( $response );
|
||||
exit;
|
||||
}
|
||||
|
||||
public static function translation_edit()
|
||||
{
|
||||
return \admin\view\Languages::translation_edit(
|
||||
\admin\factory\Languages::translation_details( \S::get( 'id' ) ),
|
||||
\admin\factory\Languages::languages_list()
|
||||
);
|
||||
}
|
||||
|
||||
public static function translation_list()
|
||||
{
|
||||
return \admin\view\Languages::translations_list();
|
||||
}
|
||||
}
|
||||
?>
|
||||
@@ -1,141 +1,53 @@
|
||||
<?
|
||||
|
||||
namespace admin\factory;
|
||||
|
||||
class Languages
|
||||
{
|
||||
public static function translation_delete( $translation_id )
|
||||
private static function repository(): \Domain\Languages\LanguagesRepository
|
||||
{
|
||||
global $mdb;
|
||||
return $mdb -> delete( 'pp_langs_translations', [ 'id' => $translation_id ] );
|
||||
return new \Domain\Languages\LanguagesRepository($mdb);
|
||||
}
|
||||
|
||||
public static function translation_save( $translation_id, $text, $languages )
|
||||
public static function translation_delete($translation_id)
|
||||
{
|
||||
global $mdb;
|
||||
|
||||
if ( $translation_id )
|
||||
{
|
||||
$mdb -> update( 'pp_langs_translations', [ 'text' => $text ], [ 'id' => $translation_id ] );
|
||||
if ( is_array( $languages ) and !empty( $languages ) ): foreach ( $languages as $key => $val ):
|
||||
$mdb -> update( 'pp_langs_translations', [ $key => $val ], [ 'id' => $translation_id ] );
|
||||
endforeach; endif;
|
||||
\S::htacces();
|
||||
\S::delete_dir( '../temp/' );
|
||||
return $translation_id;
|
||||
}
|
||||
else
|
||||
{
|
||||
$mdb -> insert( 'pp_langs_translations', [ 'text' => $text ] );
|
||||
if ( $translation_id = $mdb -> id() )
|
||||
{
|
||||
if ( is_array( $languages ) and !empty( $languages ) ): foreach ( $languages as $key => $val ):
|
||||
$mdb -> update( 'pp_langs_translations', [ $key => $val ], [ 'id' => $translation_id ] );
|
||||
endforeach; endif;
|
||||
}
|
||||
\S::htacces();
|
||||
\S::delete_dir( '../temp/' );
|
||||
return $translation_id;
|
||||
}
|
||||
return self::repository()->deleteTranslation((int)$translation_id);
|
||||
}
|
||||
|
||||
public static function translation_details( $translation_id )
|
||||
public static function translation_save($translation_id, $text, $languages)
|
||||
{
|
||||
global $mdb;
|
||||
return $mdb -> get( 'pp_langs_translations', '*', [ 'id' => $translation_id ] );
|
||||
return self::repository()->saveTranslation((int)$translation_id, (string)$text, is_array($languages) ? $languages : []);
|
||||
}
|
||||
|
||||
public static function language_delete( $language_id )
|
||||
public static function translation_details($translation_id)
|
||||
{
|
||||
global $mdb;
|
||||
return self::repository()->translationDetails((int)$translation_id);
|
||||
}
|
||||
|
||||
if ( $mdb -> count( 'pp_langs' ) > 1 )
|
||||
{
|
||||
if ( $mdb -> query( 'ALTER TABLE pp_langs_translations DROP ' . $language_id )
|
||||
and
|
||||
$mdb -> delete( 'pp_langs', [ 'id' => $language_id ] )
|
||||
)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
public static function language_delete($language_id)
|
||||
{
|
||||
return self::repository()->deleteLanguage((string)$language_id);
|
||||
}
|
||||
|
||||
public static function max_order()
|
||||
{
|
||||
global $mdb;
|
||||
return $mdb -> max( 'pp_langs', 'o' );
|
||||
return self::repository()->maxOrder();
|
||||
}
|
||||
|
||||
public static function language_save( $language_id, $name, $status, $start, $o )
|
||||
public static function language_save($language_id, $name, $status, $start, $o)
|
||||
{
|
||||
global $mdb;
|
||||
|
||||
if ( $start == 'on' )
|
||||
$mdb -> update( 'pp_langs', [
|
||||
'start' => 0
|
||||
], [
|
||||
'id[!]' => $language_id
|
||||
] );
|
||||
|
||||
if ( $mdb -> count( 'pp_langs', [ 'id' => $language_id ] ) )
|
||||
{
|
||||
$mdb -> update( 'pp_langs',
|
||||
[
|
||||
'status' => $status == 'on' ? 1 : 0,
|
||||
'start' => $start == 'on' ? 1 : 0,
|
||||
'name' => $name,
|
||||
'o' => $o
|
||||
], [
|
||||
'id' => $language_id
|
||||
] );
|
||||
|
||||
if ( !$mdb -> count( 'pp_langs', [ 'start' => 1 ] ) )
|
||||
{
|
||||
$id_tmp = $mdb -> get( 'pp_langs', 'id', [ 'ORDER' => [ 'o' => 'ASC' ] ] );
|
||||
$mdb -> update( 'pp_langs', [ 'start' => 1 ], [ 'id' => $id_tmp ] );
|
||||
}
|
||||
|
||||
\S::htacces();
|
||||
\S::delete_dir( '../temp/' );
|
||||
return $language_id;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( $mdb -> query( 'ALTER TABLE pp_langs_translations ADD ' . $language_id . ' TEXT NULL DEFAULT NULL' ) )
|
||||
{
|
||||
$mdb -> insert( 'pp_langs',
|
||||
[
|
||||
'id' => $language_id,
|
||||
'name' => $name,
|
||||
'status' => $status == 'on' ? 1 : 0,
|
||||
'start' => $start == 'on' ? 1 : 0,
|
||||
'o' => $o
|
||||
] );
|
||||
|
||||
\S::htacces();
|
||||
\S::delete_dir( '../temp/' );
|
||||
return $language_id;
|
||||
}
|
||||
}
|
||||
|
||||
return faslse;
|
||||
return self::repository()->saveLanguage((string)$language_id, (string)$name, $status, $start, (int)$o);
|
||||
}
|
||||
|
||||
public static function language_details( $language_id )
|
||||
public static function language_details($language_id)
|
||||
{
|
||||
global $mdb;
|
||||
return $mdb -> get( 'pp_langs', '*', [ 'id' => $language_id ] );
|
||||
return self::repository()->languageDetails((string)$language_id);
|
||||
}
|
||||
|
||||
public static function languages_list( $only_active = false )
|
||||
public static function languages_list($only_active = false)
|
||||
{
|
||||
global $mdb;
|
||||
|
||||
$where = [];
|
||||
if ( $only_active )
|
||||
$where['status'] = 1;
|
||||
|
||||
return $mdb -> select( 'pp_langs', '*', array_merge( [ 'ORDER' => [ 'o' => 'ASC' ] ], $where ) );
|
||||
return self::repository()->languagesList((bool)$only_active);
|
||||
}
|
||||
}
|
||||
?>
|
||||
?>
|
||||
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
<?
|
||||
namespace admin\view;
|
||||
|
||||
class Languages
|
||||
{
|
||||
public static function translation_edit( $translation, $languages )
|
||||
{
|
||||
$tpl = new \Tpl;
|
||||
$tpl -> languages = $languages;
|
||||
$tpl -> translation = $translation;
|
||||
return $tpl -> render( 'languages/translation-edit' );
|
||||
}
|
||||
|
||||
public static function language_edit( $language, $order )
|
||||
{
|
||||
$tpl = new \Tpl;
|
||||
$tpl -> language = $language;
|
||||
$tpl -> order = $order;
|
||||
return $tpl -> render( 'languages/language-edit' );
|
||||
}
|
||||
|
||||
public static function translations_list()
|
||||
{
|
||||
$tpl = new \Tpl;
|
||||
return $tpl -> render( 'languages/translations-list' );
|
||||
}
|
||||
|
||||
public static function languages_list()
|
||||
{
|
||||
$tpl = new \Tpl;
|
||||
return $tpl -> render( 'languages/languages-list' );
|
||||
}
|
||||
}
|
||||
?>
|
||||
116
tests/Unit/Domain/Languages/LanguagesRepositoryTest.php
Normal file
116
tests/Unit/Domain/Languages/LanguagesRepositoryTest.php
Normal file
@@ -0,0 +1,116 @@
|
||||
<?php
|
||||
namespace Tests\Unit\Domain\Languages;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Domain\Languages\LanguagesRepository;
|
||||
|
||||
class LanguagesRepositoryTest extends TestCase
|
||||
{
|
||||
public function testLanguageDetailsReturnsArrayOrNull(): void
|
||||
{
|
||||
$mockDb = $this->createMock(\medoo::class);
|
||||
$mockDb->expects($this->once())
|
||||
->method('get')
|
||||
->with('pp_langs', '*', ['id' => 'pl'])
|
||||
->willReturn(['id' => 'pl', 'name' => 'Polski']);
|
||||
|
||||
$repository = new LanguagesRepository($mockDb);
|
||||
$language = $repository->languageDetails('pl');
|
||||
|
||||
$this->assertIsArray($language);
|
||||
$this->assertSame('pl', $language['id']);
|
||||
}
|
||||
|
||||
public function testLanguagesListReturnsArray(): void
|
||||
{
|
||||
$mockDb = $this->createMock(\medoo::class);
|
||||
$mockDb->expects($this->once())
|
||||
->method('select')
|
||||
->with('pp_langs', '*', ['ORDER' => ['o' => 'ASC']])
|
||||
->willReturn([
|
||||
['id' => 'pl', 'name' => 'Polski', 'status' => 1],
|
||||
]);
|
||||
|
||||
$repository = new LanguagesRepository($mockDb);
|
||||
$list = $repository->languagesList(false);
|
||||
|
||||
$this->assertCount(1, $list);
|
||||
$this->assertSame('pl', $list[0]['id']);
|
||||
}
|
||||
|
||||
public function testSaveLanguageRejectsInvalidLanguageId(): void
|
||||
{
|
||||
$mockDb = $this->createMock(\medoo::class);
|
||||
$repository = new LanguagesRepository($mockDb);
|
||||
|
||||
$this->assertNull($repository->saveLanguage('pol', 'Polski', 1, 1, 1));
|
||||
$this->assertNull($repository->saveLanguage('p1', 'Polski', 1, 1, 1));
|
||||
}
|
||||
|
||||
public function testSaveTranslationInsertsNewTranslationAndReturnsId(): void
|
||||
{
|
||||
$mockDb = $this->createMock(\medoo::class);
|
||||
|
||||
$mockDb->expects($this->once())
|
||||
->method('insert')
|
||||
->with('pp_langs_translations', ['text' => 'Hello'])
|
||||
->willReturn($this->createMock(\PDOStatement::class));
|
||||
|
||||
$mockDb->expects($this->once())
|
||||
->method('id')
|
||||
->willReturn(15);
|
||||
|
||||
$mockDb->expects($this->exactly(2))
|
||||
->method('update')
|
||||
->withConsecutive(
|
||||
['pp_langs_translations', ['pl' => 'Czesc'], ['id' => 15]],
|
||||
['pp_langs_translations', ['en' => 'Hello'], ['id' => 15]]
|
||||
);
|
||||
|
||||
$repository = new LanguagesRepository($mockDb);
|
||||
$savedId = $repository->saveTranslation(0, 'Hello', ['pl' => 'Czesc', 'en' => 'Hello']);
|
||||
|
||||
$this->assertSame(15, $savedId);
|
||||
}
|
||||
|
||||
public function testDeleteTranslationReturnsBoolean(): void
|
||||
{
|
||||
$mockDb = $this->createMock(\medoo::class);
|
||||
$mockDb->expects($this->once())
|
||||
->method('delete')
|
||||
->with('pp_langs_translations', ['id' => 5])
|
||||
->willReturn($this->createMock(\PDOStatement::class));
|
||||
|
||||
$repository = new LanguagesRepository($mockDb);
|
||||
$this->assertTrue($repository->deleteTranslation(5));
|
||||
}
|
||||
|
||||
public function testListForAdminReturnsItemsAndTotal(): void
|
||||
{
|
||||
$mockDb = $this->createMock(\medoo::class);
|
||||
|
||||
$countStmt = $this->createMock(\PDOStatement::class);
|
||||
$countStmt->expects($this->once())
|
||||
->method('fetchAll')
|
||||
->willReturn([[1]]);
|
||||
|
||||
$dataStmt = $this->createMock(\PDOStatement::class);
|
||||
$dataStmt->expects($this->once())
|
||||
->method('fetchAll')
|
||||
->willReturn([
|
||||
['id' => 'pl', 'name' => 'Polski', 'status' => 1, 'start' => 1, 'o' => 1],
|
||||
]);
|
||||
|
||||
$mockDb->expects($this->exactly(2))
|
||||
->method('query')
|
||||
->willReturnOnConsecutiveCalls($countStmt, $dataStmt);
|
||||
|
||||
$repository = new LanguagesRepository($mockDb);
|
||||
$result = $repository->listForAdmin(['name' => '', 'status' => '', 'start' => ''], 'o', 'ASC', 1, 15);
|
||||
|
||||
$this->assertSame(1, $result['total']);
|
||||
$this->assertCount(1, $result['items']);
|
||||
$this->assertSame('pl', $result['items'][0]['id']);
|
||||
}
|
||||
}
|
||||
|
||||
63
tests/Unit/admin/Controllers/LanguagesControllerTest.php
Normal file
63
tests/Unit/admin/Controllers/LanguagesControllerTest.php
Normal file
@@ -0,0 +1,63 @@
|
||||
<?php
|
||||
namespace Tests\Unit\admin\Controllers;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use admin\Controllers\LanguagesController;
|
||||
use Domain\Languages\LanguagesRepository;
|
||||
|
||||
class LanguagesControllerTest extends TestCase
|
||||
{
|
||||
private $mockRepository;
|
||||
private $controller;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
$this->mockRepository = $this->createMock(LanguagesRepository::class);
|
||||
$this->controller = new LanguagesController($this->mockRepository);
|
||||
}
|
||||
|
||||
public function testConstructorAcceptsRepository(): void
|
||||
{
|
||||
$controller = new LanguagesController($this->mockRepository);
|
||||
$this->assertInstanceOf(LanguagesController::class, $controller);
|
||||
}
|
||||
|
||||
public function testHasMainActionMethods(): void
|
||||
{
|
||||
$this->assertTrue(method_exists($this->controller, 'list'));
|
||||
$this->assertTrue(method_exists($this->controller, 'view_list'));
|
||||
$this->assertTrue(method_exists($this->controller, 'language_edit'));
|
||||
$this->assertTrue(method_exists($this->controller, 'language_save'));
|
||||
$this->assertTrue(method_exists($this->controller, 'language_delete'));
|
||||
$this->assertTrue(method_exists($this->controller, 'translation_list'));
|
||||
$this->assertTrue(method_exists($this->controller, 'translation_edit'));
|
||||
$this->assertTrue(method_exists($this->controller, 'translation_save'));
|
||||
$this->assertTrue(method_exists($this->controller, 'translation_delete'));
|
||||
}
|
||||
|
||||
public function testActionMethodReturnTypes(): void
|
||||
{
|
||||
$reflection = new \ReflectionClass($this->controller);
|
||||
|
||||
$this->assertEquals('string', (string)$reflection->getMethod('list')->getReturnType());
|
||||
$this->assertEquals('string', (string)$reflection->getMethod('view_list')->getReturnType());
|
||||
$this->assertEquals('string', (string)$reflection->getMethod('language_edit')->getReturnType());
|
||||
$this->assertEquals('void', (string)$reflection->getMethod('language_save')->getReturnType());
|
||||
$this->assertEquals('void', (string)$reflection->getMethod('language_delete')->getReturnType());
|
||||
$this->assertEquals('string', (string)$reflection->getMethod('translation_list')->getReturnType());
|
||||
$this->assertEquals('string', (string)$reflection->getMethod('translation_edit')->getReturnType());
|
||||
$this->assertEquals('void', (string)$reflection->getMethod('translation_save')->getReturnType());
|
||||
$this->assertEquals('void', (string)$reflection->getMethod('translation_delete')->getReturnType());
|
||||
}
|
||||
|
||||
public function testConstructorRequiresLanguagesRepository(): void
|
||||
{
|
||||
$reflection = new \ReflectionClass(LanguagesController::class);
|
||||
$constructor = $reflection->getConstructor();
|
||||
$params = $constructor->getParameters();
|
||||
|
||||
$this->assertCount(1, $params);
|
||||
$this->assertEquals('Domain\Languages\LanguagesRepository', $params[0]->getType()->getName());
|
||||
}
|
||||
}
|
||||
|
||||
BIN
updates/0.20/ver_0.254.zip
Normal file
BIN
updates/0.20/ver_0.254.zip
Normal file
Binary file not shown.
2
updates/0.20/ver_0.254_files.txt
Normal file
2
updates/0.20/ver_0.254_files.txt
Normal file
@@ -0,0 +1,2 @@
|
||||
F: ../autoload/admin/controls/class.Languages.php
|
||||
F: ../autoload/admin/view/class.Languages.php
|
||||
@@ -1,3 +1,11 @@
|
||||
<b>ver. 0.254 - 12.02.2026</b><br />
|
||||
- UPDATE - modul `Languages` w panelu admin przepiety na `Domain\\Languages\\LanguagesRepository` + `admin\\Controllers\\LanguagesController`
|
||||
- UPDATE - migracja widokow languages (`languages-list`, `language-edit`, `translations-list`, `translation-edit`) na `components/table-list` i `components/form-edit`
|
||||
- UPDATE - routing DI dla `Languages` w `admin\\Site` oraz kompatybilna fasada `admin\\factory\\Languages` delegujaca do repozytorium
|
||||
- UPDATE - naprawiono zapis edycji jezyka (ID jezyka pobierane z URL przy edycji)
|
||||
- UPDATE - globalne poprawki UX filtrów w `components/table-list` (kompaktowe kolumny `Aktywny`/`Domyslny`, spacing i pelna szerokosc selecta)
|
||||
- CLEANUP - usuniete legacy klasy: `autoload/admin/controls/class.Languages.php`, `autoload/admin/view/class.Languages.php`
|
||||
<hr>
|
||||
<b>ver. 0.253 - 12.02.2026</b><br />
|
||||
- UPDATE - modul `Users` w panelu admin w pelni przepiety na `Domain\\User\\UserRepository` + `admin\\Controllers\\UsersController`
|
||||
- UPDATE - migracja widokow users z `grid/gridEdit` na nowe komponenty (`components/table-list`, `components/form-edit`)
|
||||
|
||||
Binary file not shown.
@@ -1,5 +1,5 @@
|
||||
<?
|
||||
$current_ver = 253;
|
||||
$current_ver = 254;
|
||||
|
||||
for ($i = 1; $i <= $current_ver; $i++)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user