From 67705f1f56f8753aae975976d76c1fc645f2acdc Mon Sep 17 00:00:00 2001 From: Jacek Pyziak Date: Fri, 13 Feb 2026 21:17:21 +0100 Subject: [PATCH] ver 0.262 - pages module refactor and admin UX fixes --- PROJECT_STRUCTURE.md | 8 + REFACTORING_PLAN.md | 18 + TESTING.md | 14 + admin/ajax.php | 1 - admin/ajax/pages.php | 63 -- .../articles/article-edit-custom-script.php | 24 +- admin/templates/banners/banner-edit.php | 4 +- admin/templates/layouts/layout-edit.php | 17 +- admin/templates/pages/menu-edit.php | 43 +- admin/templates/pages/page-articles.php | 132 ++-- admin/templates/pages/page-edit.php | 401 +---------- admin/templates/pages/pages-browse-list.php | 240 +++---- admin/templates/pages/pages-list.php | 371 +++++----- .../templates/pages/subpages-browse-list.php | 133 ++-- admin/templates/pages/subpages-list.php | 129 ++-- admin/templates/settings/settings.php | 4 +- .../templates/shop-category/category-edit.php | 22 +- admin/templates/shop-product/product-edit.php | 84 +-- admin/templates/site/main-layout.php | 72 +- autoload/Domain/Pages/PagesRepository.php | 626 +++++++++++++++++ .../Controllers/ArticlesArchiveController.php | 12 +- .../admin/Controllers/ArticlesController.php | 30 +- .../admin/Controllers/BannerController.php | 22 +- .../Controllers/DictionariesController.php | 20 +- .../admin/Controllers/LayoutsController.php | 12 +- .../admin/Controllers/PagesController.php | 660 ++++++++++++++++++ .../Controllers/ProductArchiveController.php | 4 +- .../Controllers/ScontainersController.php | 20 +- .../admin/Controllers/SettingsController.php | 4 +- .../admin/Support/Forms/FormFieldRenderer.php | 19 + autoload/admin/class.Site.php | 63 +- autoload/admin/controls/class.Pages.php | 117 ---- autoload/admin/controls/class.ShopProduct.php | 6 +- autoload/admin/factory/class.Articles.php | 3 +- autoload/admin/factory/class.Layouts.php | 19 +- autoload/admin/factory/class.Pages.php | 407 ----------- autoload/admin/view/class.Pages.php | 37 - .../Unit/Domain/Pages/PagesRepositoryTest.php | 66 ++ .../Controllers/ArticlesControllerTest.php | 12 +- .../admin/Controllers/PagesControllerTest.php | 82 +++ updates/0.20/ver_0.262.zip | Bin 0 -> 76773 bytes updates/0.20/ver_0.262_files.txt | 4 + updates/changelog.php | 10 +- updates/versions.php | 3 +- 44 files changed, 2235 insertions(+), 1803 deletions(-) delete mode 100644 admin/ajax/pages.php create mode 100644 autoload/Domain/Pages/PagesRepository.php create mode 100644 autoload/admin/Controllers/PagesController.php delete mode 100644 autoload/admin/controls/class.Pages.php delete mode 100644 autoload/admin/factory/class.Pages.php delete mode 100644 autoload/admin/view/class.Pages.php create mode 100644 tests/Unit/Domain/Pages/PagesRepositoryTest.php create mode 100644 tests/Unit/admin/Controllers/PagesControllerTest.php create mode 100644 updates/0.20/ver_0.262.zip create mode 100644 updates/0.20/ver_0.262_files.txt diff --git a/PROJECT_STRUCTURE.md b/PROJECT_STRUCTURE.md index 4d4640f..7b07d2c 100644 --- a/PROJECT_STRUCTURE.md +++ b/PROJECT_STRUCTURE.md @@ -471,3 +471,11 @@ Aktualnie w suite są też testy modułów `Dictionaries`, `Articles` i `Users` - **UPDATE:** potwierdzenia usuwania zdjec i zalacznikow w edycji artykulu ujednolicone wizualnie z dialogiem usuwania z listy (jquery-confirm, `table-list-confirm-dialog`). - **FIX:** dodane ladowanie biblioteki `jquery-impromptu` w widoku edycji artykulu (kompatybilnosc dla `$.prompt`). - Testy: 178 tests, 443 assertions. + +## Aktualizacja 2026-02-13 (Pages) +- NOWE: `Domain\\Pages\\PagesRepository` (menu/page CRUD, drzewo stron, sortowanie, SEO, endpointy pomocnicze). +- NOWE: `admin\\Controllers\\PagesController` (DI) dla modulu `/admin/pages/*`. +- UPDATE: widoki `admin/templates/pages/*` dzialaja bez `admin\\factory\\Pages` i `admin\\view\\Pages`. +- UPDATE: routing DI (`admin\\Site`) ma fabryke kontrolera `Pages`. +- UPDATE: zalezne endpointy `cookie_*` i `generate_seo_link` przepiete na `/admin/pages/*`. +- CLEANUP: usuniete legacy pliki `autoload/admin/controls/class.Pages.php`, `autoload/admin/view/class.Pages.php`, `autoload/admin/factory/class.Pages.php`, `admin/ajax/pages.php`. diff --git a/REFACTORING_PLAN.md b/REFACTORING_PLAN.md index 031b0c2..2addebf 100644 --- a/REFACTORING_PLAN.md +++ b/REFACTORING_PLAN.md @@ -682,3 +682,21 @@ Gdy `persist = true`: - UPDATE: potwierdzenia usuwania zdjec i zalacznikow przepiete na `jquery-confirm` ze stylem `table-list-confirm-dialog` (jak na liscie artykulow). - FIX: dolaczona biblioteka `jquery-impromptu` w widoku edycji artykulu dla kompatybilnosci. - Testy po zmianie: **178 tests, 443 assertions**. + +## Plan 2026-02-13 - Refaktoryzacja `/admin/pages/` +- [x] Dodac `Domain\Pages\PagesRepository` (CRUD menu/stron, drzewo stron, sortowanie, SEO, operacje AJAX). +- [x] Dodac `admin\Controllers\PagesController` (DI) i przepiac routing `/admin/pages/*` na nowy kontroler. +- [x] Przebudowac widoki `admin/templates/pages/*` tak, aby nie korzystaly z `admin\factory\Pages` i `admin\view\Pages`. +- [x] Przepiac endpointy AJAX z `/admin/ajax.php?a=*` na `/admin/pages/*` (`save_pages_order`, `save_articles_order`, `generate_seo_link`, `cookie_*`). +- [x] Przeszukac i zaktualizowac zaleznosci w innych modulach (`articles`, `layouts`, helpery) powiazane z Pages. +- [x] Usunac legacy klasy/pliki Pages (`autoload/admin/controls/class.Pages.php`, `autoload/admin/view/class.Pages.php`, `autoload/admin/factory/class.Pages.php`, `admin/ajax/pages.php`) po odpieciu zaleznosci. +- [x] Dodac/uzupelnic testy (`PagesRepository`, `PagesController`) i uruchomic testy. + +## Aktualizacja 2026-02-13 - Pages (/admin/pages) +- NOWE: `Domain\Pages\PagesRepository` (CRUD menu/stron, drzewo stron, porzadkowanie, SEO link, URL preview, cookies tree-state). +- NOWE: `admin\Controllers\PagesController` (DI) dla akcji: `view_list/list`, `browse_list`, `pages_url_browser`, `menu_*`, `page_*`, `save_*_order`, `generate_seo_link`, `cookie_*`. +- UPDATE: `/admin/pages/*` dziala bez legacy `admin\controls\Pages` i `admin\view\Pages`. +- UPDATE: widoki `admin/templates/pages/*` przepiete na dane z kontrolera/repozytorium (bez `admin\factory\Pages`). +- UPDATE: endpointy zalezne od Pages w innych modulach (`articles`, `layouts`, `shop-category`, `shop-product`) przepiete z `admin/ajax.php?a=*` na `/admin/pages/*`. +- CLEANUP: usuniete `autoload/admin/controls/class.Pages.php`, `autoload/admin/view/class.Pages.php`, `autoload/admin/factory/class.Pages.php`, `admin/ajax/pages.php`; `admin/ajax.php` nie includuje juz `ajax/pages.php`. +- Testy: **OK (186 tests, 478 assertions)**. diff --git a/TESTING.md b/TESTING.md index c971739..7978a3b 100644 --- a/TESTING.md +++ b/TESTING.md @@ -267,3 +267,17 @@ OK (178 tests, 443 assertions) Nowe testy/rozszerzenia 2026-02-13: - `tests/Unit/Domain/Article/ArticleRepositoryTest.php` (nowe przypadki dla `saveFilesOrder`) + +## Aktualizacja suite (Pages migration) +Ostatnio zweryfikowano: 2026-02-13 + +```text +OK (186 tests, 478 assertions) +``` + +Nowe testy dodane 2026-02-13: +- `tests/Unit/Domain/Pages/PagesRepositoryTest.php` +- `tests/Unit/admin/Controllers/PagesControllerTest.php` + +Zaktualizowane testy 2026-02-13: +- `tests/Unit/admin/Controllers/ArticlesControllerTest.php` (konstruktor z `Domain\\Pages\\PagesRepository`) diff --git a/admin/ajax.php b/admin/ajax.php index eeef67c..601c666 100644 --- a/admin/ajax.php +++ b/admin/ajax.php @@ -37,7 +37,6 @@ $mdb = new medoo( [ 'charset' => 'utf8' ] ); -require_once 'ajax/pages.php'; require_once 'ajax/shop-category.php'; require_once 'ajax/users.php'; require_once 'ajax/shop.php'; diff --git a/admin/ajax/pages.php b/admin/ajax/pages.php deleted file mode 100644 index c0d92d0..0000000 --- a/admin/ajax/pages.php +++ /dev/null @@ -1,63 +0,0 @@ - 'error', 'msg' => 'Podczas zapisywania kolejności wyświetlania artykułów wystąpił błąd. Proszę spróbować ponownie.' ]; - - if ( \admin\factory\Pages::save_articles_order( \S::get( 'page_id' ), \S::get( 'articles' ) ) ) - $response = [ 'status' => 'ok' ]; - - echo json_encode( $response ); - exit; -} - -if ( $a == 'save_pages_order' ) -{ - $response = [ 'status' => 'error', 'msg' => 'Podczas zapisywania kolejności stron wystąpił błąd. Proszę spróbować ponownie.' ]; - - if ( \admin\factory\Pages::save_pages_order( \S::get( 'menu_id' ), \S::get( 'pages' ) ) ) - $response = [ 'status' => 'ok' ]; - - echo json_encode( $response ); - exit; -} - -if ( $a == 'generate_seo_link' ) -{ - $response = [ 'status' => 'error', 'msg' => 'Podczas generowania pola "seo link" wystąpił błąd. Proszę spróbować ponownie.' ]; - - if ( $seo_link = \admin\factory\Pages::generate_seo_link( \S::get( 'title' ), \S::get( 'page_id' ), \S::get( 'article_id' ), \S::get( 'category_id' ) ) ) - $response = [ 'status' => 'ok', 'seo_link' => $seo_link ]; - - echo json_encode( $response ); - exit; -} - -if ( $a == 'cookie_menus' ) -{ - $array = unserialize( $_COOKIE[ 'cookie_menus' ] ); - - if ( $array[ \S::get( 'menu_id' ) ] == 0 ) - $array[ \S::get( 'menu_id' ) ] = 1; - else - $array[ \S::get( 'menu_id' ) ] = 0; - - $array = serialize( $array ); - - setcookie( 'cookie_menus', $array, time() + 3600 * 24 * 365 ); -} - -if ( $a == 'cookie_pages' ) -{ - $array = unserialize( $_COOKIE[ 'cookie_pages' ] ); - - if ( $array[ \S::get( 'page_id' ) ] == 0 ) - $array[ \S::get( 'page_id' ) ] = 1; - else - $array[ \S::get( 'page_id' ) ] = 0; - - $array = serialize( $array ); - - setcookie( 'cookie_pages', $array, time() + 3600 * 24 * 365 ); -} diff --git a/admin/templates/articles/article-edit-custom-script.php b/admin/templates/articles/article-edit-custom-script.php index 51a0b71..964f801 100644 --- a/admin/templates/articles/article-edit-custom-script.php +++ b/admin/templates/articles/article-edit-custom-script.php @@ -225,7 +225,7 @@ if (!empty($_COOKIE['cookie_menus'])) { $.ajax({ type: 'POST', cache: false, - url: '/admin/articles/gallery_order_save/', + url: '/admin/articles/galleryOrderSave/', data: { article_id: article_id, order: order @@ -256,7 +256,7 @@ if (!empty($_COOKIE['cookie_menus'])) { $.ajax({ type: 'POST', cache: false, - url: '/admin/articles/files_order_save/', + url: '/admin/articles/filesOrderSave/', data: { article_id: article_id, order: order @@ -404,20 +404,18 @@ if (!empty($_COOKIE['cookie_menus'])) { $.ajax({ type: 'POST', cache: false, - url: '/admin/ajax.php', + url: '/admin/pages/cookieMenus/', data: { - a: 'cookie_menus', menu_id: menu_id } }); } else { - var page_id = $(this).parent('div').parent('li').attr('id'); + var page_id = $(this).parent('div').parent('li').attr('id').replace('list_', ''); $.ajax({ type: 'POST', cache: false, - url: '/admin/ajax.php', + url: '/admin/pages/cookiePages/', data: { - a: 'cookie_pages', page_id: page_id } }); @@ -438,7 +436,7 @@ if (!empty($_COOKIE['cookie_menus'])) { $.ajax({ type: 'POST', cache: false, - url: '/admin/articles/article_image_alt_change/', + url: '/admin/articles/imageAltChange/', data: { image_id: image_id, image_alt: image_alt @@ -463,7 +461,7 @@ if (!empty($_COOKIE['cookie_menus'])) { $.ajax({ type: 'POST', cache: false, - url: '/admin/articles/article_file_name_change/', + url: '/admin/articles/fileNameChange/', data: { file_id: file_id, file_name: file_name @@ -489,7 +487,7 @@ if (!empty($_COOKIE['cookie_menus'])) { $.ajax({ type: 'POST', cache: false, - url: '/admin/articles/article_file_delete/', + url: '/admin/articles/fileDelete/', data: { file_id: file_id }, @@ -519,7 +517,7 @@ if (!empty($_COOKIE['cookie_menus'])) { $.ajax({ type: 'POST', cache: false, - url: '/admin/articles/article_image_delete/', + url: '/admin/articles/imageDelete/', data: { image_id: image_id }, @@ -555,9 +553,8 @@ if (!empty($_COOKIE['cookie_menus'])) { $.ajax({ type: 'POST', cache: false, - url: '/admin/ajax.php', + url: '/admin/pages/generateSeoLink/', data: { - a: 'generate_seo_link', title: title, article_id: article_id }, @@ -581,3 +578,4 @@ if (!empty($_COOKIE['cookie_menus'])) { }); } + diff --git a/admin/templates/banners/banner-edit.php b/admin/templates/banners/banner-edit.php index 469abb8..21fc5a3 100644 --- a/admin/templates/banners/banner-edit.php +++ b/admin/templates/banners/banner-edit.php @@ -150,8 +150,8 @@ $grid -> fields = [ ]; $grid -> external_code = $out; $grid -> actions = [ - 'save' => [ 'url' => '/admin/banners/banner_save/', 'back_url' => '/admin/banners/view_list/' ], - 'cancel' => [ 'url' => '/admin/banners/view_list/' ] + 'save' => [ 'url' => '/admin/banners/save/', 'back_url' => '/admin/banners/list/' ], + 'cancel' => [ 'url' => '/admin/banners/list/' ] ]; $grid -> persist_edit = true; $grid -> id_param = 'id'; diff --git a/admin/templates/layouts/layout-edit.php b/admin/templates/layouts/layout-edit.php index 0c3f5ed..2de458c 100644 --- a/admin/templates/layouts/layout-edit.php +++ b/admin/templates/layouts/layout-edit.php @@ -92,9 +92,8 @@ { type: 'POST', cache: false, - url: '/admin/ajax.php', + url: '/admin/pages/cookieMenus/', data: { - a: 'cookie_menus', menu_id: menu_id } }); @@ -107,10 +106,9 @@ { type: 'POST', cache: false, - url: '/admin/ajax.php', + url: '/admin/pages/cookiePages/', data: { - a: 'cookie_pages', - page_id: page_id + page_id: page_id.replace( 'list_', '' ) } }); } @@ -159,14 +157,14 @@ ob_start(); );?> 'Szablon domyślny', + 'label' => 'Szablon domyślny', 'name' => 'status', 'checked' => $this -> layout['status'] == 1 ? true : false ) );?> 'Szablon domyślny (kategorie)', + 'label' => 'Szablon domyślny (kategorie)', 'name' => 'categories_default', 'checked' => $this -> layout['categories_default'] == 1 ? true : false ) @@ -246,8 +244,8 @@ $grid -> fields = [ ] ]; $grid -> actions = [ - 'save' => [ 'url' => '/admin/layouts/layout_save/', 'back_url' => '/admin/layouts/view_list/' ], - 'cancel' => [ 'url' => '/admin/layouts/view_list/' ] + 'save' => [ 'url' => '/admin/layouts/save/', 'back_url' => '/admin/layouts/list/' ], + 'cancel' => [ 'url' => '/admin/layouts/list/' ] ]; $grid -> external_code = $out; $grid -> persist_edit = true; @@ -255,3 +253,4 @@ $grid -> id_param = 'id'; echo $grid -> draw(); ?> + diff --git a/admin/templates/pages/menu-edit.php b/admin/templates/pages/menu-edit.php index dc74f28..5fe1611 100644 --- a/admin/templates/pages/menu-edit.php +++ b/admin/templates/pages/menu-edit.php @@ -1,42 +1 @@ - gdb_opt = $gdb; -$grid -> include_plugins = true; -$grid -> title = 'Zapisz menu'; -$grid -> fields = [ - [ - 'db' => 'id', - 'type' => 'hidden', - 'value' => $this -> menu['id'] - ], - [ - 'name' => 'Nazwa', - 'db' => 'name', - 'type' => 'text', - 'value' => $this -> menu['name'], - 'params' => [ 'class' => 'require' ] - ], - [ - 'name' => 'Aktywne', - 'db' => 'status', - 'type' => 'input_switch', - 'checked' => $this -> menu['status'] ? true : false, - 'replace' => [ 'array' => [ 0 => 'nie', 1 => 'tak' ] ] - ] - ]; -$grid -> actions = [ - 'save' => [ 'url' => '/admin/pages/menu_save/', 'back_url' => '/admin/pages/view_list/' ], - 'cancel' => [ 'url' => '/admin/pages/view_list/' ] - ]; -$grid -> persist_edit = true; -$grid -> id_param = 'id'; -echo $grid -> draw(); -?> - \ No newline at end of file + $this->form]); ?> diff --git a/admin/templates/pages/page-articles.php b/admin/templates/pages/page-articles.php index 33d6ba2..8e32fab 100644 --- a/admin/templates/pages/page-articles.php +++ b/admin/templates/pages/page-articles.php @@ -1,89 +1,87 @@ -page_id ?? 0); +$articles = is_array($this->articles ?? null) ? $this->articles : []; + ob_start(); ?> -
    - articles ) ) foreach ( $this -> articles as $article ) - { - ?> -
  1. -
    -
  2. - + + -
-"> +
+ + + + gdb_opt = $gdb; -$grid -> include_plugins = true; -$grid -> default_buttons = false; -$grid -> external_code = $out; -$grid -> title = 'Lista artykułów'; -$grid -> buttons = [ - [ - 'label' => 'Wstecz', - 'url' => '/admin/pages/view_list/', - 'icon' => 'fa-reply', - 'class' => 'btn-dark' - ] - ]; -echo $grid -> draw(); +$grid->gdb_opt = $gdb; +$grid->include_plugins = true; +$grid->default_buttons = false; +$grid->external_code = $out; +$grid->title = 'Lista artykułów'; +$grid->buttons = [ + [ + 'label' => 'Wstecz', + 'url' => '/admin/pages/list/', + 'icon' => 'fa-reply', + 'class' => 'btn-dark', + ], +]; +echo $grid->draw(); ?> \ No newline at end of file + + + diff --git a/admin/templates/pages/page-edit.php b/admin/templates/pages/page-edit.php index f2857c8..5fe1611 100644 --- a/admin/templates/pages/page-edit.php +++ b/admin/templates/pages/page-edit.php @@ -1,400 +1 @@ - - -
- -
-
-
-
- -
-
-
- languages ) ): foreach ( $this -> languages as $lg ):?> - -
- 'Nazwa strony', - 'name' => 'title[' . $lg['id'] . ']', - 'id' => 'title_' . $lg['id'], - 'value' => $this -> page[ 'languages' ][ $lg['id'] ]['title'], - ) - );?> -
- - -
-
-
-
-
- menus ) ): foreach ( $this -> menus as $menu ): - $menus[ $menu['id'] ] = $menu['name']; - endforeach; endif; - ?> - 'Menu', - 'name' => 'menu_id', - 'values' => $menus, - 'value' => $this -> page['id'] ? $this -> page['menu_id'] : $this -> menu_id - ) - );?> - 'Typ strony', - 'name' => 'page_type', - 'id' => 'page_type', - 'values' => \admin\factory\Pages::$_page_types, - 'value' => $this -> page['page_type'] - ) - );?> - -
-
- 'hidden', - 'name' => 'category_id', - 'id' => 'category_id', - 'value' => $this -> page['category_id'] - ) - ); - ?> - 'Kategoria', - 'name' => 'category_title', - 'id' => 'category_title', - 'value' => $this -> page['category_id'] ? \admin\factory\ShopCategory::category_title( $this -> page['category_id'] ) : '', - 'icon_class' => 'fa fa-link', - 'icon_js' => 'category_url_browser();' - ) - ); - ?> -
-
- 'Sortowanie artykułów', - 'name' => 'sort_type', - 'id' => 'sort_type', - 'values' => \admin\factory\Pages::$_sort_types, - 'value' => $this -> page['sort_type'] - ) - );?> - layouts ) ): foreach ( $this -> layouts as $layout ): - $layouts[ $layout['id'] ] = $layout['name']; - endforeach; endif; - ?> - 'Szablon', - 'name' => 'layout_id', - 'id' => 'layout_id', - 'values' => $layouts, - 'value' => $this -> page['layout_id'] - ) - );?> - 'Liczba artykułów na stronę', - 'name' => 'articles_limit', - 'id' => 'articles_limit', - 'value' => $this -> page['articles_limit'] ? $this -> page['articles_limit'] : 2 - ) - );?> - 'Pokaż tytuł', - 'name' => 'show_title', - 'checked' => $this -> page['show_title'] == 1 or !$this -> page['id'] ? true : false - ) - );?> - 'Aktywna', - 'name' => 'status', - 'checked' => $this -> page['status'] == 1 or !$this -> page['id'] ? true : false - ) - );?> - 'Strona startowa', - 'name' => 'start', - 'checked' => $this -> page['start'] == 1 ? true : false - ) - );?> -
-
-
-
- -
-
-
- languages ) ): foreach ( $this -> languages as $lg ):?> - -
- 'Link SEO', - 'name' => 'seo_link[' . $lg['id'] . ']', - 'id' => 'seo_link_' . $lg['id'], - 'value' => $this -> page['languages' ][ $lg['id'] ]['seo_link'], - 'icon_content' => 'generuj', - 'icon_js' => 'generate_seo_links( "' . $lg['id'] . '", $( "#title_' . $lg['id'] . '" ).val(), ' . (int)$this -> page['id'] . ' );' - ] );?> - 'Tytuł strony (h1)', - 'name' => 'page_title[' . $lg['id'] . ']', - 'id' => 'page_title_' . $lg['id'], - 'value' => $this -> page['languages' ][ $lg['id'] ]['page_title'] - ] );?> - 'Meta title', - 'name' => 'meta_title[' . $lg['id'] . ']', - 'id' => 'meta_title_' . $lg['id'], - 'value' => $this -> page['languages'][ $lg['id'] ]['meta_title'] - ] );?> - 'Meta description', - 'name' => 'meta_description[' . $lg['id'] . ']', - 'id' => 'meta_description_' . $lg['id'], - 'value' => $this -> page['languages'][ $lg['id'] ]['meta_description'] - ] );?> - 'Meta keywords', - 'name' => 'meta_keywords[' . $lg['id'] . ']', - 'id' => 'meta_keywords_' . $lg['id'], - 'value' => $this -> page['languages'][ $lg['id'] ]['meta_keywords'] - ] );?> - 'Blokuj indeksację', - 'name' => 'noindex[' . $lg['id'] . ']', - 'id' => 'noindex_' . $lg['id'], - 'values' => [ 0 => 'nie', 1 => 'tak' ], - 'value' => $this -> page['languages'][ $lg['id'] ]['noindex'] == 1 ? 1 : 0 - ] );?> - 'Rel canonical', - 'name' => 'canonical[' . $lg['id'] . ']', - 'id' => 'canonical_' . $lg['id'], - 'value' => $this -> page['languages'][ $lg['id'] ]['canonical'] - ] );?> -
- - -
-
-
-
-
-
- id = 'page-edit'; -$grid -> gdb_opt = $gdb; -$grid -> include_plugins = true; -$grid -> title = 'Edycja strony'; -$grid -> fields = [ - [ - 'db' => 'id', - 'type' => 'hidden', - 'value' => $this -> page['id'] - ], - [ - 'db' => 'parent_id', - 'type' => 'hidden', - 'value' => $this -> page['id'] ? $this -> page['parent_id'] : $this -> parent_id - ] - ]; -$grid -> actions = [ - 'save' => [ 'url' => '/admin/pages/page_save/', 'back_url' => '/admin/pages/view_list/' ], - 'cancel' => [ 'url' => '/admin/pages/view_list/' ] - ]; -$grid -> external_code = $out; -$grid -> persist_edit = true; -$grid -> id_param = 'id'; - -echo $grid -> draw(); -?> \ No newline at end of file + $this->form]); ?> diff --git a/admin/templates/pages/pages-browse-list.php b/admin/templates/pages/pages-browse-list.php index d7077fb..2cbe209 100644 --- a/admin/templates/pages/pages-browse-list.php +++ b/admin/templates/pages/pages-browse-list.php @@ -1,48 +1,57 @@ - menus ) ) foreach ( $this -> menus as $menu ) - { - ?> - - menus ?? null) ? $this->menus : []; +$modal = !empty($this->modal); +$cookiePages = is_array($this->cookie_pages ?? null) ? $this->cookie_pages : []; +$cookieMenus = is_array($this->cookie_menus ?? null) ? $this->cookie_menus : []; +ob_start(); +foreach ($menus as $menu): + $menuId = (int)($menu['id'] ?? 0); + $menuName = (string)($menu['name'] ?? ''); + $menuStatus = (int)($menu['status'] ?? 0); +?> + + id = 'pages-list'; -$grid -> gdb_opt = $gdb; -$grid -> include_plugins = true; -$grid -> title = 'Lista stron'; -$grid -> default_buttons = false; -$grid -> external_code = $out; +$grid->id = 'pages-list'; +$grid->gdb_opt = $gdb; +$grid->include_plugins = true; +$grid->title = 'Lista stron'; +$grid->default_buttons = false; +$grid->external_code = $out; -echo $grid -> draw(); +echo $grid->draw(); ?> \ No newline at end of file + + diff --git a/admin/templates/pages/pages-list.php b/admin/templates/pages/pages-list.php index 0219d50..12549f8 100644 --- a/admin/templates/pages/pages-list.php +++ b/admin/templates/pages/pages-list.php @@ -1,208 +1,249 @@ - menus ) ) foreach ( $this -> menus as $menu ) - { - ?> - - menus ?? null) ? $this->menus : []; +$cookiePages = is_array($this->cookie_pages ?? null) ? $this->cookie_pages : []; +$cookieMenus = is_array($this->cookie_menus ?? null) ? $this->cookie_menus : []; +ob_start(); +foreach ($menus as $menu): + $menuId = (int)($menu['id'] ?? 0); + $menuName = (string)($menu['name'] ?? ''); + $menuStatus = (int)($menu['status'] ?? 0); +?> + + id = 'pages-list'; -$grid -> gdb_opt = $gdb; -$grid -> include_plugins = true; -$grid -> title = 'Lista stron'; -$grid -> default_buttons = false; -$grid -> buttons = [ - [ - 'label' => 'Dodaj menu', - 'url' => '/admin/pages/menu_edit/', - 'icon' => 'fa-plus-circle', - 'class' => 'btn-success' - ] - ]; -$grid -> external_code = $out; +$grid->id = 'pages-list'; +$grid->gdb_opt = $gdb; +$grid->include_plugins = true; +$grid->title = 'Lista stron'; +$grid->default_buttons = false; +$grid->buttons = [ + [ + 'label' => 'Dodaj menu', + 'url' => '/admin/pages/menuEdit/', + 'icon' => 'fa-plus-circle', + 'class' => 'btn-success', + ], +]; +$grid->external_code = $out; -echo $grid -> draw(); +echo $grid->draw(); ?> + \ No newline at end of file + + + diff --git a/admin/templates/pages/subpages-browse-list.php b/admin/templates/pages/subpages-browse-list.php index 0602642..8c14390 100644 --- a/admin/templates/pages/subpages-browse-list.php +++ b/admin/templates/pages/subpages-browse-list.php @@ -1,77 +1,60 @@ - pages ) ):?> - -
    - pages as $page ):?> -
  1. -
    - - '; +pages ?? null) ? $this->pages : []; +$step = (int)($this->step ?? 1); - if ( $page['start'] ) - echo ''; - - echo $page['title']; - - if ( is_array( $page['languages'] ) ): - echo '
    '; - foreach ( $page['languages'] as $lg ) - echo ''; - echo '
    '; - endif; - - $default_language = \front\factory\Languages::default_language(); - if ( is_array( $page['languages'] ) ): - foreach ( $page['languages'] as $lg ): - echo ''; - endforeach; - endif; - ?> -
    - step + 1 ); +if (empty($pages)) { + return; +} +?> +
      + + - - -
    - \ No newline at end of file +
  2. +
    + + + + + + +
    + + + + + + +
    + + + + +
    + + + +
    + +
    + + $page['subpages'] ?? [], + 'step' => $step + 1, + ]); ?> +
  3. + +
