diff --git a/DATABASE_STRUCTURE.md b/DATABASE_STRUCTURE.md
index 99353fe..323bfc7 100644
--- a/DATABASE_STRUCTURE.md
+++ b/DATABASE_STRUCTURE.md
@@ -209,3 +209,43 @@ Slownik tlumaczen panelu/frontendu.
**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`.
+
+## pp_layouts
+Szablony layoutow (HTML/CSS/JS + flagi domyslne).
+
+| Kolumna | Opis |
+|---------|------|
+| id | PK |
+| name | Nazwa szablonu |
+| html | Kod HTML |
+| css | Kod CSS |
+| js | Kod JS |
+| m_html | Kod HTML mobilny |
+| m_css | Kod CSS mobilny |
+| m_js | Kod JS mobilny |
+| status | Domyslny layout stron (0/1) |
+| categories_default | Domyslny layout kategorii (0/1) |
+
+**Uzywane w:** `Domain\\Layouts\\LayoutsRepository`, `admin\\Controllers\\LayoutsController`, `front\\factory\\Layouts`
+
+## pp_layouts_pages
+Przypisanie layoutow do stron CMS.
+
+| Kolumna | Opis |
+|---------|------|
+| layout_id | FK do pp_layouts |
+| page_id | FK do pp_pages |
+
+**Uzywane w:** `Domain\\Layouts\\LayoutsRepository`, `front\\factory\\Layouts`
+
+## pp_layouts_categories
+Przypisanie layoutow do kategorii sklepu.
+
+| Kolumna | Opis |
+|---------|------|
+| layout_id | FK do pp_layouts |
+| category_id | FK do pp_shop_categories |
+
+**Uzywane w:** `Domain\\Layouts\\LayoutsRepository`, `front\\factory\\Layouts`
+
+**Aktualizacja 2026-02-12 (ver. 0.256):** modul `/admin/layouts` korzysta z `Domain\\Layouts\\LayoutsRepository` (DI kontroler + fasada legacy).
diff --git a/PROJECT_STRUCTURE.md b/PROJECT_STRUCTURE.md
index 75d5034..8a54078 100644
--- a/PROJECT_STRUCTURE.md
+++ b/PROJECT_STRUCTURE.md
@@ -408,4 +408,14 @@ Aktualnie w suite są też testy modułów `Dictionaries`, `Articles` i `Users`
- UPDATE: w admin/Site fabryki DI dla Articles, Banners, Settings, Dictionaries przekazuja rowniez LanguagesRepository.
- UPDATE: legacy admin/controls/* oraz admin/factory/Shop* przepiete z admin/factory/Languages::languages_list() na bezposrednie wywolania LanguagesRepository.
- FIX: autoload/admin/factory/class.Languages.php uzywa pelnego znacznika
Menu: = $menu['name'];?>
- = \admin\view\Layouts::subpages_list( \admin\factory\Pages::menu_pages( $menu['id'] ), $this -> layout['pages'] );?>
+ = \Tpl::view( 'layouts/subpages-list', [
+ 'pages' => $menu['pages'],
+ 'layout_pages' => $this -> layout['pages'],
+ 'step' => 1
+ ] );?>
@@ -202,8 +206,8 @@ ob_start();
layout['categories'] ) and in_array( $category['id'], $this -> layout['categories'] ) ):?>checked="checked" endif;?> />
= $category['languages'][$this -> dlang]['title'];?>
- = \Tpl::view( 'shop-product/subcategories-list', [
- 'categories' => \admin\factory\ShopCategory::subcategories( $category['id'] ),
+ = \Tpl::view( 'layouts/subcategories-list', [
+ 'categories' => $category['subcategories'],
'product_categories' => $this -> layout['categories'],
'dlang' => $this -> dlang
] );?>
@@ -250,4 +254,4 @@ $grid -> persist_edit = true;
$grid -> id_param = 'id';
echo $grid -> draw();
-?>
\ No newline at end of file
+?>
diff --git a/admin/templates/layouts/layouts-list.php b/admin/templates/layouts/layouts-list.php
index 2e7a218..0f89c5b 100644
--- a/admin/templates/layouts/layouts-list.php
+++ b/admin/templates/layouts/layouts-list.php
@@ -1,54 +1 @@
- gdb_opt = $gdb;
-$grid -> order = [ 'column' => 'name', 'type' => 'ASC' ];
-$grid -> search = [
- [ 'name' => 'Nazwa', 'db' => 'name', 'type' => 'text' ],
- [ 'name' => 'Szablon domyślny', 'db' => 'status', 'type' => 'select', 'replace' => [ 'array' => [ 0 => 'nie', 1 => 'tak' ] ] ]
- ];
-$grid -> columns_view = [
- [
- 'name' => 'Lp.',
- 'th' => [ 'class' => 'g-lp' ],
- 'td' => [ 'class' => 'g-center' ],
- 'autoincrement' => true
- ],
- [
- 'name' => 'Nazwa',
- 'db' => 'name',
- 'php' => 'echo "[name]";',
- 'sort' => true
- ],
- [
- 'name' => 'Szablon domyślny',
- 'db' => 'status',
- 'replace' => [ 'array' => [ 0 => 'nie', 1 => 'tak' ] ],
- 'td' => [ 'class' => 'g-center' ],
- 'th' => [ 'class' => 'g-center', 'style' => 'width: 150px;' ]
- ],
- [
- 'name' => 'Szablon domyślny (kategorie)',
- 'db' => 'categories_default',
- 'replace' => [ 'array' => [ 0 => 'nie', 1 => 'tak' ] ],
- 'td' => [ 'class' => 'g-center' ],
- 'th' => [ 'class' => 'g-center', 'style' => 'width: 150px;' ]
- ],
- [
- 'name' => 'Akcja',
- 'action' => [ 'type' => 'edit', 'url' => '/admin/layouts/layout_edit/id=[id]' ],
- 'th' => [ 'class' => 'g-center' ],
- 'td' => [ 'class' => 'g-center', 'style' => 'width: 70px;' ]
- ],
- [
- 'name' => 'Akcja',
- 'action' => [ 'type' => 'delete', 'url' => '/admin/layouts/layout_delete/id=[id]' ],
- 'th' => [ 'class' => 'g-center' ],
- 'td' => [ 'class' => 'g-center', 'style' => 'width: 70px;' ]
- ]
- ];
-$grid -> buttons = [
- [ 'label' => 'Dodaj szablon', 'url' => '/admin/layouts/layout_edit/', 'icon' => 'fa-plus-circle', 'class' => 'btn-success' ]
- ];
-echo $grid -> draw();
\ No newline at end of file
+= \Tpl::view('components/table-list', ['list' => $this->viewModel]); ?>
diff --git a/admin/templates/layouts/subcategories-list.php b/admin/templates/layouts/subcategories-list.php
new file mode 100644
index 0000000..e1e5bf5
--- /dev/null
+++ b/admin/templates/layouts/subcategories-list.php
@@ -0,0 +1,20 @@
+ if ( is_array( $this -> categories ) ):?>
+
+ foreach ( $this -> categories as $category ):?>
+ -
+
+ = \Tpl::view( 'layouts/subcategories-list', [
+ 'categories' => $category['subcategories'],
+ 'product_categories' => $this -> product_categories,
+ 'dlang' => $this -> dlang
+ ] );?>
+
+ endforeach;?>
+
+ endif;?>
+
diff --git a/admin/templates/layouts/subpages-list.php b/admin/templates/layouts/subpages-list.php
index d46b0a9..3f68d21 100644
--- a/admin/templates/layouts/subpages-list.php
+++ b/admin/templates/layouts/subpages-list.php
@@ -8,9 +8,13 @@
if ( is_array( $page['subpages'] ) )
- echo \admin\view\Layouts::subpages_list( $page['subpages'], $this -> layout_pages, $page['id'], $this -> step + 1 );
+ echo \Tpl::view( 'layouts/subpages-list', [
+ 'pages' => $page['subpages'],
+ 'layout_pages' => $this -> layout_pages,
+ 'step' => $this -> step + 1
+ ] );
?>
endforeach;?>
- endif;?>
\ No newline at end of file
+ endif;?>
diff --git a/autoload/Domain/Languages/LanguagesRepository.php b/autoload/Domain/Languages/LanguagesRepository.php
index 7957acc..cce748d 100644
--- a/autoload/Domain/Languages/LanguagesRepository.php
+++ b/autoload/Domain/Languages/LanguagesRepository.php
@@ -187,6 +187,26 @@ class LanguagesRepository
return is_array($rows) ? $rows : [];
}
+ public function defaultLanguageId(): string
+ {
+ $languages = $this->languagesList();
+ if (empty($languages)) {
+ return 'pl';
+ }
+
+ foreach ($languages as $language) {
+ if ((int)($language['start'] ?? 0) === 1 && !empty($language['id'])) {
+ return (string)$language['id'];
+ }
+ }
+
+ if (!empty($languages[0]['id'])) {
+ return (string)$languages[0]['id'];
+ }
+
+ return 'pl';
+ }
+
public function deleteLanguage(string $languageId): bool
{
$languageId = $this->sanitizeLanguageId($languageId);
@@ -327,4 +347,3 @@ class LanguagesRepository
return ($value === 'on' || $value === 1 || $value === '1' || $value === true) ? 1 : 0;
}
}
-
diff --git a/autoload/Domain/Layouts/LayoutsRepository.php b/autoload/Domain/Layouts/LayoutsRepository.php
new file mode 100644
index 0000000..7cf6be6
--- /dev/null
+++ b/autoload/Domain/Layouts/LayoutsRepository.php
@@ -0,0 +1,343 @@
+db = $db;
+ }
+
+ public function delete(int $layoutId): bool
+ {
+ if ((int)$this->db->count('pp_layouts') <= 1) {
+ return false;
+ }
+
+ return (bool)$this->db->delete('pp_layouts', ['id' => $layoutId]);
+ }
+
+ public function find(int $layoutId): array
+ {
+ $layout = $this->db->get('pp_layouts', '*', ['id' => $layoutId]);
+ if (!is_array($layout)) {
+ return $this->defaultLayout();
+ }
+
+ $layout['pages'] = $this->db->select('pp_layouts_pages', 'page_id', ['layout_id' => $layoutId]);
+ $layout['categories'] = $this->db->select('pp_layouts_categories', 'category_id', ['layout_id' => $layoutId]);
+
+ return $layout;
+ }
+
+ public function save(array $data): ?int
+ {
+ $layoutId = (int)($data['id'] ?? 0);
+ $status = $this->toSwitchValue($data['status'] ?? 0);
+ $categoriesDefault = $this->toSwitchValue($data['categories_default'] ?? 0);
+
+ $row = [
+ 'name' => (string)($data['name'] ?? ''),
+ 'html' => (string)($data['html'] ?? ''),
+ 'css' => (string)($data['css'] ?? ''),
+ 'js' => (string)($data['js'] ?? ''),
+ 'm_html' => (string)($data['m_html'] ?? ''),
+ 'm_css' => (string)($data['m_css'] ?? ''),
+ 'm_js' => (string)($data['m_js'] ?? ''),
+ 'status' => $status,
+ 'categories_default' => $categoriesDefault,
+ ];
+
+ if ($status === 1) {
+ $this->db->update('pp_layouts', ['status' => 0]);
+ }
+
+ if ($categoriesDefault === 1) {
+ $this->db->update('pp_layouts', ['categories_default' => 0]);
+ }
+
+ if ($layoutId <= 0) {
+ $this->db->insert('pp_layouts', $row);
+ $layoutId = (int)$this->db->id();
+ if ($layoutId <= 0) {
+ return null;
+ }
+ } else {
+ $this->db->update('pp_layouts', $row, ['id' => $layoutId]);
+ }
+
+ $this->db->delete('pp_layouts_pages', ['layout_id' => $layoutId]);
+ $this->syncPages($layoutId, $data['pages'] ?? []);
+
+ $this->db->delete('pp_layouts_categories', ['layout_id' => $layoutId]);
+ $this->syncCategories($layoutId, $data['categories'] ?? []);
+
+ \S::delete_dir('../temp/');
+
+ return $layoutId;
+ }
+
+ public function listAll(): array
+ {
+ $rows = $this->db->select('pp_layouts', '*', ['ORDER' => ['name' => 'ASC']]);
+ return is_array($rows) ? $rows : [];
+ }
+
+ public function menusWithPages(): array
+ {
+ $menus = $this->db->select('pp_menus', '*', ['ORDER' => ['id' => 'ASC']]);
+ if (!is_array($menus)) {
+ return [];
+ }
+
+ foreach ($menus as $key => $menu) {
+ $menuId = (int)($menu['id'] ?? 0);
+ $menus[$key]['pages'] = $this->menuPages($menuId, null);
+ }
+
+ return $menus;
+ }
+
+ public function categoriesTree($parentId = null): array
+ {
+ $rows = $this->db->select('pp_shop_categories', ['id'], [
+ 'parent_id' => $parentId,
+ 'ORDER' => ['o' => 'ASC'],
+ ]);
+
+ if (!is_array($rows)) {
+ return [];
+ }
+
+ $categories = [];
+ foreach ($rows as $row) {
+ $categoryId = (int)($row['id'] ?? 0);
+ if ($categoryId <= 0) {
+ continue;
+ }
+
+ $category = $this->db->get('pp_shop_categories', '*', ['id' => $categoryId]);
+ if (!is_array($category)) {
+ continue;
+ }
+
+ $translations = $this->db->select('pp_shop_categories_langs', '*', ['category_id' => $categoryId]);
+ $category['languages'] = [];
+ if (is_array($translations)) {
+ foreach ($translations as $translation) {
+ $langId = (string)($translation['lang_id'] ?? '');
+ if ($langId !== '') {
+ $category['languages'][$langId] = $translation;
+ }
+ }
+ }
+
+ $category['subcategories'] = $this->categoriesTree($categoryId);
+ $categories[] = $category;
+ }
+
+ return $categories;
+ }
+
+ /**
+ * @return array{items: array>, total: int}
+ */
+ public function listForAdmin(
+ array $filters,
+ string $sortColumn = 'name',
+ string $sortDir = 'ASC',
+ int $page = 1,
+ int $perPage = 15
+ ): array {
+ $allowedSortColumns = [
+ 'id' => 'pl.id',
+ 'name' => 'pl.name',
+ 'status' => 'pl.status',
+ 'categories_default' => 'pl.categories_default',
+ ];
+
+ $sortSql = $allowedSortColumns[$sortColumn] ?? 'pl.name';
+ $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;
+ }
+
+ $categoriesDefault = trim((string)($filters['categories_default'] ?? ''));
+ if ($categoriesDefault === '0' || $categoriesDefault === '1') {
+ $where[] = 'pl.categories_default = :categories_default';
+ $params[':categories_default'] = (int)$categoriesDefault;
+ }
+
+ $whereSql = implode(' AND ', $where);
+
+ $sqlCount = "
+ SELECT COUNT(0)
+ FROM pp_layouts 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.categories_default
+ FROM pp_layouts AS pl
+ WHERE {$whereSql}
+ ORDER BY {$sortSql} {$sortDir}, 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,
+ ];
+ }
+
+ private function syncPages(int $layoutId, $pages): void
+ {
+ foreach ($this->normalizeIds($pages) as $pageId) {
+ $this->db->delete('pp_layouts_pages', ['page_id' => $pageId]);
+ $this->db->insert('pp_layouts_pages', [
+ 'layout_id' => $layoutId,
+ 'page_id' => $pageId,
+ ]);
+ }
+ }
+
+ private function syncCategories(int $layoutId, $categories): void
+ {
+ foreach ($this->normalizeIds($categories) as $categoryId) {
+ $this->db->delete('pp_layouts_categories', ['category_id' => $categoryId]);
+ $this->db->insert('pp_layouts_categories', [
+ 'layout_id' => $layoutId,
+ 'category_id' => $categoryId,
+ ]);
+ }
+ }
+
+ /**
+ * @return int[]
+ */
+ private function normalizeIds($values): array
+ {
+ if (!is_array($values)) {
+ $values = [$values];
+ }
+
+ $ids = [];
+ foreach ($values as $value) {
+ $id = (int)$value;
+ if ($id > 0) {
+ $ids[$id] = $id;
+ }
+ }
+
+ return array_values($ids);
+ }
+
+ private function toSwitchValue($value): int
+ {
+ return ($value === 'on' || $value === 1 || $value === '1' || $value === true) ? 1 : 0;
+ }
+
+ private function defaultLayout(): array
+ {
+ return [
+ 'id' => 0,
+ 'name' => '',
+ 'status' => 0,
+ 'categories_default' => 0,
+ 'html' => '',
+ 'css' => '',
+ 'js' => '',
+ 'm_html' => '',
+ 'm_css' => '',
+ 'm_js' => '',
+ 'pages' => [],
+ 'categories' => [],
+ ];
+ }
+
+ private function menuPages(int $menuId, $parentId = null): array
+ {
+ if ($menuId <= 0) {
+ return [];
+ }
+
+ $rows = $this->db->select('pp_pages', ['id', 'menu_id', 'status', 'parent_id', 'start'], [
+ 'AND' => [
+ 'menu_id' => $menuId,
+ 'parent_id' => $parentId,
+ ],
+ 'ORDER' => ['o' => 'ASC'],
+ ]);
+
+ if (!is_array($rows)) {
+ return [];
+ }
+
+ $pages = [];
+ foreach ($rows as $row) {
+ $pageId = (int)($row['id'] ?? 0);
+ if ($pageId <= 0) {
+ continue;
+ }
+
+ $row['title'] = $this->pageTitle($pageId);
+ $row['subpages'] = $this->menuPages($menuId, $pageId);
+ $pages[] = $row;
+ }
+
+ return $pages;
+ }
+
+ private function pageTitle(int $pageId): string
+ {
+ $result = $this->db->select('pp_pages_langs', [
+ '[><]pp_langs' => ['lang_id' => 'id'],
+ ], 'title', [
+ 'AND' => [
+ 'page_id' => $pageId,
+ 'title[!]' => '',
+ ],
+ 'ORDER' => ['o' => 'ASC'],
+ 'LIMIT' => 1,
+ ]);
+
+ if (is_array($result) && isset($result[0])) {
+ return (string)$result[0];
+ }
+
+ return '';
+ }
+}
diff --git a/autoload/admin/Controllers/ArticlesController.php b/autoload/admin/Controllers/ArticlesController.php
index 807880e..9766a01 100644
--- a/autoload/admin/Controllers/ArticlesController.php
+++ b/autoload/admin/Controllers/ArticlesController.php
@@ -3,16 +3,23 @@ namespace admin\Controllers;
use Domain\Article\ArticleRepository;
use Domain\Languages\LanguagesRepository;
+use Domain\Layouts\LayoutsRepository;
class ArticlesController
{
private ArticleRepository $repository;
private LanguagesRepository $languagesRepository;
+ private LayoutsRepository $layoutsRepository;
- public function __construct(ArticleRepository $repository, LanguagesRepository $languagesRepository)
+ public function __construct(
+ ArticleRepository $repository,
+ LanguagesRepository $languagesRepository,
+ LayoutsRepository $layoutsRepository
+ )
{
$this->repository = $repository;
$this->languagesRepository = $languagesRepository;
+ $this->layoutsRepository = $layoutsRepository;
}
/**
@@ -189,7 +196,7 @@ class ArticlesController
'article' => $this->repository->find((int)\S::get('id')),
'menus' => \admin\factory\Pages::menus_list(),
'languages' => $this->languagesRepository->languagesList(),
- 'layouts' => \admin\factory\Layouts::layouts_list(),
+ 'layouts' => $this->layoutsRepository->listAll(),
'user' => $user
]);
}
diff --git a/autoload/admin/Controllers/LayoutsController.php b/autoload/admin/Controllers/LayoutsController.php
new file mode 100644
index 0000000..f02c6ac
--- /dev/null
+++ b/autoload/admin/Controllers/LayoutsController.php
@@ -0,0 +1,172 @@
+repository = $repository;
+ $this->languagesRepository = $languagesRepository;
+ }
+
+ public function list(): string
+ {
+ $sortableColumns = ['name', 'status', 'categories_default'];
+
+ $filterDefinitions = [
+ [
+ 'key' => 'name',
+ 'label' => 'Nazwa',
+ 'type' => 'text',
+ ],
+ [
+ 'key' => 'status',
+ 'label' => 'Szablon domyslny',
+ 'type' => 'select',
+ 'options' => [
+ '' => '- domyslny -',
+ '1' => 'tak',
+ '0' => 'nie',
+ ],
+ ],
+ [
+ 'key' => 'categories_default',
+ 'label' => 'Domyslny (kategorie)',
+ 'type' => 'select',
+ 'options' => [
+ '' => '- kategorie -',
+ '1' => 'tak',
+ '0' => 'nie',
+ ],
+ ],
+ ];
+
+ $listRequest = \admin\Support\TableListRequestFactory::fromRequest(
+ $filterDefinitions,
+ $sortableColumns,
+ 'name'
+ );
+
+ $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 = (int)($item['id'] ?? 0);
+ $name = trim((string)($item['name'] ?? ''));
+
+ $rows[] = [
+ 'lp' => $lp++ . '.',
+ 'name' => '' . htmlspecialchars($name, ENT_QUOTES, 'UTF-8') . '',
+ 'status' => ((int)($item['status'] ?? 0) === 1) ? 'tak' : 'nie',
+ 'categories_default' => ((int)($item['categories_default'] ?? 0) === 1) ? 'tak' : 'nie',
+ '_actions' => [
+ [
+ 'label' => 'Edytuj',
+ 'url' => '/admin/layouts/layout_edit/id=' . $id,
+ 'class' => 'btn btn-xs btn-primary',
+ ],
+ [
+ 'label' => 'Usun',
+ 'url' => '/admin/layouts/layout_delete/id=' . $id,
+ 'class' => 'btn btn-xs btn-danger',
+ 'confirm' => 'Na pewno chcesz usunac wybrany szablon?',
+ ],
+ ],
+ ];
+ }
+
+ $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' => 'name', 'sort_key' => 'name', 'label' => 'Nazwa', 'sortable' => true, 'raw' => true],
+ ['key' => 'status', 'sort_key' => 'status', 'label' => 'Szablon domyslny', 'class' => 'text-center', 'sortable' => true, 'raw' => true],
+ ['key' => 'categories_default', 'sort_key' => 'categories_default', 'label' => 'Domyslny (kategorie)', 'class' => 'text-center', '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/layouts/view_list/',
+ 'Brak danych w tabeli.',
+ '/admin/layouts/layout_edit/',
+ 'Dodaj szablon'
+ );
+
+ return \Tpl::view('layouts/layouts-list', [
+ 'viewModel' => $viewModel,
+ ]);
+ }
+
+ public function edit(): string
+ {
+ return \Tpl::view('layouts/layout-edit', [
+ 'layout' => $this->repository->find((int)\S::get('id')),
+ 'menus' => $this->repository->menusWithPages(),
+ 'categories' => $this->repository->categoriesTree(),
+ 'dlang' => $this->languagesRepository->defaultLanguageId(),
+ ]);
+ }
+
+ public function save(): void
+ {
+ $response = ['status' => 'error', 'msg' => 'Podczas zapisywania szablonu wystapil blad. Prosze sprobowac ponownie.'];
+ $values = json_decode((string)\S::get('values'), true);
+
+ if (is_array($values)) {
+ $id = $this->repository->save($values);
+ if (!empty($id)) {
+ $response = ['status' => 'ok', 'msg' => 'Szablon zostal zapisany.', 'id' => $id];
+ }
+ }
+
+ echo json_encode($response);
+ exit;
+ }
+
+ public function delete(): void
+ {
+ if ($this->repository->delete((int)\S::get('id'))) {
+ \S::alert('Szablon zostal usuniety.');
+ }
+
+ header('Location: /admin/layouts/view_list/');
+ exit;
+ }
+
+}
diff --git a/autoload/admin/class.Site.php b/autoload/admin/class.Site.php
index 5e14bd6..12f12e8 100644
--- a/autoload/admin/class.Site.php
+++ b/autoload/admin/class.Site.php
@@ -207,7 +207,8 @@ class Site
return new \admin\Controllers\ArticlesController(
new \Domain\Article\ArticleRepository( $mdb ),
- new \Domain\Languages\LanguagesRepository( $mdb )
+ new \Domain\Languages\LanguagesRepository( $mdb ),
+ new \Domain\Layouts\LayoutsRepository( $mdb )
);
},
'Banners' => function() {
@@ -266,6 +267,14 @@ class Site
new \Domain\Languages\LanguagesRepository( $mdb )
);
},
+ 'Layouts' => function() {
+ global $mdb;
+
+ return new \admin\Controllers\LayoutsController(
+ new \Domain\Layouts\LayoutsRepository( $mdb ),
+ new \Domain\Languages\LanguagesRepository( $mdb )
+ );
+ },
];
return self::$newControllers;
@@ -309,6 +318,9 @@ class Site
'unit_edit' => 'edit',
'unit_save' => 'save',
'unit_delete' => 'delete',
+ 'layout_edit' => 'edit',
+ 'layout_save' => 'save',
+ 'layout_delete' => 'delete',
];
public static function route()
diff --git a/autoload/admin/controls/class.Layouts.php b/autoload/admin/controls/class.Layouts.php
deleted file mode 100644
index 9325906..0000000
--- a/autoload/admin/controls/class.Layouts.php
+++ /dev/null
@@ -1,43 +0,0 @@
- 'error', 'msg' => 'Podczas zapisywania szablonu wystąpił błąd. Proszę spróbować ponownie.' ];
- $values = json_decode( \S::get( 'values' ), true );
-
- if ( $id = \admin\factory\Layouts::layout_save( $values['id'], $values['name'], $values['status'], $values['pages'], $values['html'], $values['css'], $values['js'], $values['m_html'],
- $values['m_css'], $values['m_js'], $values['categories'], $values['categories_default'] )
- )
- $response = [ 'status' => 'ok', 'msg' => 'Szablon został zapisany.', 'id' => $id ];
-
- echo json_encode( $response );
- exit;
- }
-
- public static function layout_edit()
- {
- return \Tpl::view( 'layouts/layout-edit', [
- 'layout' => \admin\factory\Layouts::layout_details( \S::get( 'id' ) ),
- 'menus' => \admin\factory\Layouts::menus_list(),
- 'categories' => \admin\factory\ShopCategory::subcategories( null ),
- 'dlang' => \front\factory\Languages::default_language()
- ] );
- }
-
- public static function view_list()
- {
- return \admin\view\Layouts::layouts_list();
- }
-}
-?>
\ No newline at end of file
diff --git a/autoload/admin/factory/class.Layouts.php b/autoload/admin/factory/class.Layouts.php
index 367932d..4031bb3 100644
--- a/autoload/admin/factory/class.Layouts.php
+++ b/autoload/admin/factory/class.Layouts.php
@@ -1,190 +1,78 @@
count( 'pp_layouts' ) > 1 )
- return $mdb -> delete( 'pp_layouts', [ 'id' => (int)$layout_id ] );
- return false;
- }
-
- public static function layout_details( $layout_id )
- {
- global $mdb;
-
- $layout = $mdb -> get( 'pp_layouts', '*', [ 'id' => (int)$layout_id ] );
-
- $layout['pages'] = $mdb -> select( 'pp_layouts_pages', 'page_id', [ 'layout_id' => (int)$layout_id ] );
- $layout['categories'] = $mdb -> select( 'pp_layouts_categories', 'category_id', [ 'layout_id' => (int)$layout_id ] );
-
- return $layout;
- }
-
- public static function layout_save( $layout_id, $name, $status, $pages, $html, $css, $js, $m_html, $m_css, $m_js, $categories, $categories_default )
- {
- global $mdb;
-
- if ( !$layout_id )
+ public static function layout_delete($layout_id)
{
- if ( $status == 'on' )
- $mdb -> update( 'pp_layouts', [ 'status' => 0 ] );
-
- if ( $categories_default == 'on' )
- $mdb -> update( 'pp_layouts', [ 'categories_default' => 0 ] );
-
- $mdb -> insert( 'pp_layouts', [
- 'name' => $name,
- 'html' => $html,
- 'css' => $css,
- 'js' => $js,
- 'm_html' => $m_html,
- 'm_css' => $m_css,
- 'm_js' => $m_js,
- 'status' => $status == 'on' ? 1 : 0,
- 'categories_default' => $categories_default == 'on' ? 1 : 0
- ] );
-
- $id = $mdb -> id();
-
- if ( $id )
- {
- if ( is_array( $pages ) ) foreach ( $pages as $page )
- {
- $mdb -> delete( 'pp_layouts_pages', [ 'page_id' => (int)$page ] );
-
- $mdb -> insert( 'pp_layouts_pages', [
- 'layout_id' => (int)$id,
- 'page_id' => (int)$page
- ] );
- }
- else if ( $pages )
- {
- $mdb -> delete( 'pp_layouts_pages', [ 'page_id' => (int)$pages ] );
-
- $mdb -> insert( 'pp_layouts_pages', [
- 'layout_id' => (int)$id,
- 'page_id' => (int)$pages
- ] );
- }
-
- if ( is_array( $categories ) ) foreach ( $categories as $category )
- {
- $mdb -> delete( 'pp_layouts_categories', [ 'category_id' => (int)$category ] );
-
- $mdb -> insert( 'pp_layouts_categories', [
- 'layout_id' => (int)$id,
- 'category_id' => (int)$category
- ] );
- }
- else if ( $categories )
- {
- $mdb -> delete( 'pp_layouts_categories', [ 'category_id' => (int)$categories ] );
-
- $mdb -> insert( 'pp_layouts_categories', [
- 'layout_id' => (int)$id,
- 'category_id' => (int)$categories
- ] );
- }
-
- \S::delete_dir( '../temp/' );
-
- return $id;
- }
+ return self::repository()->delete((int)$layout_id);
}
- else
+
+ public static function layout_details($layout_id)
{
- if ( $status == 'on' )
- $mdb -> update( 'pp_layouts', [ 'status' => 0 ] );
-
- if ( $categories_default == 'on' )
- $mdb -> update( 'pp_layouts', [ 'categories_default' => 0 ] );
-
- $mdb -> update( 'pp_layouts', [
- 'name' => $name,
- 'html' => $html,
- 'css' => $css,
- 'js' => $js,
- 'm_html' => $m_html,
- 'm_css' => $m_css,
- 'm_js' => $m_js,
- 'status' => $status == 'on' ? 1 : 0,
- 'categories_default' => $categories_default == 'on' ? 1 : 0
- ], [
- 'id' => $layout_id
- ] );
-
- $mdb -> delete( 'pp_layouts_pages', [ 'layout_id' => (int)$layout_id ] );
-
- if ( is_array( $pages ) ) foreach ( $pages as $page )
- {
- $mdb -> delete( 'pp_layouts_pages', [ 'page_id' => (int)$page ] );
-
- $mdb -> insert( 'pp_layouts_pages', [
- 'layout_id' => (int)$layout_id,
- 'page_id' => (int)$page
- ] );
- }
- else if ( $pages )
- {
- $mdb -> delete( 'pp_layouts_pages', [ 'page_id' => (int)$pages ] );
-
- $mdb -> insert( 'pp_layouts_pages', [
- 'layout_id' => (int)$layout_id,
- 'page_id' => (int)$pages
- ] );
- }
-
- $mdb -> delete( 'pp_layouts_categories', [ 'layout_id' => (int)$layout_id ] );
-
- if ( is_array( $categories ) ) foreach ( $categories as $category )
- {
- $mdb -> delete( 'pp_layouts_categories', [ 'category_id' => (int)$category ] );
-
- $mdb -> insert( 'pp_layouts_categories', [
- 'layout_id' => (int)$layout_id,
- 'category_id' => (int)$category
- ] );
- }
- else if ( $categories )
- {
- $mdb -> delete( 'pp_layouts_categories', [ 'category_id' => (int)$categories ] );
-
- $mdb -> insert( 'pp_layouts_categories', [
- 'layout_id' => (int)$layout_id,
- 'category_id' => (int)$categories
- ] );
- }
-
- \S::delete_dir( '../temp/' );
-
- return $layout_id;
+ return self::repository()->find((int)$layout_id);
}
- return false;
- }
-
- public static function menus_list()
- {
- global $mdb;
-
- $results = $mdb -> select( 'pp_menus', 'id', [ 'ORDER' => [ 'id' => 'ASC' ] ] );
- if ( is_array( $results ) ) foreach ( $results as $row )
+
+ public static function layout_save(
+ $layout_id,
+ $name,
+ $status,
+ $pages,
+ $html,
+ $css,
+ $js,
+ $m_html,
+ $m_css,
+ $m_js,
+ $categories,
+ $categories_default
+ ) {
+ return self::repository()->save([
+ 'id' => $layout_id,
+ 'name' => $name,
+ 'status' => $status,
+ 'pages' => $pages,
+ 'html' => $html,
+ 'css' => $css,
+ 'js' => $js,
+ 'm_html' => $m_html,
+ 'm_css' => $m_css,
+ 'm_js' => $m_js,
+ 'categories' => $categories,
+ 'categories_default' => $categories_default,
+ ]);
+ }
+
+ public static function menus_list()
{
- $menu = \admin\factory\Pages::menu_details( $row );
- $menu['pages'] = \admin\factory\Pages::menu_pages( $row );
-
- $menus[] = $menu;
+ $menus = \admin\factory\Pages::menus_list();
+ if (!is_array($menus)) {
+ return [];
+ }
+
+ foreach ($menus as $key => $menu) {
+ $menuId = (int)($menu['id'] ?? 0);
+ if ($menuId <= 0) {
+ continue;
+ }
+
+ $menus[$key]['pages'] = \admin\factory\Pages::menu_pages($menuId);
+ }
+
+ return $menus;
+ }
+
+ public static function layouts_list()
+ {
+ return self::repository()->listAll();
+ }
+
+ private static function repository(): LayoutsRepository
+ {
+ global $mdb;
+ return new LayoutsRepository($mdb);
}
- return $menus;
- }
-
- public static function layouts_list()
- {
- global $mdb;
- return $mdb -> select( 'pp_layouts', '*', [ 'ORDER' => [ 'name' => 'ASC' ] ] );
- }
}
-?>
\ No newline at end of file
+
diff --git a/autoload/admin/view/class.Layouts.php b/autoload/admin/view/class.Layouts.php
deleted file mode 100644
index fd4ea67..0000000
--- a/autoload/admin/view/class.Layouts.php
+++ /dev/null
@@ -1,21 +0,0 @@
- pages = $pages;
- $tpl -> step = $step;
- $tpl -> layout_pages = $layout_pages;
- return $tpl -> render( 'layouts/subpages-list' );
- }
-
- public static function layouts_list()
- {
- $tpl = new \Tpl;
- return $tpl -> render( 'layouts/layouts-list' );
- }
-}
-?>
\ No newline at end of file
diff --git a/tests/Unit/Domain/Languages/LanguagesRepositoryTest.php b/tests/Unit/Domain/Languages/LanguagesRepositoryTest.php
index 36fa2bf..97375f2 100644
--- a/tests/Unit/Domain/Languages/LanguagesRepositoryTest.php
+++ b/tests/Unit/Domain/Languages/LanguagesRepositoryTest.php
@@ -112,5 +112,37 @@ class LanguagesRepositoryTest extends TestCase
$this->assertCount(1, $result['items']);
$this->assertSame('pl', $result['items'][0]['id']);
}
-}
+ public function testDefaultLanguageIdReturnsLanguageWithStartFlag(): void
+ {
+ $mockDb = $this->createMock(\medoo::class);
+ $mockDb->expects($this->once())
+ ->method('select')
+ ->with('pp_langs', '*', ['ORDER' => ['o' => 'ASC']])
+ ->willReturn([
+ ['id' => 'en', 'start' => 0],
+ ['id' => 'pl', 'start' => 1],
+ ]);
+
+ $repository = new LanguagesRepository($mockDb);
+ $this->assertSame('pl', $repository->defaultLanguageId());
+ }
+
+ public function testDefaultLanguageIdFallsBackToFirstLanguageOrPl(): void
+ {
+ $mockDb = $this->createMock(\medoo::class);
+ $mockDb->expects($this->exactly(2))
+ ->method('select')
+ ->with('pp_langs', '*', ['ORDER' => ['o' => 'ASC']])
+ ->willReturnOnConsecutiveCalls(
+ [
+ ['id' => 'en', 'start' => 0],
+ ],
+ []
+ );
+
+ $repository = new LanguagesRepository($mockDb);
+ $this->assertSame('en', $repository->defaultLanguageId());
+ $this->assertSame('pl', $repository->defaultLanguageId());
+ }
+}
diff --git a/tests/Unit/Domain/Layouts/LayoutsRepositoryTest.php b/tests/Unit/Domain/Layouts/LayoutsRepositoryTest.php
new file mode 100644
index 0000000..fdcb4a8
--- /dev/null
+++ b/tests/Unit/Domain/Layouts/LayoutsRepositoryTest.php
@@ -0,0 +1,110 @@
+createMock(\medoo::class);
+
+ $mockDb->expects($this->once())
+ ->method('get')
+ ->with('pp_layouts', '*', ['id' => 5])
+ ->willReturn(['id' => 5, 'name' => 'Main']);
+
+ $mockDb->expects($this->exactly(2))
+ ->method('select')
+ ->withConsecutive(
+ ['pp_layouts_pages', 'page_id', ['layout_id' => 5]],
+ ['pp_layouts_categories', 'category_id', ['layout_id' => 5]]
+ )
+ ->willReturnOnConsecutiveCalls([10, 11], [2, 3]);
+
+ $repository = new LayoutsRepository($mockDb);
+ $layout = $repository->find(5);
+
+ $this->assertSame(5, $layout['id']);
+ $this->assertSame([10, 11], $layout['pages']);
+ $this->assertSame([2, 3], $layout['categories']);
+ }
+
+ public function testDeleteReturnsFalseWhenOnlyOneLayoutExists(): void
+ {
+ $mockDb = $this->createMock(\medoo::class);
+
+ $mockDb->expects($this->once())
+ ->method('count')
+ ->with('pp_layouts')
+ ->willReturn(1);
+
+ $repository = new LayoutsRepository($mockDb);
+ $this->assertFalse($repository->delete(1));
+ }
+
+ public function testFindReturnsDefaultLayoutWhenRecordDoesNotExist(): void
+ {
+ $mockDb = $this->createMock(\medoo::class);
+ $mockDb->expects($this->once())
+ ->method('get')
+ ->with('pp_layouts', '*', ['id' => 999])
+ ->willReturn(false);
+
+ $repository = new LayoutsRepository($mockDb);
+ $layout = $repository->find(999);
+
+ $this->assertSame(0, $layout['id']);
+ $this->assertSame([], $layout['pages']);
+ $this->assertSame([], $layout['categories']);
+ }
+
+ public function testSaveInsertsNewLayoutAndReturnsId(): void
+ {
+ $mockDb = $this->createMock(\medoo::class);
+
+ $mockDb->expects($this->once())
+ ->method('insert')
+ ->with('pp_layouts', $this->arrayHasKey('name'));
+
+ $mockDb->expects($this->once())
+ ->method('id')
+ ->willReturn(9);
+
+ $mockDb->expects($this->exactly(2))
+ ->method('delete')
+ ->withConsecutive(
+ ['pp_layouts_pages', ['layout_id' => 9]],
+ ['pp_layouts_categories', ['layout_id' => 9]]
+ )
+ ->willReturn(true);
+
+ $repository = new LayoutsRepository($mockDb);
+ $savedId = $repository->save([
+ 'name' => 'Nowy szablon',
+ 'status' => 0,
+ 'categories_default' => 0,
+ ]);
+
+ $this->assertSame(9, $savedId);
+ }
+
+ public function testListAllReturnsArray(): void
+ {
+ $mockDb = $this->createMock(\medoo::class);
+
+ $mockDb->expects($this->once())
+ ->method('select')
+ ->with('pp_layouts', '*', ['ORDER' => ['name' => 'ASC']])
+ ->willReturn([
+ ['id' => 1, 'name' => 'Default'],
+ ]);
+
+ $repository = new LayoutsRepository($mockDb);
+ $rows = $repository->listAll();
+
+ $this->assertCount(1, $rows);
+ $this->assertSame('Default', $rows[0]['name']);
+ }
+}
diff --git a/tests/Unit/admin/Controllers/ArticlesControllerTest.php b/tests/Unit/admin/Controllers/ArticlesControllerTest.php
index 6b1ad26..15b92e2 100644
--- a/tests/Unit/admin/Controllers/ArticlesControllerTest.php
+++ b/tests/Unit/admin/Controllers/ArticlesControllerTest.php
@@ -5,18 +5,25 @@ use PHPUnit\Framework\TestCase;
use admin\Controllers\ArticlesController;
use Domain\Article\ArticleRepository;
use Domain\Languages\LanguagesRepository;
+use Domain\Layouts\LayoutsRepository;
class ArticlesControllerTest extends TestCase
{
private $mockRepository;
private $mockLanguagesRepository;
+ private $mockLayoutsRepository;
private $controller;
protected function setUp(): void
{
$this->mockRepository = $this->createMock(ArticleRepository::class);
$this->mockLanguagesRepository = $this->createMock(LanguagesRepository::class);
- $this->controller = new ArticlesController($this->mockRepository, $this->mockLanguagesRepository);
+ $this->mockLayoutsRepository = $this->createMock(LayoutsRepository::class);
+ $this->controller = new ArticlesController(
+ $this->mockRepository,
+ $this->mockLanguagesRepository,
+ $this->mockLayoutsRepository
+ );
}
public function testCanCreateController(): void
@@ -26,7 +33,11 @@ class ArticlesControllerTest extends TestCase
public function testConstructorAcceptsRepository(): void
{
- $controller = new ArticlesController($this->mockRepository, $this->mockLanguagesRepository);
+ $controller = new ArticlesController(
+ $this->mockRepository,
+ $this->mockLanguagesRepository,
+ $this->mockLayoutsRepository
+ );
$this->assertInstanceOf(ArticlesController::class, $controller);
}
@@ -69,8 +80,9 @@ class ArticlesControllerTest extends TestCase
$constructor = $reflection->getConstructor();
$params = $constructor->getParameters();
- $this->assertCount(2, $params);
+ $this->assertCount(3, $params);
$this->assertEquals('Domain\Article\ArticleRepository', $params[0]->getType()->getName());
$this->assertEquals('Domain\Languages\LanguagesRepository', $params[1]->getType()->getName());
+ $this->assertEquals('Domain\Layouts\LayoutsRepository', $params[2]->getType()->getName());
}
}
diff --git a/tests/Unit/admin/Controllers/LayoutsControllerTest.php b/tests/Unit/admin/Controllers/LayoutsControllerTest.php
new file mode 100644
index 0000000..e9d47ed
--- /dev/null
+++ b/tests/Unit/admin/Controllers/LayoutsControllerTest.php
@@ -0,0 +1,56 @@
+mockRepository = $this->createMock(LayoutsRepository::class);
+ $this->mockLanguagesRepository = $this->createMock(LanguagesRepository::class);
+ $this->controller = new LayoutsController($this->mockRepository, $this->mockLanguagesRepository);
+ }
+
+ public function testConstructorAcceptsRepository(): void
+ {
+ $controller = new LayoutsController($this->mockRepository, $this->mockLanguagesRepository);
+ $this->assertInstanceOf(LayoutsController::class, $controller);
+ }
+
+ public function testHasMainActionMethods(): void
+ {
+ $this->assertTrue(method_exists($this->controller, 'list'));
+ $this->assertTrue(method_exists($this->controller, 'edit'));
+ $this->assertTrue(method_exists($this->controller, 'save'));
+ $this->assertTrue(method_exists($this->controller, 'delete'));
+ }
+
+ public function testActionMethodReturnTypes(): void
+ {
+ $reflection = new \ReflectionClass($this->controller);
+
+ $this->assertEquals('string', (string)$reflection->getMethod('list')->getReturnType());
+ $this->assertEquals('string', (string)$reflection->getMethod('edit')->getReturnType());
+ $this->assertEquals('void', (string)$reflection->getMethod('save')->getReturnType());
+ $this->assertEquals('void', (string)$reflection->getMethod('delete')->getReturnType());
+ }
+
+ public function testConstructorRequiresLayoutsRepository(): void
+ {
+ $reflection = new \ReflectionClass(LayoutsController::class);
+ $constructor = $reflection->getConstructor();
+ $params = $constructor->getParameters();
+
+ $this->assertCount(2, $params);
+ $this->assertEquals('Domain\Layouts\LayoutsRepository', $params[0]->getType()->getName());
+ $this->assertEquals('Domain\Languages\LanguagesRepository', $params[1]->getType()->getName());
+ }
+}
diff --git a/updates/0.20/ver_0.256.zip b/updates/0.20/ver_0.256.zip
new file mode 100644
index 0000000..bb16d60
Binary files /dev/null and b/updates/0.20/ver_0.256.zip differ
diff --git a/updates/0.20/ver_0.256_files.txt b/updates/0.20/ver_0.256_files.txt
new file mode 100644
index 0000000..b90b43d
--- /dev/null
+++ b/updates/0.20/ver_0.256_files.txt
@@ -0,0 +1,2 @@
+F: ../autoload/admin/controls/class.Layouts.php
+F: ../autoload/admin/view/class.Layouts.php
diff --git a/updates/changelog.php b/updates/changelog.php
index c038a18..b402229 100644
--- a/updates/changelog.php
+++ b/updates/changelog.php
@@ -1,8 +1,15 @@
-ver. 0.255 - 12.02.2026
+ver. 0.256 - 12.02.2026
+- NEW - migracja modulu `Layouts` do architektury Domain + DI (`Domain\\Layouts\\LayoutsRepository`, `admin\\Controllers\\LayoutsController`)
+- UPDATE - lista `/admin/layouts/view_list/` przepieta z legacy `grid` na `components/table-list` (filtry, sortowanie, paginacja)
+- UPDATE - `layouts/layout-edit` korzysta z danych z repozytorium (menus/categories), bez wywolan legacy factory w widoku
+- UPDATE - `Domain\\Languages\\LanguagesRepository` rozszerzone o wspolna metode `defaultLanguageId()`
+- UPDATE - `admin\\Controllers\\ArticlesController` pobiera layouty przez `Domain\\Layouts\\LayoutsRepository` (DI)
+- CLEANUP - usuniete legacy klasy `autoload/admin/controls/class.Layouts.php`, `autoload/admin/view/class.Layouts.php`
+
ver. 0.255 - 12.02.2026
- UPDATE - kontrolery admin `Settings`, `Banners`, `Dictionaries`, `Articles` pobieraja liste jezykow przez `Domain\\Languages\\LanguagesRepository` (DI)
- UPDATE - routing DI (`admin\\Site`) przekazuje `LanguagesRepository` do kontrolerow `Articles`, `Banners`, `Settings`, `Dictionaries`
- UPDATE - aktywne legacy odwolania (`admin\\controls`, `admin\\factory\\Shop*`) przepiete z `admin\\factory\\Languages` na `LanguagesRepository`
-- FIX - `autoload/admin/factory/class.Languages.php` uzywa `ver. 0.254 - 12.02.2026
- 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`
@@ -383,3 +390,4 @@
+
diff --git a/updates/versions.php b/updates/versions.php
index f6ef0de..b64e3e9 100644
--- a/updates/versions.php
+++ b/updates/versions.php
@@ -1,5 +1,5 @@
-$current_ver = 255;
+$current_ver = 256;
for ($i = 1; $i <= $current_ver; $i++)
{
@@ -45,3 +45,4 @@ else
echo $ver . PHP_EOL;
}
+