diff --git a/admin/templates/pages/subpages-list.php b/admin/templates/pages/subpages-list.php index 1c9c0e8..fd85e11 100644 --- a/admin/templates/pages/subpages-list.php +++ b/admin/templates/pages/subpages-list.php @@ -1,60 +1,75 @@ - pages ) ):?> -
    - pages as $page ):?> -
  1. -
    - - \admin\factory\Pages::menu_pages( $this -> menu_id, $page['id'] ), - 'menu_id' => $this -> menu_id, - 'parent_id' => $page['id'], - 'step' => $this -> step + 1 - ] ); - ?> -
  2. - -
- \ No newline at end of file + + + + + +
+ $page['subpages'] ?? [], + 'step' => $step + 1, + ]); ?> + + + + diff --git a/admin/templates/settings/settings.php b/admin/templates/settings/settings.php index 1f2337a..37274e3 100644 --- a/admin/templates/settings/settings.php +++ b/admin/templates/settings/settings.php @@ -361,7 +361,7 @@ $grid -> gdb_opt = $gdb; $grid -> include_plugins = true; $grid -> title = 'Edycja ustawień'; $grid -> actions = [ - 'save' => [ 'url' => '/admin/settings/settings_save/', 'back_url' => '' ], + 'save' => [ 'url' => '/admin/settings/save/', 'back_url' => '' ], ]; $grid -> persist_edit = true; $grid -> external_code = $out; @@ -378,4 +378,4 @@ echo $grid -> draw(); html: true }); }); - \ No newline at end of file + diff --git a/admin/templates/shop-category/category-edit.php b/admin/templates/shop-category/category-edit.php index 0b0cb95..9ef6831 100644 --- a/admin/templates/shop-category/category-edit.php +++ b/admin/templates/shop-category/category-edit.php @@ -36,9 +36,8 @@ { type: 'POST', cache: false, - url: '/admin/ajax.php', + url: '/admin/pages/generateSeoLink/', data: { - a: 'generate_seo_link', title: title, category_id: category_id }, @@ -67,7 +66,7 @@ ob_start(); ?>
@@ -77,7 +76,7 @@ ob_start(); @@ -105,7 +104,7 @@ ob_start(); );?> 'Opis kategorii (rozwinięcie)', + 'label' => 'Opis kategorii (rozwiniÄ™cie)', 'name' => 'text_hidden[' . $lg['id'] . ']', 'id' => 'text_hidden_' . $lg['id'], 'value' => $this -> category['languages'][ $lg['id'] ]['text_hidden'], @@ -144,7 +143,7 @@ ob_start(); );?> 'Sortowanie produktów', + 'label' => 'Sortowanie produktĂłw', 'name' => 'sort_type', 'id' => 'sort_type', 'values' => \admin\factory\ShopCategory::$_sort_types, @@ -153,7 +152,7 @@ ob_start(); );?> 'Wyświetlić podkategorie', + 'label' => 'WyĹ›wietlić podkategorie', 'name' => 'view_subcategories', 'checked' => $this -> category['view_subcategories'] == 1 ? true : false ) @@ -164,7 +163,7 @@ ob_start(); @@ -184,7 +183,7 @@ ob_start(); );?> 'Tytuł kategorii (h1)', + 'label' => 'TytuĹ‚ kategorii (h1)', 'name' => 'category_title[' . $lg['id'] . ']', 'id' => 'category_title_' . $lg['id'], 'value' => $this -> category['languages' ][ $lg['id'] ]['category_title'] @@ -216,7 +215,7 @@ ob_start(); );?> 'Blokuj indeksację', + 'label' => 'Blokuj indeksacjÄ™', 'name' => 'noindex[' . $lg['id'] . ']', 'id' => 'noindex_' . $lg['id'], 'values' => array( @@ -263,4 +262,5 @@ $grid -> persist_edit = true; $grid -> id_param = 'id'; echo $grid -> draw(); -?> \ No newline at end of file +?> + diff --git a/admin/templates/shop-product/product-edit.php b/admin/templates/shop-product/product-edit.php index e4a216a..e5a07a3 100644 --- a/admin/templates/shop-product/product-edit.php +++ b/admin/templates/shop-product/product-edit.php @@ -21,15 +21,15 @@ ob_start();
  • Opis
  • -
  • Zakładki
  • +
  • ZakĹ‚adki
  • Cena
  • Magazyn
  • Ustawienia
  • SEO
  • -
  • Wyświetlanie
  • +
  • WyĹ›wietlanie
  • Galeria
  • -
  • Załączniki
  • -
  • Produkty powiązane
  • +
  • Załączniki
  • +
  • Produkty powiÄ…zane
  • XML
  • Dodatkowe pola
  • GPSR
  • @@ -40,7 +40,7 @@ ob_start();
      languages)) : foreach ($this->languages as $lg) : ?> -
    • '; ?>
    • +
    • '; ?>
    • languages)) foreach ($this->languages as $lg_tmp) { @@ -65,7 +65,7 @@ ob_start(); 'Wyświetlaj treść z wersji', + 'label' => 'WyĹ›wietlaj treść z wersji', 'name' => 'copy_from[' . $lg['id'] . ']', 'values' => $languages, 'value' => $this->product['languages'][$lg['id']]['copy_from'], @@ -86,7 +86,7 @@ ob_start(); 'Komunikat gdy stan magazynowy równy 0', + 'label' => 'Komunikat gdy stan magazynowy rĂłwny 0', 'name' => 'warehouse_message_zero[' . $lg['id'] . ']', 'id' => 'warehouse_message_zero_' . $lg['id'], 'value' => $this->product['languages'][$lg['id']]['warehouse_message_zero'], @@ -97,7 +97,7 @@ ob_start(); 'Komunikat gdy stan magazynowy większy niż 0', + 'label' => 'Komunikat gdy stan magazynowy wiÄ™kszy niĹĽ 0', 'name' => 'warehouse_message_nonzero[' . $lg['id'] . ']', 'id' => 'warehouse_message_nonzero_' . $lg['id'], 'value' => $this->product['languages'][$lg['id']]['warehouse_message_nonzero'], @@ -108,7 +108,7 @@ ob_start(); 'Krótki opis', + 'label' => 'KrĂłtki opis', 'name' => 'short_description[' . $lg['id'] . ']', 'id' => 'short_description_' . $lg['id'], 'value' => $this->product['languages'][$lg['id']]['short_description'], @@ -154,7 +154,7 @@ ob_start();
        languages)) : foreach ($this->languages as $lg) : ?> -
      • '; ?>
      • +
      • '; ?>
      • languages)) foreach ($this->languages as $lg_tmp) { @@ -179,7 +179,7 @@ ob_start(); 'Nazwa zakładki (1)', + 'label' => 'Nazwa zakĹ‚adki (1)', 'name' => 'tab_name_1[' . $lg['id'] . ']', 'id' => 'tab_name_1_' . $lg['id'], 'value' => $this->product['languages'][$lg['id']]['tab_name_1'], @@ -190,7 +190,7 @@ ob_start(); 'Zawartość zakładki (1)', + 'label' => 'Zawartość zakĹ‚adki (1)', 'name' => 'tab_description_1[' . $lg['id'] . ']', 'id' => 'tab_description_1_' . $lg['id'], 'value' => $this->product['languages'][$lg['id']]['tab_description_1'], @@ -201,7 +201,7 @@ ob_start(); 'Nazwa zakładki (2)', + 'label' => 'Nazwa zakĹ‚adki (2)', 'name' => 'tab_name_2[' . $lg['id'] . ']', 'id' => 'tab_name_2_' . $lg['id'], 'value' => $this->product['languages'][$lg['id']]['tab_name_2'], @@ -212,7 +212,7 @@ ob_start(); 'Zawartość zakładki (2)', + 'label' => 'Zawartość zakĹ‚adki (2)', 'name' => 'tab_description_2[' . $lg['id'] . ']', 'id' => 'tab_description_2_' . $lg['id'], 'value' => $this->product['languages'][$lg['id']]['tab_description_2'], @@ -305,7 +305,7 @@ ob_start(); ?> units as $unit) $units[$unit['id']] = $unit['text']; ?> @@ -317,7 +317,7 @@ ob_start(); 'value' => $this->product['product_unit_id'] ]); ?> 'Waga/pojemność', + 'label' => 'Waga/pojemność', 'name' => 'weight', 'id' => 'weight', 'class' => 'number-format', @@ -336,14 +336,14 @@ ob_start(); ?> 'Pozwól zamawiać gdy stan 0', + 'label' => 'PozwĂłl zamawiać gdy stan 0', 'name' => 'stock_0_buy', 'checked' => $this->product['stock_0_buy'] == 1 ? true : false ]); ?> 'Współczynnik WP', + 'label' => 'Współczynnik WP', 'name' => 'wp', 'id' => 'wp', 'class' => 'number-format', @@ -382,7 +382,7 @@ ob_start(); ?> 'Nowość do dnia', + 'label' => 'Nowość do dnia', 'name' => 'new_to_date', 'id' => 'new_to_date', 'class' => 'date', @@ -390,19 +390,19 @@ ob_start(); ]); ?> 'Wyświetlaj pole na dodatkową wiadomość', + 'label' => 'WyĹ›wietlaj pole na dodatkowÄ… wiadomość', 'name' => 'additional_message', 'checked' => $this->product['additional_message'] == 1 ? true : false ]); ?> 'Dodatkowa wiadomość jest wymagana', + 'label' => 'Dodatkowa wiadomość jest wymagana', 'name' => 'additional_message_required', 'checked' => $this->product['additional_message_required'] == 1 ? true : false ]); ?> 'Dodatkowa wiadomość (treść komunikatu)', + 'label' => 'Dodatkowa wiadomość (treść komunikatu)', 'name' => 'additional_message_text', 'id' => 'additional_message_text', 'value' => $this->product['additional_message_text'] @@ -414,7 +414,7 @@ ob_start();
          languages)) : foreach ($this->languages as $lg) : ?> -
        • '; ?>
        • +
        • '; ?>
        • layouts)) : foreach ($this->layouts as $layout) : $layouts[$layout['id']] = $layout['name']; endforeach; @@ -497,7 +497,7 @@ ob_start(); ]); ?>
          - +
          - +
          +
          @@ -700,7 +700,7 @@ ob_start();
          - usuń + usuĹ„
          @@ -724,7 +724,7 @@ ob_start();
            languages ) ): foreach ( $this -> languages as $lg ):?> -
          • '; ?>
          • +
          • '; ?>
          @@ -733,7 +733,7 @@ ob_start();
          'Informacje o bezpieczeństwie ('.$lg['name'].')', + 'label' => 'Informacje o bezpieczeĹ„stwie ('.$lg['name'].')', 'name' => 'security_information[' . $lg['id'] . ']', 'id' => 'security_information_' . $lg['id'], 'value' => $this->product['languages'][$lg['id']]['security_information'] @@ -776,7 +776,7 @@ $grid->actions = [ ]; $grid->buttons = [ [ - 'label' => 'Podgląd', + 'label' => 'PodglÄ…d', 'id' => 'product-preview', 'url' => '#', 'icon' => 'fa-search', @@ -845,7 +845,7 @@ echo $grid->draw(); html += '
          '; html += '
          '; html += '
          '; - html += 'usuń'; + html += 'usuĹ„'; html += '
          '; html += '
          '; html += '
          '; @@ -1138,8 +1138,8 @@ echo $grid->draw(); $(this).blur(); var file_id = $(this).attr('file_id'); - $.prompt('Na pewno chcesz usunąć wybrany plik?', { - title: 'Potwierdź?', + $.prompt('Na pewno chcesz usunąć wybrany plik?', { + title: 'PotwierdĹş?', submit: function(e, v, m, f) { if (v === true) { $.ajax({ @@ -1178,8 +1178,8 @@ echo $grid->draw(); $(this).blur(); var image_id = $(this).attr('image-id'); - $.prompt('Na pewno chcesz usunąć wybrane zdjęcie?', { - title: 'Potwierdź?', + $.prompt('Na pewno chcesz usunąć wybrane zdjÄ™cie?', { + title: 'PotwierdĹş?', submit: function(e, v, m, f) { if (v === true) { $.ajax({ @@ -1316,9 +1316,8 @@ echo $grid->draw(); $.ajax({ type: 'POST', cache: false, - url: '/admin/ajax.php', + url: '/admin/pages/generateSeoLink/', data: { - a: 'generate_seo_link', title: title, article_id: article_id }, @@ -1346,3 +1345,4 @@ echo $grid->draw(); + diff --git a/admin/templates/site/main-layout.php b/admin/templates/site/main-layout.php index 0d5baf7..167e055 100644 --- a/admin/templates/site/main-layout.php +++ b/admin/templates/site/main-layout.php @@ -6,7 +6,7 @@ - + @@ -54,7 +54,7 @@ Sklep
          -
          Zawartość
          +
          Zawartość
          Newsletter @@ -94,28 +94,28 @@
        • Ustawienia
        - Pozostałe + Pozostałe
        Konfiguracja
        - Słowniki + Słowniki
- Podgląd + Podgląd
@@ -167,7 +167,7 @@
- +
@@ -191,7 +191,7 @@
- +
@@ -228,41 +228,41 @@ } }); - // Obsługa przycisku czyszczenia cache + // Cache clear button handler $('#clear-cache-btn').on('click', function(e) { e.preventDefault(); var $btn = $(this); var originalText = $btn.text(); - // Wyświetl komunikat o czyszczeniu - $btn.prop('disabled', true).html(' Czyszczę cache...'); + // Show pending state + $btn.prop('disabled', true).html(' Czyszcz\u0119 cache...'); - // Wyślij żądanie AJAX + // Send AJAX request $.ajax({ - url: '/admin/settings/clear_cache_ajax/', + url: '/admin/settings/clearCacheAjax/', type: 'POST', dataType: 'json', success: function(response) { if (response.status === 'success') { - // Zmień komunikat na "wyczyszczono" + // Show success state $btn.html(' Cache wyczyszczony!').removeClass('btn-danger').addClass('btn-success'); - // Po 2 sekundach przywróć pierwotny stan + // Restore original state after delay setTimeout(function() { $btn.prop('disabled', false).html(originalText).removeClass('btn-success').addClass('btn-danger'); }, 2000); } else { - // Obsługa błędu - $btn.html(' Błąd!').removeClass('btn-danger').addClass('btn-warning'); + // Request failed on server + $btn.html(' B\u0142\u0105d!').removeClass('btn-danger').addClass('btn-warning'); setTimeout(function() { $btn.prop('disabled', false).html(originalText).removeClass('btn-warning').addClass('btn-danger'); }, 2000); } }, error: function() { - // Obsługa błędu połączenia - $btn.html(' Błąd połączenia!').removeClass('btn-danger').addClass('btn-warning'); + // Network or transport error + $btn.html(' B\u0142\u0105d po\u0142\u0105czenia!').removeClass('btn-danger').addClass('btn-warning'); setTimeout(function() { $btn.prop('disabled', false).html(originalText).removeClass('btn-warning').addClass('btn-danger'); }, 2000); diff --git a/autoload/Domain/Pages/PagesRepository.php b/autoload/Domain/Pages/PagesRepository.php new file mode 100644 index 0000000..7c9a941 --- /dev/null +++ b/autoload/Domain/Pages/PagesRepository.php @@ -0,0 +1,626 @@ + + */ + private const PAGE_TYPES = [ + 0 => 'pelne artykuly', + 1 => 'wprowadzenia', + 2 => 'miniaturki', + 3 => 'link', + 4 => 'kontakt', + 5 => 'kategoria sklepu', + ]; + + /** + * @var array + */ + private const SORT_TYPES = [ + 0 => 'data dodania - najstarsze na poczatku', + 1 => 'data dodania - najnowsze na poczatku', + 2 => 'data modyfikacji - rosnaco', + 3 => 'data modyfikacji - malejaco', + 4 => 'reczne', + 5 => 'alfabetycznie - A - Z', + 6 => 'alfabetycznie - Z - A', + ]; + + private $db; + + public function __construct($db) + { + $this->db = $db; + } + + /** + * @return array + */ + public function pageTypes(): array + { + return self::PAGE_TYPES; + } + + /** + * @return array + */ + public function sortTypes(): array + { + return self::SORT_TYPES; + } + + /** + * @return array> + */ + public function menusList(): array + { + $rows = $this->db->select('pp_menus', '*', ['ORDER' => ['id' => 'ASC']]); + return is_array($rows) ? $rows : []; + } + + /** + * @return array> + */ + public function menusWithPages(): array + { + $menus = $this->menusList(); + foreach ($menus as $index => $menu) { + $menuId = (int)($menu['id'] ?? 0); + $menus[$index]['pages'] = $this->menuPages($menuId); + } + + return $menus; + } + + /** + * @return array> + */ + public function menuPages(int $menuId, ?int $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['languages'] = $this->pageLanguages($pageId); + $row['subpages'] = $this->menuPages($menuId, $pageId); + $pages[] = $row; + } + + return $pages; + } + + public function menuDelete(int $menuId): bool + { + if ($menuId <= 0) { + return false; + } + + if ((int)$this->db->count('pp_pages', ['menu_id' => $menuId]) > 0) { + return false; + } + + return (bool)$this->db->delete('pp_menus', ['id' => $menuId]); + } + + public function pageDelete(int $pageId): bool + { + if ($pageId <= 0) { + return false; + } + + if ((int)$this->db->count('pp_pages', ['parent_id' => $pageId]) > 0) { + return false; + } + + return (bool)$this->db->delete('pp_pages', ['id' => $pageId]); + } + + /** + * @return array + */ + public function menuDetails(int $menuId): array + { + if ($menuId <= 0) { + return [ + 'id' => 0, + 'name' => '', + 'status' => 1, + ]; + } + + $menu = $this->db->get('pp_menus', '*', ['id' => $menuId]); + if (!is_array($menu)) { + return [ + 'id' => 0, + 'name' => '', + 'status' => 1, + ]; + } + + return $menu; + } + + public function menuSave(int $menuId, string $name, $status): bool + { + $statusValue = $this->toSwitchValue($status); + + if ($menuId <= 0) { + $result = $this->db->insert('pp_menus', [ + 'name' => $name, + 'status' => $statusValue, + ]); + + return (bool)$result; + } + + $this->db->update('pp_menus', [ + 'name' => $name, + 'status' => $statusValue, + ], [ + 'id' => $menuId, + ]); + + return true; + } + + /** + * @return array + */ + public function pageDetails(int $pageId): array + { + if ($pageId <= 0) { + return $this->defaultPage(); + } + + $page = $this->db->get('pp_pages', '*', ['id' => $pageId]); + if (!is_array($page)) { + return $this->defaultPage(); + } + + $translations = $this->db->select('pp_pages_langs', '*', ['page_id' => $pageId]); + if (is_array($translations)) { + foreach ($translations as $row) { + $langId = (string)($row['lang_id'] ?? ''); + if ($langId !== '') { + $page['languages'][$langId] = $row; + } + } + } + + $page['layout_id'] = (int)$this->db->get('pp_layouts_pages', 'layout_id', ['page_id' => $pageId]); + + return $page; + } + + /** + * @return array> + */ + public function pageArticles(int $pageId): array + { + if ($pageId <= 0) { + return []; + } + + $sql = ' + SELECT + ap.article_id, + ap.o, + a.status, + ( + SELECT title + FROM pp_articles_langs AS pal + JOIN pp_langs AS pl ON pal.lang_id = pl.id + WHERE pal.article_id = ap.article_id + AND pal.title != "" + ORDER BY pl.o ASC + LIMIT 1 + ) AS title + FROM pp_articles_pages AS ap + JOIN pp_articles AS a ON a.id = ap.article_id + WHERE ap.page_id = :page_id + AND a.status != -1 + ORDER BY ap.o ASC + '; + + $stmt = $this->db->query($sql, [':page_id' => $pageId]); + $rows = $stmt ? $stmt->fetchAll() : []; + + return is_array($rows) ? $rows : []; + } + + public function saveArticlesOrder(int $pageId, $articles): bool + { + if ($pageId <= 0) { + return false; + } + + if (!is_array($articles)) { + return true; + } + + $this->db->update('pp_articles_pages', ['o' => 0], ['page_id' => $pageId]); + + $position = 0; + foreach ($articles as $item) { + $articleId = (int)($item['item_id'] ?? 0); + if ($articleId <= 0) { + continue; + } + + $position++; + $this->db->update('pp_articles_pages', ['o' => $position], [ + 'AND' => [ + 'page_id' => $pageId, + 'article_id' => $articleId, + ], + ]); + } + + return true; + } + + public function savePagesOrder(int $menuId, $pages): bool + { + if ($menuId <= 0) { + return false; + } + + if (!is_array($pages)) { + return true; + } + + $this->db->update('pp_pages', ['o' => 0], ['menu_id' => $menuId]); + + $position = 0; + foreach ($pages as $item) { + $itemId = (int)($item['item_id'] ?? 0); + $depth = (int)($item['depth'] ?? 0); + if ($itemId <= 0 || $depth <= 1) { + continue; + } + + $parentId = (int)($item['parent_id'] ?? 0); + if ($depth === 2) { + $parentId = null; + } + + $position++; + $this->db->update('pp_pages', [ + 'o' => $position, + 'parent_id' => $parentId, + ], [ + 'id' => $itemId, + ]); + } + + \S::delete_dir('../temp/'); + + return true; + } + + public function pageSave(array $data): ?int + { + $pageId = (int)($data['id'] ?? 0); + $menuId = (int)($data['menu_id'] ?? 0); + $parentId = $this->normalizeNullableInt($data['parent_id'] ?? null); + $pageType = (int)($data['page_type'] ?? 0); + $sortType = (int)($data['sort_type'] ?? 0); + $layoutId = (int)($data['layout_id'] ?? 0); + $articlesLimit = (int)($data['articles_limit'] ?? 0); + $showTitle = $this->toSwitchValue($data['show_title'] ?? 0); + $status = $this->toSwitchValue($data['status'] ?? 0); + $start = $this->toSwitchValue($data['start'] ?? 0); + $categoryId = $this->normalizeNullableInt($data['category_id'] ?? null); + if ($pageType !== 5) { + $categoryId = null; + } + + if ($pageId <= 0) { + $order = $this->maxPageOrder() + 1; + $result = $this->db->insert('pp_pages', [ + 'menu_id' => $menuId, + 'page_type' => $pageType, + 'sort_type' => $sortType, + 'articles_limit' => $articlesLimit, + 'show_title' => $showTitle, + 'status' => $status, + 'o' => $order, + 'parent_id' => $parentId, + 'start' => $start, + 'category_id' => $categoryId, + ]); + + if (!$result) { + return null; + } + + $pageId = (int)$this->db->id(); + if ($pageId <= 0) { + return null; + } + } else { + $this->db->update('pp_pages', [ + 'menu_id' => $menuId, + 'page_type' => $pageType, + 'sort_type' => $sortType, + 'articles_limit' => $articlesLimit, + 'show_title' => $showTitle, + 'status' => $status, + 'parent_id' => $parentId, + 'start' => $start, + 'category_id' => $categoryId, + ], [ + 'id' => $pageId, + ]); + } + + if ($start === 1) { + $this->db->update('pp_pages', ['start' => 0], ['id[!]' => $pageId]); + $this->db->update('pp_pages', ['start' => 1], ['id' => $pageId]); + } + + $this->db->delete('pp_layouts_pages', ['page_id' => $pageId]); + if ($layoutId > 0) { + $this->db->insert('pp_layouts_pages', [ + 'layout_id' => $layoutId, + 'page_id' => $pageId, + ]); + } + + $this->saveTranslations($pageId, $pageType, $data); + $this->updateSubpagesMenuId($pageId, $menuId); + + \S::htacces(); + \S::delete_dir('../temp/'); + + return $pageId; + } + + public function generateSeoLink(string $title, int $pageId = 0, int $articleId = 0, int $categoryId = 0): string + { + $base = trim((string)\S::seo($title)); + if ($base === '') { + return ''; + } + + $candidate = $base; + $suffix = 0; + + while ($this->isSeoLinkUsed('pp_pages_langs', 'page_id', $candidate, $pageId) + || $this->isSeoLinkUsed('pp_articles_langs', 'article_id', $candidate, $articleId) + || $this->isSeoLinkUsed('pp_shop_categories_langs', 'category_id', $candidate, $categoryId)) { + $suffix++; + $candidate = $base . '-' . $suffix; + } + + return $candidate; + } + + public function pageUrlPreview(int $pageId, string $langId, string $title, string $seoLink, string $defaultLanguageId): string + { + $url = trim($seoLink) !== '' + ? '/' . ltrim($seoLink, '/') + : '/s-' . $pageId . '-' . \S::seo($title); + + if ($langId !== '' && $langId !== $defaultLanguageId && $url !== '#') { + $url = '/' . $langId . $url; + } + + return $url; + } + + public function toggleCookieValue(string $cookieName, int $itemId): void + { + if ($cookieName === '' || $itemId <= 0) { + return; + } + + $state = []; + if (!empty($_COOKIE[$cookieName])) { + $decoded = @unserialize((string)$_COOKIE[$cookieName], ['allowed_classes' => false]); + if (is_array($decoded)) { + $state = $decoded; + } + } + + $state[$itemId] = empty($state[$itemId]) ? 1 : 0; + setcookie($cookieName, serialize($state), time() + 3600 * 24 * 365); + } + + public function pageTitle(int $pageId): string + { + if ($pageId <= 0) { + return ''; + } + + $rows = $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($rows) || !isset($rows[0])) { + return ''; + } + + return (string)$rows[0]; + } + + /** + * @return array> + */ + public function pageLanguages(int $pageId): array + { + if ($pageId <= 0) { + return []; + } + + $rows = $this->db->select('pp_pages_langs', '*', [ + 'AND' => [ + 'page_id' => $pageId, + 'title[!]' => null, + ], + ]); + + return is_array($rows) ? $rows : []; + } + + /** + * @return array + */ + private function defaultPage(): array + { + return [ + 'id' => 0, + 'menu_id' => 0, + 'page_type' => 0, + 'sort_type' => 0, + 'articles_limit' => 2, + 'show_title' => 1, + 'status' => 1, + 'start' => 0, + 'parent_id' => null, + 'category_id' => null, + 'layout_id' => 0, + 'languages' => [], + ]; + } + + private function saveTranslations(int $pageId, int $pageType, array $data): void + { + $titles = is_array($data['title'] ?? null) ? $data['title'] : []; + $seoLinks = is_array($data['seo_link'] ?? null) ? $data['seo_link'] : []; + $metaTitles = is_array($data['meta_title'] ?? null) ? $data['meta_title'] : []; + $metaDescriptions = is_array($data['meta_description'] ?? null) ? $data['meta_description'] : []; + $metaKeywords = is_array($data['meta_keywords'] ?? null) ? $data['meta_keywords'] : []; + $noindexValues = is_array($data['noindex'] ?? null) ? $data['noindex'] : []; + $pageTitles = is_array($data['page_title'] ?? null) ? $data['page_title'] : []; + $links = is_array($data['link'] ?? null) ? $data['link'] : []; + $canonicals = is_array($data['canonical'] ?? null) ? $data['canonical'] : []; + + foreach ($titles as $langId => $title) { + $langId = (string)$langId; + if ($langId === '') { + continue; + } + + $row = [ + 'lang_id' => $langId, + 'title' => $this->nullIfEmpty($title), + 'meta_description' => $this->nullIfEmpty($metaDescriptions[$langId] ?? null), + 'meta_keywords' => $this->nullIfEmpty($metaKeywords[$langId] ?? null), + 'meta_title' => $this->nullIfEmpty($metaTitles[$langId] ?? null), + 'seo_link' => $this->nullIfEmpty(\S::seo((string)($seoLinks[$langId] ?? ''))), + 'noindex' => (int)($noindexValues[$langId] ?? 0), + 'page_title' => $this->nullIfEmpty($pageTitles[$langId] ?? null), + 'link' => $pageType === 3 ? $this->nullIfEmpty($links[$langId] ?? null) : null, + 'canonical' => $this->nullIfEmpty($canonicals[$langId] ?? null), + ]; + + $translationId = (int)$this->db->get('pp_pages_langs', 'id', [ + 'AND' => [ + 'page_id' => $pageId, + 'lang_id' => $langId, + ], + ]); + + if ($translationId > 0) { + $this->db->update('pp_pages_langs', $row, ['id' => $translationId]); + } else { + $row['page_id'] = $pageId; + $this->db->insert('pp_pages_langs', $row); + } + } + } + + private function updateSubpagesMenuId(int $parentId, int $menuId): void + { + if ($parentId <= 0 || $menuId <= 0) { + return; + } + + $this->db->update('pp_pages', ['menu_id' => $menuId], ['parent_id' => $parentId]); + + $children = $this->db->select('pp_pages', ['id'], ['parent_id' => $parentId]); + if (!is_array($children)) { + return; + } + + foreach ($children as $row) { + $childId = (int)($row['id'] ?? 0); + if ($childId > 0) { + $this->updateSubpagesMenuId($childId, $menuId); + } + } + } + + private function isSeoLinkUsed(string $table, string $idColumn, string $seoLink, int $exceptId): bool + { + $where = [ + 'seo_link' => $seoLink, + ]; + + if ($exceptId > 0) { + $where[$idColumn . '[!]'] = $exceptId; + } + + return (int)$this->db->count($table, ['AND' => $where]) > 0; + } + + private function maxPageOrder(): int + { + $max = $this->db->max('pp_pages', 'o'); + return $max ? (int)$max : 0; + } + + private function toSwitchValue($value): int + { + if ($value === 'on' || $value === '1' || $value === 1 || $value === true) { + return 1; + } + + return 0; + } + + private function normalizeNullableInt($value): ?int + { + if ($value === null || $value === '' || (int)$value === 0) { + return null; + } + + return (int)$value; + } + + private function nullIfEmpty($value): ?string + { + $value = trim((string)$value); + return $value === '' ? null : $value; + } +} diff --git a/autoload/admin/Controllers/ArticlesArchiveController.php b/autoload/admin/Controllers/ArticlesArchiveController.php index cfd0a12..9205d00 100644 --- a/autoload/admin/Controllers/ArticlesArchiveController.php +++ b/autoload/admin/Controllers/ArticlesArchiveController.php @@ -48,13 +48,13 @@ class ArticlesArchiveController $rows[] = [ 'lp' => $lp++ . '.', - 'title' => '' . htmlspecialchars($title, ENT_QUOTES, 'UTF-8') . '', + 'title' => '' . htmlspecialchars($title, ENT_QUOTES, 'UTF-8') . '', 'date_add' => !empty($item['date_add']) ? date('Y-m-d H:i', strtotime((string)$item['date_add'])) : '-', 'date_modify' => !empty($item['date_modify']) ? date('Y-m-d H:i', strtotime((string)$item['date_modify'])) : '-', '_actions' => [ [ 'label' => 'Przywroc', - 'url' => '/admin/articles_archive/article_restore/id=' . $id, + 'url' => '/admin/articles_archive/restore/id=' . $id, 'class' => 'btn btn-xs btn-success', 'confirm' => 'Na pewno chcesz przywrocic wybrany artykul?', 'confirm_ok' => 'Przywroc', @@ -62,7 +62,7 @@ class ArticlesArchiveController ], [ 'label' => 'Usun', - 'url' => '/admin/articles_archive/article_delete/id=' . $id, + 'url' => '/admin/articles_archive/delete/id=' . $id, 'class' => 'btn btn-xs btn-danger', 'confirm' => 'Na pewno chcesz trwale usunac wybrany artykul?', 'confirm_ok' => 'Usun', @@ -101,7 +101,7 @@ class ArticlesArchiveController ]), $listRequest['perPageOptions'], $sortableColumns, - '/admin/articles_archive/view_list/', + '/admin/articles_archive/list/', 'Brak danych w tabeli.' ); @@ -121,7 +121,7 @@ class ArticlesArchiveController \S::alert('Artykul zostal przywrocony.'); } - header('Location: /admin/articles_archive/view_list/'); + header('Location: /admin/articles_archive/list/'); exit; } @@ -136,7 +136,7 @@ class ArticlesArchiveController \S::alert('Artykul zostal trwale usuniety.'); } - header('Location: /admin/articles_archive/view_list/'); + header('Location: /admin/articles_archive/list/'); exit; } diff --git a/autoload/admin/Controllers/ArticlesController.php b/autoload/admin/Controllers/ArticlesController.php index d8ecf6e..b9bccf2 100644 --- a/autoload/admin/Controllers/ArticlesController.php +++ b/autoload/admin/Controllers/ArticlesController.php @@ -4,6 +4,7 @@ namespace admin\Controllers; use Domain\Article\ArticleRepository; use Domain\Languages\LanguagesRepository; use Domain\Layouts\LayoutsRepository; +use Domain\Pages\PagesRepository; use admin\ViewModels\Forms\FormAction; use admin\ViewModels\Forms\FormEditViewModel; use admin\ViewModels\Forms\FormField; @@ -14,16 +15,19 @@ class ArticlesController private ArticleRepository $repository; private LanguagesRepository $languagesRepository; private LayoutsRepository $layoutsRepository; + private PagesRepository $pagesRepository; public function __construct( ArticleRepository $repository, LanguagesRepository $languagesRepository, - LayoutsRepository $layoutsRepository + LayoutsRepository $layoutsRepository, + PagesRepository $pagesRepository ) { $this->repository = $repository; $this->languagesRepository = $languagesRepository; $this->layoutsRepository = $layoutsRepository; + $this->pagesRepository = $pagesRepository; } /** @@ -83,7 +87,7 @@ class ArticlesController $rows[] = [ 'lp' => $lp++ . '.', - 'title' => '' . htmlspecialchars($title, ENT_QUOTES, 'UTF-8') . '' + 'title' => '' . htmlspecialchars($title, ENT_QUOTES, 'UTF-8') . '' . '' . htmlspecialchars($pages, ENT_QUOTES, 'UTF-8') . '', 'status' => ((int)$item['status'] === 1) ? 'tak' : 'nie', 'date_add' => !empty($item['date_add']) ? date('Y-m-d H:i', strtotime((string)$item['date_add'])) : '-', @@ -92,12 +96,12 @@ class ArticlesController '_actions' => [ [ 'label' => 'Edytuj', - 'url' => '/admin/articles/article_edit/id=' . $id, + 'url' => '/admin/articles/edit/id=' . $id, 'class' => 'btn btn-xs btn-primary', ], [ 'label' => 'Usun', - 'url' => '/admin/articles/article_delete/id=' . $id, + 'url' => '/admin/articles/delete/id=' . $id, 'class' => 'btn btn-xs btn-danger', 'confirm' => 'Na pewno chcesz usunac wybrany element?', ], @@ -136,9 +140,9 @@ class ArticlesController ]), $listRequest['perPageOptions'], $sortableColumns, - '/admin/articles/view_list/', + '/admin/articles/list/', 'Brak danych w tabeli.', - '/admin/articles/article_edit/', + '/admin/articles/edit/', 'Dodaj artykul' ); @@ -259,7 +263,7 @@ class ArticlesController \S::alert('Artykul zostal przeniesiony do archiwum.'); } - header('Location: /admin/articles/view_list/'); + header('Location: /admin/articles/list/'); exit; } @@ -280,7 +284,7 @@ class ArticlesController $article = $this->repository->find((int)\S::get('id')) ?: ['id' => 0, 'languages' => [], 'images' => [], 'files' => [], 'pages' => []]; $languages = $this->languagesRepository->languagesList(); - $menus = \admin\factory\Pages::menus_list(); + $menus = $this->pagesRepository->menusList(); $layouts = $this->layoutsRepository->listAll(); $viewModel = $this->buildFormViewModel($article, $languages, $menus, $layouts); @@ -400,8 +404,8 @@ class ArticlesController ]; $actions = [ - FormAction::save('/admin/articles/article_save/' . ($articleId > 0 ? 'id=' . $articleId : ''), '/admin/articles/view_list/'), - FormAction::cancel('/admin/articles/view_list/'), + FormAction::save('/admin/articles/save/' . ($articleId > 0 ? 'id=' . $articleId : ''), '/admin/articles/list/'), + FormAction::cancel('/admin/articles/list/'), ]; return new FormEditViewModel( @@ -412,8 +416,8 @@ class ArticlesController $tabs, $actions, 'POST', - '/admin/articles/article_save/' . ($articleId > 0 ? 'id=' . $articleId : ''), - '/admin/articles/view_list/', + '/admin/articles/save/' . ($articleId > 0 ? 'id=' . $articleId : ''), + '/admin/articles/list/', true, ['id' => $articleId], $languages @@ -430,7 +434,7 @@ class ArticlesController $menuId = (int)($menu['id'] ?? 0); $menuName = $this->escapeHtml((string)($menu['name'] ?? '')); $menuStatus = (int)($menu['status'] ?? 0); - $menuPages = \admin\factory\Pages::menu_pages($menuId); + $menuPages = $this->pagesRepository->menuPages($menuId); $html .= '