diff --git a/AGENTS.md b/AGENTS.md index 3c92d26..c81696f 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -6,10 +6,12 @@ Gdy użytkownik napisze `KONIEC PRACY`, wykonaj kolejno: 1. Przeprowadzenie testów. 2. Aktualizacja dokumentacji technicznej, jeśli zmiany tego wymagają: - - `DATABASE_STRUCTURE.md` - - `PROJECT_STRUCTURE.md` - - `REFACTORING_PLAN.md` - - `TESTING.md` + - `docs/DATABASE_STRUCTURE.md` + - `docs/PROJECT_STRUCTURE.md` + - `docs/REFACTORING_PLAN.md` + - `docs/FORM_EDIT_SYSTEM.md` + - `docs/CHANGELOG.md` + - `docs/TESTING.md` 3. Przygotowanie aktualizacji (ZIP, plik z usuwanymi plikami, plik SQL jeśli wymagany). 4. Commit. 5. Push. @@ -18,10 +20,11 @@ Gdy użytkownik napisze `KONIEC PRACY`, wykonaj kolejno: Przed rozpoczęciem implementacji sprawdź aktualną zawartość: -- `DATABASE_STRUCTURE.md` -- `PROJECT_STRUCTURE.md` -- `REFACTORING_PLAN.md` -- `TESTING.md` +- `docs/DATABASE_STRUCTURE.md` +- `docs/PROJECT_STRUCTURE.md` +- `docs/REFACTORING_PLAN.md` +- `docs/CHANGELOG.md` +- `docs/TESTING.md` To ma pomóc zachować spójność zmian i dokumentacji. diff --git a/PROJECT_STRUCTURE.md b/PROJECT_STRUCTURE.md deleted file mode 100644 index 7df694b..0000000 --- a/PROJECT_STRUCTURE.md +++ /dev/null @@ -1,505 +0,0 @@ -# Struktura Projektu shopPRO - -Dokumentacja struktury projektu shopPRO do szybkiego odniesienia. - -## System Cache (Redis) - -### Klasy odpowiedzialne za cache - -#### RedisConnection -- **Plik:** `autoload/class.RedisConnection.php` -- **Opis:** Singleton zarządzający połączeniem z Redis -- **Metody:** - - `getInstance()` - pobiera instancję połączenia - - `getConnection()` - zwraca obiekt Redis - -#### CacheHandler -- **Plik:** `autoload/class.CacheHandler.php` -- **Opis:** Handler do obsługi cache Redis -- **Metody:** - - `get($key)` - pobiera wartość z cache - - `set($key, $value, $ttl = 86400)` - zapisuje wartość do cache - - `exists($key)` - sprawdza czy klucz istnieje - - `delete($key)` - usuwa pojedynczy klucz - - `deletePattern($pattern)` - usuwa klucze według wzorca - -#### Klasa S (pomocnicza) -- **Plik:** `autoload/class.S.php` -- **Metody cache:** - - `clear_redis_cache()` - czyści cały cache Redis (flushAll) - - `clear_product_cache(int $product_id)` - czyści cache konkretnego produktu - -### Wzorce kluczy Redis - -#### Produkty -``` -shop\product:{product_id}:{lang_id}:{permutation_hash} -``` -- Przechowuje zserializowany obiekt produktu -- TTL: 24 godziny (86400 sekund) -- Klasa: `shop\Product::getFromCache()` - `autoload/shop/class.Product.php:121` - -#### Opcje ilościowe produktu -``` -\shop\Product::get_product_permutation_quantity_options:{product_id}:{permutation} -``` -- Przechowuje informacje o ilości i komunikatach magazynowych -- Klasa: `shop\Product::get_product_permutation_quantity_options()` - `autoload/shop/class.Product.php:549` - -#### Zestawy produktów -``` -\shop\Product::product_sets_when_add_to_basket:{product_id} -``` -- Przechowuje produkty często kupowane razem -- Klasa: `shop\Product::product_sets_when_add_to_basket()` - `autoload/shop/class.Product.php:316` - -## Integracje z systemami zewnętrznymi (CRON) - -### Plik: `cron.php` - -#### Apilo -- **Aktualizacja pojedynczego produktu:** synchronizacja cen i stanow - - Czestotliwosc: Co 10 minut -- **Synchronizacja cennika:** masowa aktualizacja cen z Apilo - - Czestotliwosc: Co 1 godzine - -**Uwaga:** Integracje Sellasist i Baselinker zostaly usuniete w ver. 0.263. - -## Panel Administratora - -### Routing -- Główny katalog: `admin/` -- Template główny: `admin/templates/site/main-layout.php` -- Kontrolery (nowe): `autoload/admin/Controllers/` -- Kontrolery legacy (fallback): `autoload/admin/controls/` - -### Przycisk "Wyczyść cache" -- **Lokalizacja UI:** `admin/templates/site/main-layout.php:172` -- **JavaScript:** `admin/templates/site/main-layout.php:235-274` -- **Endpoint AJAX:** `/admin/settings/clear_cache_ajax/` -- **Kontroler:** `autoload/admin/Controllers/SettingsController.php:43-60` -- **Działanie:** - 1. Pokazuje spinner "Czyszczę cache..." - 2. Czyści katalogi: `temp/`, `thumbs/` - 3. Wykonuje `flushAll()` na Redis - 4. Pokazuje "Cache wyczyszczony!" przez 2 sekundy - 5. Przywraca stan początkowy - -## Struktura katalogów - -``` -shopPRO/ -├── admin/ # Panel administratora -│ ├── templates/ # Szablony widoków -│ └── layout/ # Zasoby CSS/JS/ikony -├── autoload/ # Klasy autoloadowane -│ ├── admin/ # Klasy panelu admin -│ │ ├── controls/ # Kontrolery -│ │ └── factory/ # Fabryki/helpery -│ ├── front/ # Klasy frontendu -│ │ └── factory/ # Fabryki/helpery -│ └── shop/ # Klasy sklepu -├── libraries/ # Biblioteki zewnętrzne -├── temp/ # Cache tymczasowy -├── thumbs/ # Miniatury zdjęć -└── cron.php # Zadania CRON - -``` - -## Baza danych - -### Główne tabele produktów -- `pp_shop_products` - produkty główne -- `pp_shop_products_langs` - tłumaczenia produktów -- `pp_shop_products_images` - zdjęcia produktów -- `pp_shop_products_categories` - kategorie produktów -- `pp_shop_products_custom_fields` - pola własne produktów - -### Tabele integracji -- Kolumny w `pp_shop_products`: - - `apilo_product_id`, `apilo_product_name`, `apilo_get_data_date` -- Tabele ustawien: - - `pp_shop_apilo_settings` (key-value) - - `pp_shop_shoppro_settings` (key-value) - -## Konfiguracja - -### Redis -- Konfiguracja: `config.php` (zmienna `$config['redis']`) -- Parametry: host, port, password - -### Autoload -- Funkcja: `__autoload_my_classes()` w `cron.php:6` -- Wzorzec: `autoload/{namespace}/class.{ClassName}.php` - -## Klasy pomocnicze - -### \S (autoload/class.S.php) -Główna klasa helper z metodami: -- `seo($val)` - generowanie URL SEO -- `normalize_decimal($val, $precision)` - normalizacja liczb -- `send_email()` - wysyłanie emaili -- `delete_dir($dir)` - usuwanie katalogów -- `htacces()` - generowanie .htaccess i sitemap.xml - -### Medoo -- Plik: `libraries/medoo/medoo.php` -- Zmienna: `$mdb` -- ORM do operacji na bazie danych - -## Najważniejsze wzorce - -### Namespace'y -- `\admin\Controllers\` - nowe kontrolery panelu admin (DI) -- `\admin\controls\` - kontrolery legacy (fallback) -- `\Domain\` - repozytoria/logika domenowa -- `\admin\factory\` - helpery/fabryki admin -- `\front\factory\` - helpery/fabryki frontend -- `\shop\` - klasy sklepu (Product, Order, itp.) - -### Cachowanie produktów -```php -// Pobranie produktu z cache -$product = \shop\Product::getFromCache($product_id, $lang_id, $permutation_hash); - -// Czyszczenie cache produktu -\S::clear_product_cache($product_id); - -// Czyszczenie całego cache -\S::clear_redis_cache(); -``` - -## Refaktoryzacja do Domain-Driven Architecture - -### Nowa struktura (w trakcie migracji) -``` -autoload/ -├── Domain/ # Nowa warstwa biznesowa (namespace \Domain\) -│ ├── Product/ -│ │ └── ProductRepository.php # getQuantity, getPrice, getName, find, updateQuantity, archive, unarchive -│ ├── Banner/ -│ │ └── BannerRepository.php # find, delete, save -│ ├── Settings/ -│ │ └── SettingsRepository.php # saveSettings, getSettings (fasada → factory) -│ └── Cache/ -│ └── CacheRepository.php # clearCache (dirs + Redis) -├── admin/ -│ ├── Controllers/ # Nowe kontrolery (namespace \admin\Controllers\) -│ │ ├── BannerController.php # DI, instancyjny -│ │ ├── SettingsController.php # DI, instancyjny (clearCache, save, view) -│ │ ├── ProductArchiveController.php # DI, instancyjny (list, unarchive) -│ │ └── UsersController.php # DI, instancyjny (view_list, user_edit, user_save, user_delete, login_form, twofa) -│ ├── class.Site.php # Router: nowy kontroler → fallback stary -│ ├── controls/ # Stare kontrolery (niezależny fallback) -│ ├── factory/ # Stare helpery (niezależny fallback) -│ └── view/ # Widoki (statyczne - bez zmian) -├── shop/ # Legacy - fasady do Domain -└── front/factory/ # Legacy - stopniowo migrowane -``` - -#### Aktualny stan migracji (uzupełnienie) -- Dodane repozytorium: `Domain\Dictionaries\DictionariesRepository` -- Dodane kontrolery DI: `admin\Controllers\DictionariesController`, `admin\Controllers\FilemanagerController`, `admin\Controllers\UsersController` -- Dodane repozytorium: `Domain\User\UserRepository` -- `Domain\Settings\SettingsRepository` działa bezpośrednio na DB (bez delegacji do `admin\factory\Settings`) - -### Routing admin (admin\Site::route()) -1. Sprawdź mapę `$newControllers` → utwórz instancję z DI → wywołaj -2. Jeśli nowy kontroler nie istnieje (`class_exists()` = false) → fallback na `admin\controls\` -3. Stary kontroler jest NIEZALEŻNY od nowych klas (bezpieczny fallback) - -### Dependency Injection -Nowe klasy używają **Dependency Injection** zamiast `global` variables: -```php -// STARE -global $mdb; -$quantity = $mdb->get('pp_shop_products', 'quantity', ['id' => $id]); - -// NOWE -$repository = new \Domain\Product\ProductRepository($mdb); -$quantity = $repository->getQuantity($id); -``` - -## Testowanie (tylko dla deweloperów) - -**UWAGA:** Pliki testów NIE są częścią aktualizacji dla klientów! - -### Narzędzia -- **PHPUnit 9.6.34** - framework testowy -- **test.bat** - uruchamianie testów -- **composer.json** - autoloading PSR-4 - -### Struktura -``` -tests/ -├── Unit/ -│ ├── Domain/ -│ │ ├── Product/ProductRepositoryTest.php # 11 testów -│ │ ├── Banner/BannerRepositoryTest.php # 4 testy -│ │ ├── Settings/SettingsRepositoryTest.php # 3 testy -│ │ └── Cache/CacheRepositoryTest.php # 4 testy -│ └── admin/ -│ └── Controllers/ -│ ├── SettingsControllerTest.php # 7 testów -│ └── ProductArchiveControllerTest.php # 6 testów -└── Integration/ -``` -Aktualnie w suite są też testy modułów `Dictionaries`, `Articles` i `Users` (repozytoria + kontrolery DI). -**Łącznie: 119 tests, 256 assertions** - -## Ostatnie modyfikacje - -### 2026-02-10: Porządki po migracji i release 0.252 (ver. 0.252) -- **UPDATE:** `ProductArchiveController` i szablony listy archiwum przepięte na nową tabelę (`components/table-list`) -- **UPDATE:** CSS/JS dla list wydzielone do osobnych widoków `*-custom-script.php` (banery i archiwum produktów) -- **UPDATE:** dodano `admin\Controllers\FilemanagerController` i przepięto filemanager na nowy routing -- **FIX:** naprawiono błąd `Invalid Key` w filemanagerze -- **CLEANUP:** usunięto legacy pliki: `autoload/admin/controls/class.Archive.php`, `autoload/admin/controls/class.Filemanager.php`, `autoload/admin/view/class.FileManager.php`, stare szablony `admin/templates/product_archive/*` -- **RENAME:** folder szablonów `admin/templates/product_archive/` → `admin/templates/product-archive/` -- Testy: 82 tests, 181 assertions - -### 2026-02-09: Migracja Dictionaries (ver. 0.251) -- **NEW:** `Domain\Dictionaries\DictionariesRepository` (listForAdmin, find, save, delete, allUnits) -- **NEW:** `admin\Controllers\DictionariesController` (lista + formularz na nowych komponentach) -- **UPDATE:** migracja słowników na `components/table-list` i `components/form-edit` -- **FIX:** obsługa `lang_id` jako string (`pl`, `en`) w zapisie tłumaczeń -- **CLEANUP:** usunięto legacy klasy Dictionaries (`admin\controls`, `admin\factory`, `front\factory`) -- Testy: 82 tests, 181 assertions - -### 2026-02-09: Refaktoryzacja Settings (ver. 0.250) -- **UPDATE:** `Domain\Settings\SettingsRepository` ma bezpośredni dostęp do DB (bez delegacji do `admin\factory\Settings`) -- **UPDATE:** przepięto użycia `admin\factory\Settings` na `Domain\Settings\SettingsRepository` -- **CLEANUP:** usunięto legacy klasy Settings (`factory`, `controls`, `view`) -- Testy: 82 tests, 181 assertions - -### 2026-02-07: Usuniecie legacy kontrolera Articles (ver. 0.246) -- **UPDATE:** usunieto `autoload/admin/controls/class.Articles.php` -- **UPDATE:** `admin\Controllers\ArticlesController::galleryOrderSave()` uzywa `Domain\Article\ArticleRepository::saveGalleryOrder()` -- **UPDATE:** `Domain\Article\ArticleRepository` - dodano `saveGalleryOrder(int $articleId, string $order): bool` -- **UPDATE:** `admin\factory\Articles::gallery_order_save()` deleguje do `ArticleRepository::saveGalleryOrder()` (backward compatibility) -- **FIX:** sortowanie list admin po reloadzie - `RewriteRule` dla `/admin/...` ma `QSA` -- **FIX:** generator `\S::htacces()` komentuje dyrektywy `AddHandler|SetHandler|ForceType` (kompatybilnosc hostingu) -- **UPDATE:** zrodlo generatora `libraries/htaccess.conf` dostosowane do powyzszych zmian -- **WAZNE (deploy):** w paczce aktualizacji dodac `ver_X.XXX_files.txt` z wpisem: - `F: ../autoload/admin/controls/class.Articles.php` -- Testy: 65 tests, 131 assertions - -### 2026-02-06: Migracja Articles::article_delete do DI (ver. 0.245) -- **UPDATE:** `Domain\Article\ArticleRepository` - dodano `archive()` (ustawia status = -1) -- **UPDATE:** `admin\Controllers\ArticlesController` - nowa akcja `delete()` z DI -- **UPDATE:** Router `admin\Site` - dodano `'article_delete' => 'delete'` do `$actionMap` -- **UPDATE:** `admin\factory\Articles::articles_set_archive()` deleguje do `ArticleRepository::archive()` -- **UPDATE:** `admin\controls\Articles::article_delete()` oznaczone `@deprecated` -- Testy: 59 tests, 123 assertions - -### 2026-02-06: Migracja Articles::article_save do DI (ver. 0.244) -- **UPDATE:** `Domain\Article\ArticleRepository` - dodano `save()` + prywatne helpery (`buildArticleRow`, `buildLangRow`, `saveTranslations`, `savePages`, `assignTempFiles`, `assignTempImages`, `deleteMarkedFiles`, `deleteMarkedImages`, `maxPageOrder`) -- **UPDATE:** `admin\Controllers\ArticlesController` - nowa akcja `save()` z DI -- **UPDATE:** Router `admin\Site` - dodano `'article_save' => 'save'` do `$actionMap` -- **UPDATE:** `admin\factory\Articles::article_save()` deleguje do `ArticleRepository::save()` (backward compatibility) -- **UPDATE:** `admin\controls\Articles::article_save()` oznaczone `@deprecated` -- **UPDATE:** `tests/bootstrap.php` - dodano stub `S::seo()` -- Testy: 57 tests, 119 assertions - -### 2026-02-06: Articles cleanup moved to repository (ver. 0.243) -- **UPDATE:** `Domain\Article\ArticleRepository` - added `deleteNonassignedImages()` and `deleteNonassignedFiles()` -- **UPDATE:** `admin\Controllers\ArticlesController::edit()` uses repository cleanup methods -- **UPDATE:** `admin\factory\Articles::delete_nonassigned_images()` and `delete_nonassigned_files()` delegate to repository (backward compatibility) -- Testy: 50 tests, 95 assertions - -### 2026-02-06: Migracja Articles::article_edit do DI (ver. 0.242) -- **NOWE:** `Domain\Article\ArticleRepository` - repozytorium artykułów (`find()`) -- **UPDATE:** `admin\Controllers\ArticlesController` - konstruktor DI + `edit()` używa repozytorium -- **UPDATE:** Router `admin\Site` - factory dla `ArticlesController` z `ArticleRepository` -- **UPDATE:** `admin\factory\Articles::article_details()` deleguje do `Domain\Article\ArticleRepository` -- **UPDATE:** Stare kontrolery `admin\controls\Articles|Banners|Settings` - metody przejęte przez nowe kontrolery oznaczone `@deprecated` -- Testy: 48 testów, 91 asercji - -### 2026-02-06: Migracja ProductArchive (ver. 0.241) -- **NOWE:** `admin\Controllers\ProductArchiveController` - kontroler archiwum produktów z DI -- **NOWE:** `ProductRepository::archive()`, `unarchive()` - operacje archiwizacji w repozytorium -- **RENAME:** `admin/templates/archive/` → `admin/templates/product_archive/` -- **FIX:** SQL w `ajax_products_list_archive()` - puste wyszukiwanie generowało `name|ean|sku LIKE '%%'` (NULL bitwise OR filtrował wyniki) -- **FIX:** Brakujący `archive = 1` w branchu bez wyszukiwania -- **CLEANUP:** Usunięto zbędny JS z szablonu archiwum (apilo, baselinker, duplikowanie, edycja cen) -- Stary kontroler `admin\controls\Archive` zachowany jako fallback -- Testy: 50 tests, 95 assertions (+10 nowych) - -### 2026-02-05: Migracja Settings + Cache (ver. 0.240) -- **NOWE:** `Domain\Settings\SettingsRepository` - repozytorium ustawień (fasada → factory) -- **NOWE:** `Domain\Cache\CacheRepository` - repozytorium cache (dirs + Redis) -- **NOWE:** `admin\Controllers\SettingsController` - kontroler z DI (clearCache, save, view) -- **FIX:** Brakujący `id="content"` w main-layout.php (komunikaty grid.js) -- **FIX:** `persist_edit = true` w settings.php (komunikat po zapisie) -- Stary kontroler `admin\controls\Settings` zachowany jako fallback -- Testy: 29 testów, 60 asercji (+14 nowych) -- Bootstrap testów: stuby klas systemowych (S, RedisConnection, Redis, CacheHandler) - -### 2026-02-05: Migracja Banner + Product (ver. 0.239) -- **NOWE:** `Domain\Banner\BannerRepository` - repozytorium banerów (find, delete, save) -- **NOWE:** `admin\Controllers\BannerController` - pierwszy kontroler z DI -- **NOWE:** Router z mapą `$newControllers` + fallback na stare kontrolery -- **NOWE:** Autoloader PSR-4 fallback w 9 entry pointach -- Zmigrowano: `get_product_price()` → `ProductRepository::getPrice()` -- Zmigrowano: `get_product_name()` → `ProductRepository::getName()` -- Testy: 15 testów, 31 asercji - -### 2025-02-05: Refaktoryzacja - Product Repository (ver. 0.238) -- **NOWE:** `Domain\Product\ProductRepository` - pierwsza klasa w nowej architekturze -- **NOWE:** Dependency Injection zamiast `global $mdb` -- **NOWE:** Testy jednostkowe (5 testów, 100% pokrycie) -- Zmigrowano: `get_product_quantity()` → `ProductRepository::getQuantity()` -- Kompatybilność: Stara klasa `shop\Product` działa jako fasada - -### 2025-02-05: System cache produktów (ver. 0.237) -- Automatyczne czyszczenie cache produktu po aktualizacji przez CRON -- AJAX dla przycisku "Wyczyść cache" w panelu admin -- Metody `delete()` i `deletePattern()` w CacheHandler -- Metoda `clear_product_cache()` w klasie S - ---- -*Dokument aktualizowany: 2026-02-12* - - -### 2026-02-12: Migracja Users (/admin/users) (ver. 0.253) -- **NOWE:** `Domain\User\UserRepository` - repozytorium uzytkownikow (CRUD, check_login, logon, details, 2FA) -- **NOWE:** `admin\Controllers\UsersController` - kontroler DI dla akcji `view_list`, `user_edit`, `user_save`, `user_delete`, `login_form`, `twofa` -- **UPDATE:** `admin\Site` - dodany factory wpis dla modulu `Users` w mapie nowych kontrolerow -- **UPDATE:** `admin\factory\Users` - fasada deleguje logike do `Domain\User\UserRepository` -- **UPDATE:** `admin/ajax/users.php` - `check_login` korzysta bezposrednio z `UserRepository` -- **CLEANUP:** usuniety `autoload/admin/controls/class.Users.php` (brak fallback - nowy kontroler obsluguje wszystkie akcje) -- Testy: 119 tests, 256 assertions - ---- -*Dokument aktualizowany: 2026-02-12* -- **UPDATE:** widoki Users przeniesione z `grid/gridEdit` na `components/table-list` i `components/form-edit` - -## Aktualizacja 2026-02-12 (finalizacja Users) -- Modu� users dzia�a na `Domain\\User\\UserRepository` + `admin\\Controllers\\UsersController`. -- Usuni�to legacy klasy: `autoload/admin/controls/class.Users.php`, `autoload/admin/factory/class.Users.php`, `autoload/admin/view/class.Users.php`. -- Walidacja: przy w��czonym 2FA pole `twofa_email` jest wymagane. -- Widoki users przeniesione na `components/table-list` i `components/form-edit`. -- **NOWE:** `Domain\\Languages\\LanguagesRepository` - repozytorium jezykow i tlumaczen (lista, zapis, usuwanie, max_order) -- **NOWE:** `admin\\Controllers\\LanguagesController` - kontroler DI (`list/view_list`, `language_*`, `translation_*`) -- **UPDATE:** modul Languages przepiety z `grid/gridEdit` na `components/table-list` i `components/form-edit` -- **CLEANUP:** usuniete legacy klasy `autoload/admin/controls/class.Languages.php`, `autoload/admin/view/class.Languages.php` -- Testy: 130 tests, 301 assertions - -## Aktualizacja 2026-02-12 (Languages final) -- Dodano `Domain\\Languages\\LanguagesRepository` oraz `admin\\Controllers\\LanguagesController`. -- Modul `/admin/languages/` (jezyki + tlumaczenia) dziala na nowym routingu DI. -- Widoki jezykow przepiete na `components/table-list` i `components/form-edit`. -- Usunieto legacy: `autoload/admin/controls/class.Languages.php`, `autoload/admin/view/class.Languages.php`. - -## Aktualizacja 2026-02-12 (ver. 0.255) -- UPDATE: admin/Controllers/SettingsController, BannerController, DictionariesController, ArticlesController pobieraja listy jezykow przez Domain/Languages/LanguagesRepository (DI), bez zaleznosci od admin/factory/Languages. -- 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 `edit/save/delete`. -- UPDATE: `admin\factory\Scontainers` dziala jako fasada do `Domain\Scontainers\ScontainersRepository`. -- UPDATE: `front\factory\Scontainers` korzysta z `Domain\Scontainers\ScontainersRepository`. -- CLEANUP: usuniete legacy klasy `autoload/admin/controls/class.Scontainers.php`, `autoload/admin/view/class.Scontainers.php`. -- Testy: 158 tests, 397 assertions. - -## Aktualizacja 2026-02-12 (ver. 0.260) -- NOWE: `Domain\Article\ArticleRepository` rozszerzone o `listArchivedForAdmin()`, `restore()`, `deletePermanently()`. -- NOWE: `admin\Controllers\ArticlesArchiveController` (DI) dla akcji `list/view_list`, `article_restore`, `article_delete`. -- UPDATE: routing DI (`admin\Site`) rozszerzony o modul `ArticlesArchive` oraz mapowanie akcji `article_restore -> restore`. -- UPDATE: `/admin/articles_archive/view_list/` przepiete z legacy `grid` na `components/table-list`. -- CLEANUP: usuniete legacy klasy `autoload/admin/controls/class.ArticlesArchive.php`, `autoload/admin/factory/class.ArticlesArchive.php`, `autoload/admin/view/class.ArticlesArchive.php`. -- Testy: 165 tests, 424 assertions. - -### 2026-02-13: Refaktoryzacja /admin/articles (ver. 0.261) -- **UPDATE:** routing DI dla `ArticlesController` obsluguje akcje AJAX: `article_image_alt_change`, `article_file_name_change`, `article_image_delete`, `article_file_delete`. -- **UPDATE:** widok `admin/templates/articles/article-edit.php` korzysta z endpointow `/admin/articles/*` zamiast `admin/ajax.php?a=article_*`. -- **UPDATE:** lista artykulow nie korzysta juz z `admin\factory\Articles::article_pages` (etykiety stron z `Domain\Article\ArticleRepository`). -- **CLEANUP:** usuniete legacy pliki `autoload/admin/view/class.Articles.php` i `admin/ajax/articles.php`; odpiecie include w `admin/ajax.php`. -- Testy: 176 tests, 439 assertions. - -### 2026-02-13: Articles edit UX i sortowanie zalacznikow (ver. 0.261) -- **UPDATE:** `Domain\Article\ArticleRepository` - dodane `saveFilesOrder()` oraz obsluga `files_order` podczas `save()` (pierwszy zapis zachowuje kolejnosc). -- **UPDATE:** routing DI (`admin\Site::$actionMap`) rozszerzony o `files_order_save -> filesOrderSave`. -- **UPDATE:** `admin\Controllers\ArticlesController` - nowa akcja AJAX `filesOrderSave()`. -- **UPDATE:** `admin/templates/articles/article-edit-custom-script.php` - drag&drop sortowania listy zalacznikow + synchronizacja hidden input `files_order`. -- **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`. - -## Aktualizacja 2026-02-13 (Integrations refactor, ver. 0.263) -- NOWE: `Domain\Integrations\IntegrationsRepository` (settings Apilo/ShopPRO, OAuth, product linking, API fetch). -- NOWE: `admin\Controllers\IntegrationsController` (DI) dla akcji Apilo (settings, authorization, fetch lists, product CRUD) i ShopPRO (settings, product import). -- UPDATE: `admin\factory\Integrations` jako fasada delegujaca do repozytorium (tylko Apilo + ShopPRO). -- CLEANUP: **usunieto integracje Sellasist i Baselinker z calego projektu** - kontrolery, factory, szablony, referencje w cron.php, Order, ShopStatuses, ShopTransport, ShopPaymentMethod, ShopProduct, config.php, front/factory/*. -- CLEANUP: usuniete pliki: `autoload/admin/controls/class.Integrations.php`, `autoload/admin/controls/class.Baselinker.php`, `autoload/admin/factory/class.Baselinker.php`, `autoload/front/factory/class.Shop.php`, `autoload/shop/class.ShopStatus.php`, szablony sellasist/baselinker. -- Testy: **OK (212 tests, 577 assertions)**. - -## Aktualizacja 2026-02-13 (ShopPromotion refactor, ver. 0.264) -- NOWE: `Domain\Promotion\PromotionRepository` (listForAdmin, find, save, delete, categoriesTree + invalidacja cache aktywnych promocji). -- NOWE: `admin\Controllers\ShopPromotionController` (DI) dla akcji `list`, `edit`, `save`, `delete`. -- UPDATE: modul `/admin/shop_promotion/*` przepiety z legacy `grid/gridEdit` na `components/table-list` i `components/form-edit`. -- NOWE: widoki `admin/templates/shop-promotion/promotions-list.php`, `admin/templates/shop-promotion/promotion-edit.php`. -- NOWE: partiale drzewa kategorii: `admin/templates/shop-promotion/promotion-categories-selector.php`, `admin/templates/shop-promotion/promotion-categories-tree.php`. -- NOWE: `admin/templates/shop-promotion/promotion-edit-custom-script.php` (logika warunkow promocji + drzewo kategorii). -- CLEANUP: usuniete legacy klasy/pliki `autoload/admin/controls/class.ShopPromotion.php`, `autoload/admin/factory/class.ShopPromotion.php`, `admin/templates/shop-promotion/view-list.php`. -- UPDATE: menu admin wskazuje kanoniczny URL `/admin/shop_promotion/list/`. -- Testy: **OK (222 tests, 609 assertions)**. - -## Aktualizacja 2026-02-13 (ShopPromotion poprawki, ver. 0.265) -- UPDATE: dodano pole `Data od` (`date_from`) w module `/admin/shop_promotion` (repozytorium, formularz i lista). -- UPDATE: `shop\Promotion::get_active_promotions()` uwzglednia `date_from` (`NULL` lub `<= dzisiaj`) obok `date_to`. -- FIX: edycja promocji zapisuje update zamiast insert (stabilne przekazanie `id` przez hidden field + fallback `id` z URL w `save()`). -- Testy: **OK (222 tests, 614 assertions)**. - -## Aktualizacja 2026-02-13 (ShopCoupon refactor, ver. 0.266) -- NOWE: `Domain\Coupon\CouponRepository` (`listForAdmin`, `find`, `save`, `delete`, `categoriesTree`). -- NOWE: `admin\Controllers\ShopCouponController` (DI) dla akcji `list`, `edit`, `save`, `delete`. -- UPDATE: zachowana kompatybilnosc aliasow legacy akcji (`view_list`, `coupon_edit`, `coupon_save`, `coupon_delete`) w nowym kontrolerze. -- UPDATE: modul `/admin/shop_coupon/*` przepiety z legacy `grid/gridEdit` na `components/table-list` i `components/form-edit`. -- NOWE: widoki/partiale `shop-coupon/coupons-list`, `shop-coupon/coupon-edit-new`, `shop-coupon/coupon-categories-selector`, `shop-coupon/coupon-categories-tree`, `shop-coupon/coupon-edit-custom-script`. -- CLEANUP: usuniete legacy klasy/pliki `autoload/admin/controls/class.ShopCoupon.php`, `autoload/admin/factory/class.ShopCoupon.php`, `admin/templates/shop-coupon/view-list.php`, `admin/templates/shop-coupon/coupon-edit.php`. -- UPDATE: menu admin wskazuje kanoniczny URL `/admin/shop_coupon/list/`. -- FIX: ujednolicone zachowanie drzewek i styl checkboxow miedzy widokami `/admin/shop_coupon/edit/*` i `/admin/layouts/edit/*` (strzalki, focus, iCheck). -- Testy: **OK (235 tests, 682 assertions)**. diff --git a/REFACTORING_PLAN.md b/REFACTORING_PLAN.md deleted file mode 100644 index 7aa43de..0000000 --- a/REFACTORING_PLAN.md +++ /dev/null @@ -1,873 +0,0 @@ -# Plan Refaktoryzacji shopPRO - Domain-Driven Architecture - -## Cel -Stopniowe przeniesienie logiki biznesowej do architektury warstwowej: -- **Domain/** - logika biznesowa (core) -- **Admin/** - warstwa administratora -- **Frontend/** - warstwa użytkownika -- **Shared/** - współdzielone narzędzia - -## Docelowa struktura - -``` -autoload/ -├── Domain/ # Logika biznesowa (CORE) - namespace \Domain\ -│ ├── Product/ -│ │ ├── ProductRepository.php # ✅ Zmigrowane (getQuantity, getPrice, getName, find, updateQuantity, archive, unarchive) -│ │ ├── ProductService.php # Logika biznesowa (przyszłość) -│ │ └── ProductCacheService.php # Cache produktu (przyszłość) -│ ├── Banner/ -│ │ └── BannerRepository.php # ✅ Zmigrowane (find, delete, save) -│ ├── Settings/ -│ │ └── SettingsRepository.php # ✅ Zmigrowane (saveSettings, getSettings) - bezposrednio DB -│ ├── Dictionaries/ -│ │ └── DictionariesRepository.php # ✅ Zmigrowane (listForAdmin, find, save, delete, allUnits) -│ ├── Cache/ -│ │ └── CacheRepository.php # ✅ Zmigrowane (clearCache) -│ ├── Order/ -│ ├── Category/ -│ └── ... -│ -├── admin/ # Warstwa administratora (istniejący katalog!) -│ ├── Controllers/ # Nowe kontrolery - namespace \admin\Controllers\ -│ │ ├── ArticlesController.php -│ │ ├── BannerController.php -│ │ ├── DictionariesController.php -│ │ ├── FilemanagerController.php -│ │ ├── ProductArchiveController.php -│ │ └── SettingsController.php -│ ├── controls/ # Stare kontrolery (legacy fallback) -│ ├── factory/ # Stare helpery (legacy) -│ └── view/ # Widoki (statyczne - OK bez zmian) -│ -├── Frontend/ # Warstwa użytkownika (przyszłość) -│ ├── Controllers/ -│ └── Services/ -│ -├── Shared/ # Współdzielone narzędzia -│ ├── Cache/ -│ │ ├── CacheHandler.php -│ │ └── RedisConnection.php -│ └── Helpers/ -│ └── S.php -│ -└── [LEGACY] # Stare klasy (stopniowo deprecated) - ├── shop/ - ├── admin/factory/ - └── front/factory/ -``` - -### WAŻNE: Konwencja namespace → katalog (Linux case-sensitive!) -- `\Domain\` → `autoload/Domain/` (duże D - nowy katalog) -- `\admin\Controllers\` → `autoload/admin/Controllers/` (małe a - istniejący katalog) -- NIE używać `\Admin\` (duże A) bo na serwerze Linux katalog to `admin/` (małe a) - -## Zasady migracji - -### 1. Stopniowość -- Przenosimy **jedną funkcję na raz** -- Zachowujemy kompatybilność wsteczną -- Stare klasy działają jako fasady do nowych - -### 2. Dependency Injection zamiast statycznych metod -```php -// ❌ STARE - statyczne -class Product { - public static function getQuantity($id) { - global $mdb; - return $mdb->get('pp_shop_products', 'quantity', ['id' => $id]); - } -} - -// ✅ NOWE - instancje z DI -class ProductRepository { - private $db; - - public function __construct($db) { - $this->db = $db; - } - - public function getQuantity($id) { - return $this->db->get('pp_shop_products', 'quantity', ['id' => $id]); - } -} -``` - -### 3. Fasady dla kompatybilności -```php -// Stara klasa wywołuje nową -namespace shop; - -class Product { - public static function getQuantity($id) { - global $mdb; - $repo = new \Domain\Product\ProductRepository($mdb); - return $repo->getQuantity($id); - } -} -``` - -## Proces migracji funkcji - -### Krok 1: Wybór funkcji -- Wybierz prostą funkcję statyczną -- Sprawdź jej zależności -- Przeanalizuj gdzie jest używana - -### Krok 2: Stworzenie nowej struktury -- Utwórz folder `Domain/{Module}/` -- Stwórz odpowiednią klasę (Repository/Service/Entity) -- Przenieś logikę - -### Krok 3: Znalezienie użyć -```bash -grep -r "Product::getQuantity" . -``` - -### Krok 4: Aktualizacja wywołań -- Opcja A: Bezpośrednie wywołanie nowej klasy -- Opcja B: Fasada w starej klasie (zalecane na początek) - -### Krok 5: Testy -- Napisz test jednostkowy dla nowej funkcji -- Sprawdź czy stare wywołania działają - -## Status migracji - -### ✅ Zmigrowane moduły -- **Cache** (częściowo) - - ✅ CacheHandler - ma delete/deletePattern - - ✅ RedisConnection - singleton - - ✅ S::clear_product_cache() - nowa metoda - -### 🔄 Status modułów -- **Product** - - ✅ get_product_quantity() - **ZMIGROWANE** (2025-02-05) 🎉 - - Nowa klasa: `Domain\Product\ProductRepository::getQuantity()` - - Fasada w: `shop\Product::get_product_quantity()` - - Test: `tests/Unit/Domain/Product/ProductRepositoryTest.php` - - Testy: ✅ 5/5 przechodzą - - Aktualizacja: ver. 0.238 - - Użycie DI: ✅ Konstruktor przyjmuje `$db` - - ✅ get_product_price() - **ZMIGROWANE** (2026-02-05) 🎉 - - Nowa metoda: `Domain\Product\ProductRepository::getPrice()` - - Fasada w: `shop\Product::get_product_price()` - - Testy: ✅ 4 nowe testy (cena regularna, promocyjna, promo wyższa, nie znaleziono) - - Użycie: `front\factory\ShopPromotion` (linia 132) - - Aktualizacja: ver. 0.239 - - ✅ get_product_name() - **ZMIGROWANE** (2026-02-05) 🎉 - - Nowa metoda: `Domain\Product\ProductRepository::getName()` - - Fasada w: `shop\Product::get_product_name()` - - Testy: ✅ 2 nowe testy (nazwa znaleziona, nie znaleziona) - - Użycie: brak aktywnych wywołań (przygotowane na przyszłość) - - Aktualizacja: ver. 0.239 - - ✅ archive() / unarchive() - **ZMIGROWANE** (2026-02-06) 🎉 - - Nowe metody: `Domain\Product\ProductRepository::archive()`, `unarchive()` - - Nowy kontroler: `admin\Controllers\ProductArchiveController` (DI, instancyjny) - - Szablony: `admin/templates/product-archive/` (rename z `archive/`, dawniej `product_archive/`) - - Testy: ✅ 4 nowe testy repozytorium + 6 testów kontrolera - - FIX: SQL bug w `ajax_products_list_archive()` (puste wyszukiwanie + brak `archive = 1`) - - Dalsze porządki: ver. 0.252 (nowy table-list, wydzielony custom script, usunięte legacy pliki) - - Aktualizacja: ver. 0.241 / 0.252 - - [ ] is_product_on_promotion() - NASTĘPNA 👉 - -- **Banner** (DEMO pełnej migracji kontrolera) - - ✅ BannerRepository - **ZMIGROWANE** (2026-02-05) 🎉 - - Nowa klasa: `Domain\Banner\BannerRepository` (find, delete, save, saveTranslations) - - Nowy kontroler: `admin\Controllers\BannerController` (DI, instancyjny) - - Router: `admin\Site::route()` → sprawdza nowy kontroler → fallback na stary - - Testy: ✅ 4 testy (find z tłumaczeniami, not found, delete, save) - - Stary kontroler `admin\controls\Banners` działa jako niezależny fallback - - Stara factory `admin\factory\Banners` zachowana bez zmian (fallback) - - Aktualizacja: ver. 0.239 - -- **Articles** (migracja kontrolera - etap edit/details) - - ✅ ArticleRepository::find() - **ZMIGROWANE** (2026-02-06) 🎉 - - Nowa klasa: `Domain\Article\ArticleRepository` (find: artykul + relacje) - - Nowy kontroler: `admin\Controllers\ArticlesController` (DI, instancyjny) - - Zmigrowana akcja: `article_edit` -> `edit` (mapowanie w `admin\Site::$actionMap`) - - Kompatybilność: `admin\factory\Articles::article_details()` deleguje do nowego repozytorium - - Legacy cleanup: metody przejęte przez nowe kontrolery oznaczone `@deprecated` w `admin\controls\Articles|Banners|Settings` - - Testy repozytorium rozszerzone o czyszczenie nieprzypisanych plik�w/zdj�� - - Aktualizacja: ver. 0.243 - - ✅ ArticleRepository::save() - **ZMIGROWANE** (2026-02-06) 🎉 - - Metoda `save()` z prywatnych helperow (buildArticleRow, buildLangRow, saveTranslations, savePages, assignTempFiles, assignTempImages, deleteMarkedFiles, deleteMarkedImages) - - Zmigrowana akcja: `article_save` -> `save` (mapowanie w `admin\Site::$actionMap`) - - Kompatybilnosc: `admin\factory\Articles::article_save()` deleguje do repozytorium - - Testy: 7 nowych testow save (create, update, translations, pages, marked delete) - - Aktualizacja: ver. 0.244 - - ✅ ArticleRepository::archive() - **ZMIGROWANE** (2026-02-06) 🎉 - - Metoda `archive()` (ustawia status = -1) - - Zmigrowana akcja: `article_delete` -> `delete` (mapowanie w `admin\Site::$actionMap`) - - Kompatybilnosc: `admin\factory\Articles::articles_set_archive()` deleguje do repozytorium - - Testy: 2 nowe testy archive (success, failure) - - Aktualizacja: ver. 0.245 - - ✅ ArticlesController::browseList() - **ZMIGROWANE** (2026-02-07) 🎉 - - Nowa metoda kontrolera: `browseList()` (DI, instancyjna) - - Zmigrowana akcja: `browse_list` -> `browseList` (mapowanie w `admin\Site::$actionMap`) - - Legacy cleanup: usuniety `autoload/admin/controls/class.Articles.php` (brak fallback dla modułu Articles) - - Testy: 2 nowe testy kontraktu kontrolera (method exists + return type) - - ✅ ArticlesController::galleryOrderSave() - **ZMIGROWANE** (2026-02-07) 🎉 - - Nowa metoda kontrolera: `galleryOrderSave()` (AJAX) - - Zmigrowana akcja: `gallery_order_save` -> `galleryOrderSave` (mapowanie w `admin\Site::$actionMap`) - - Implementacja: używa `Domain\Article\ArticleRepository::saveGalleryOrder()` - - Testy: 2 nowe testy kontraktu kontrolera (method exists + return type) - - ✅ Usuniecie legacy kontrolera Articles - **ZMIGROWANE** (2026-02-07) 🎉 - - Usuniety plik: `autoload/admin/controls/class.Articles.php` - - Wymaganie dla aktualizacji: dodac wpis do `ver_X.XXX_files.txt` - - Wpis do usuniecia: `F: ../autoload/admin/controls/class.Articles.php` - - ✅ Stabilizacja generatora `.htaccess` - **ZMIGROWANE** (2026-02-07) 🎉 - - FIX: regula admin ma `QSA` (query string dla sortowania/filtrow) - - FIX: `\S::htacces()` komentuje `AddHandler|SetHandler|ForceType` dla zgodnosci z hostingiem - - UPDATE: `libraries/htaccess.conf` zaktualizowany, aby poprawki nie znikaly po regeneracji - -- **Settings** (migracja kontrolera) - - ✅ SettingsRepository - **ZMIGROWANE** (2026-02-05) 🎉 - - Nowa klasa: `Domain\Settings\SettingsRepository` (saveSettings, getSettings) - - Aktualny stan: bezpośredni dostęp do DB (usunięta delegacja do `admin\factory\Settings`) - ver. 0.250 - - Nowy kontroler: `admin\Controllers\SettingsController` (DI, instancyjny) - - Testy: ✅ 3 testy (instancja, metody) - - Stary kontroler `admin\controls\Settings` zachowany jako fallback - - Aktualizacja: ver. 0.240 / 0.250 - - ✅ CacheRepository - **ZMIGROWANE** (2026-02-05) 🎉 - - Nowa klasa: `Domain\Cache\CacheRepository` (clearCache) - - Używa `\S::delete_dir()` + `\RedisConnection` - - Testy: ✅ 4 testy (z Redis, bez Redis, niedostępny, struktura) - - Aktualizacja: ver. 0.240 - -- **Dictionaries** (migracja kontrolera i repozytorium) - - ✅ DictionariesRepository - **ZMIGROWANE** (2026-02-09) 🎉 - - Nowa klasa: `Domain\Dictionaries\DictionariesRepository` (listForAdmin, find, save, delete, allUnits) - - Nowy kontroler: `admin\Controllers\DictionariesController` (DI, instancyjny) - - Migracja na nowe komponenty: `components/table-list` + `components/form-edit` - - Legacy cleanup: usunięto klasy z `admin\controls`, `admin\factory`, `front\factory` - - Aktualizacja: ver. 0.251 - -- **Filemanager** (migracja routingu) - - ✅ FilemanagerController - **ZMIGROWANE** (2026-02-10) 🎉 - - Nowy kontroler: `admin\Controllers\FilemanagerController` - - Naprawa błędu: `Invalid Key` - - Legacy cleanup: usunięto `autoload/admin/controls/class.Filemanager.php` i `autoload/admin/view/class.FileManager.php` - - Aktualizacja: ver. 0.252 - -- **Users** (migracja kontrolera i repozytorium) - - ✅ UserRepository - **ZMIGROWANE** (2026-02-12) 🎉 - - Nowa klasa: `Domain\User\UserRepository` (find, getById, save, delete, checkLogin, logon, details, updateById, sendTwofaCode, verifyTwofaCode) - - Nowy kontroler: `admin\Controllers\UsersController` (DI, instancyjny: view_list, user_edit, user_save, user_delete, login_form, twofa) - - Router: `admin\Site` - factory wpis dla modulu `Users` - - Fasada: `admin\factory\Users` deleguje do repozytorium (backward compatibility dla login/2FA flow) - - AJAX: `admin/ajax/users.php` - `check_login` oparty o `UserRepository` - - Legacy cleanup: usuniety `autoload/admin/controls/class.Users.php` - - Testy: 25 testow repozytorium (CRUD, logon, 2FA, checkLogin) + 12 testow kontrolera (kontrakty + normalizeUser) - -- **Integrations** (migracja kontrolera i repozytorium + cleanup Sellasist/Baselinker) - - ✅ IntegrationsRepository - **ZMIGROWANE** (2026-02-13) 🎉 - - Nowa klasa: `Domain\Integrations\IntegrationsRepository` (settings Apilo/ShopPRO, OAuth, product linking, API fetch) - - Nowy kontroler: `admin\Controllers\IntegrationsController` (DI, instancyjny) - - Router: `admin\Site` - factory wpis dla modulu `Integrations` - - Fasada: `admin\factory\Integrations` deleguje do repozytorium (tylko Apilo + ShopPRO) - - **CLEANUP:** usunieto integracje Sellasist i Baselinker z calego projektu - - Usuniete pliki: `controls/Integrations`, `controls/Baselinker`, `factory/Baselinker`, `front/factory/Shop`, `shop/ShopStatus`, szablony sellasist/baselinker - - Wyczyszczone referencje w: cron.php, Order, ShopStatuses, ShopTransport, ShopPaymentMethod, ShopProduct, config.php, front/factory/* - - Testy: 16 nowych testow (repozytorium) + 10 testow kontrolera - - Aktualizacja: ver. 0.263 - -### 📋 Do zrobienia -- Order -- Category -- ShopAttribute -- ShopProduct (factory) - -## Testowanie - -### Framework: PHPUnit -Instalacja: -```bash -composer require --dev phpunit/phpunit -``` - -### Struktura testów -``` -tests/ -├── Unit/ -│ ├── Domain/ -│ │ ├── Article/ArticleRepositoryTest.php -│ │ ├── Banner/BannerRepositoryTest.php -│ │ ├── Cache/CacheRepositoryTest.php -│ │ ├── Dictionaries/DictionariesRepositoryTest.php -│ │ ├── Product/ProductRepositoryTest.php -│ │ ├── Settings/SettingsRepositoryTest.php -│ │ ├── User/UserRepositoryTest.php -│ │ └── Integrations/IntegrationsRepositoryTest.php -│ └── admin/ -│ └── Controllers/ -│ ├── ArticlesControllerTest.php -│ ├── DictionariesControllerTest.php -│ ├── IntegrationsControllerTest.php -│ ├── ProductArchiveControllerTest.php -│ ├── SettingsControllerTest.php -│ └── UsersControllerTest.php -└── Integration/ -``` -**Łącznie: 212 testów, 577 asercji** - -### Przykład testu -```php -// tests/Unit/Domain/Product/ProductRepositoryTest.php -use PHPUnit\Framework\TestCase; -use Domain\Product\ProductRepository; - -class ProductRepositoryTest extends TestCase { - public function testGetQuantityReturnsCorrectValue() { - // Arrange - $mockDb = $this->createMock(\medoo::class); - $mockDb->method('get')->willReturn(10); - - $repo = new ProductRepository($mockDb); - - // Act - $quantity = $repo->getQuantity(123); - - // Assert - $this->assertEquals(10, $quantity); - } -} -``` - -## Zasady kodu - -### 1. SOLID Principles -- **S**ingle Responsibility - jedna klasa = jedna odpowiedzialność -- **O**pen/Closed - otwarty na rozszerzenia, zamknięty na modyfikacje -- **L**iskov Substitution - podklasy mogą zastąpić nadklasy -- **I**nterface Segregation - wiele małych interfejsów -- **D**ependency Inversion - zależności od abstrakcji - -### 2. Nazewnictwo -- **Entity** - `Product.php` (reprezentuje obiekt domenowy) -- **Repository** - `ProductRepository.php` (dostęp do danych) -- **Service** - `ProductService.php` (logika biznesowa) -- **Controller** - `ProductController.php` (obsługa requestów) - -### 3. Type Hinting -```php -// ✅ DOBRE -public function getQuantity(int $id): ?int { - return $this->db->get('pp_shop_products', 'quantity', ['id' => $id]); -} - -// ❌ ZŁE -public function getQuantity($id) { - return $this->db->get('pp_shop_products', 'quantity', ['id' => $id]); -} -``` - -## Narzędzia pomocnicze - -### Autoloader (produkcja) -Autoloader w 9 entry pointach obsługuje dwie konwencje: -1. `autoload/{namespace}/class.{ClassName}.php` (legacy) -2. `autoload/{namespace}/{ClassName}.php` (PSR-4, fallback) - -Entry pointy: `index.php`, `ajax.php`, `api.php`, `cron.php`, `cron-turstmate.php`, `download.php`, `admin/index.php`, `admin/ajax.php`, `cron/cron-xml.php` - -### Static Analysis -```bash -composer require --dev phpstan/phpstan -vendor/bin/phpstan analyse autoload/Domain -``` - -## Kolejność refaktoryzacji (priorytet) - -1. **Cache** ✅ -2. **Product** (w trakcie) - - ✅ getQuantity (ver. 0.238) - - ✅ getPrice (ver. 0.239) - - ✅ getName (ver. 0.239) - - ✅ archive / unarchive (ver. 0.241) - - [ ] is_product_on_promotion - NASTĘPNA 👉 - - [ ] getFromCache - - [ ] getProductImg -3. **Banner** ✅ (pełna migracja kontrolera, ver. 0.239) -4. **Settings** ✅ (pełna migracja repo/kontrolera + cleanup legacy, ver. 0.250) -5. **Dictionaries** ✅ (repo + kontroler + form/table, ver. 0.251) -6. **ProductArchive** ✅ (migracja kontrolera + cleanup szablonów, ver. 0.252) -7. **Filemanager** ✅ (migracja routingu + fix `Invalid Key`, ver. 0.252) -8. **Users** ✅ (repo + kontroler + 2FA + legacy cleanup, ver. 0.253) -9. **Pages** ✅ (repo + kontroler + drzewo stron + AJAX endpoints, ver. 0.262) -10. **Integrations** ✅ (repo + kontroler + cleanup Sellasist/Baselinker, ver. 0.263) -11. **Order** -12. **Category** -13. **ShopAttribute** - -- **Form Edit System** - Nowy uniwersalny system formularzy edycji - - ✅ Klasy ViewModel: `FormFieldType`, `FormField`, `FormTab`, `FormAction`, `FormEditViewModel` - - ✅ Walidacja: `FormValidator` z obsługą reguł per pole i sekcje językowe - - ✅ Persist: `FormRequestHandler` - zapamiętywanie danych przy błędzie walidacji - - ✅ Renderer: `FormFieldRenderer` - renderowanie wszystkich typów pól - - ✅ Szablon: `admin/templates/components/form-edit.php` - uniwersalny layout - - ✅ BannerController - przerobiony na nowy system formularzy - - Wspierane typy pól: text, number, email, password, date, datetime, switch, select, textarea, editor, image, file, hidden, lang_section - - Obsługa zakładek (vertical) i sekcji językowych (horizontal) - - **Do zrobienia**: Przerobić pozostałe kontrolery/formularze (Product, Category, Pages, itd.) - ---- -*Rozpoczęto: 2025-02-05* -*Ostatnia aktualizacja: 2026-02-12* - - -## Form Edit System - Dokumentacja użycia - -### Architektura - -``` -┌─────────────────────────────────────────────────────────────┐ -│ Controller │ -│ ┌─────────────────┐ ┌─────────────────┐ │ -│ │ edit() │ │ save() │ │ -│ │ - buduje VM │ │ - walidacja │ │ -│ │ - renderuje │ │ - zapis │ │ -│ └────────┬────────┘ └─────────────────┘ │ -└───────────┼─────────────────────────────────────────────────┘ - │ - ▼ -┌─────────────────────────────────────────────────────────────┐ -│ FormEditViewModel │ -│ - title, formId, data, fields, tabs, actions │ -│ - validationErrors, persist, languages │ -└───────────┬─────────────────────────────────────────────────┘ - │ - ▼ -┌─────────────────────────────────────────────────────────────┐ -│ components/form-edit.php (szablon) │ -│ ┌─────────────────────────────────────────────────────┐ │ -│ │ FormFieldRenderer - renderuje każde pole │ │ -│ │ ├─ input, select, textarea, switch │ │ -│ │ ├─ date, datetime, editor, image │ │ -│ │ └─ lang_section (zagnieżdżone pola) │ │ -│ └─────────────────────────────────────────────────────┘ │ -└─────────────────────────────────────────────────────────────┘ -``` - -### Przykład użycia w kontrolerze - -```php -use admin\ViewModels\Forms\FormEditViewModel; -use admin\ViewModels\Forms\FormField; -use admin\ViewModels\Forms\FormTab; -use admin\ViewModels\Forms\FormAction; -use admin\Support\Forms\FormRequestHandler; - -class BannerController -{ - public function edit(): string - { - $banner = $this->repository->find($id); - $languages = \admin\factory\Languages::languages_list(); - - $viewModel = new FormEditViewModel( - formId: 'banner-edit', - title: 'Edycja banera', - data: $banner, - tabs: [ - new FormTab('settings', 'Ustawienia', 'fa-wrench'), - new FormTab('content', 'Zawartość', 'fa-file'), - ], - fields: [ - // Zakładka Ustawienia - FormField::text('name', [ - 'label' => 'Nazwa', - 'tab' => 'settings', - 'required' => true, - ]), - FormField::switch('status', [ - 'label' => 'Aktywny', - 'tab' => 'settings', - ]), - FormField::date('date_start', [ - 'label' => 'Data rozpoczęcia', - 'tab' => 'settings', - ]), - - // Sekcja językowa w zakładce Zawartość - FormField::langSection('translations', 'content', [ - FormField::image('src', ['label' => 'Obraz']), - FormField::text('url', ['label' => 'Url']), - FormField::editor('text', ['label' => 'Treść']), - ]), - ], - actions: [ - FormAction::save('/admin/banners/save', '/admin/banners'), - FormAction::cancel('/admin/banners'), - ], - languages: $languages, - persist: true, - ); - - return \Tpl::view('components/form-edit', ['form' => $viewModel]); - } - - public function save(): void - { - $formHandler = new FormRequestHandler(); - $viewModel = $this->buildFormViewModel(); // jak w edit() - - $result = $formHandler->handleSubmit($viewModel, $_POST); - - if (!$result['success']) { - // Błędy walidacji - zapisane automatycznie do sesji - echo json_encode(['success' => false, 'errors' => $result['errors']]); - exit; - } - - // Sukces - persist wyczyszczony automatycznie - $this->repository->save($result['data']); - echo json_encode(['success' => true]); - exit; - } -} -``` - -### Dostępne typy pól - -| Typ | Metoda | Opcje | -|-----|--------|-------| -| `text` | `FormField::text(name, ['label' => '...', 'required' => true])` | placeholder, help | -| `number` | `FormField::number(name, [...])` | - | -| `email` | `FormField::email(name, [...])` | walidacja formatu | -| `password` | `FormField::password(name, [...])` | - | -| `date` | `FormField::date(name, [...])` | datetimepicker | -| `datetime` | `FormField::datetime(name, [...])` | datetimepicker z czasem | -| `switch` | `FormField::switch(name, [...])` | checked (bool) | -| `select` | `FormField::select(name, ['options' => [...]])` | options: [key => label] | -| `textarea` | `FormField::textarea(name, ['rows' => 4])` | rows | -| `editor` | `FormField::editor(name, ['toolbar' => 'MyTool'])` | CKEditor | -| `image` | `FormField::image(name, ['filemanager' => true])` | filemanager URL | -| `file` | `FormField::file(name, [...])` | filemanager | -| `hidden` | `FormField::hidden(name, value)` | - | -| `lang_section` | `FormField::langSection(name, 'tab', [fields])` | pola per język | - -### Walidacja - -Walidacja jest automatyczna na podstawie właściwości pól: -- `required` - pole wymagane -- `type` = `email` - walidacja formatu e-mail -- `type` = `number` - walidacja liczby -- `type` = `date` - walidacja formatu YYYY-MM-DD - -Dla sekcji językowych walidacja jest powtarzana dla każdego aktywnego języka. - -### Persist (zapamiętywanie danych) - -Gdy `persist = true`: -1. Przy błędzie walidacji dane są zapisywane w `$_SESSION['form_persist'][$formId]` -2. Formularz automatycznie przywraca dane z sesji przy ponownym wyświetleniu -3. Po udanym zapisie sesja jest czyszczona automatycznie przez `FormRequestHandler` - -### Przerabianie istniejących formularzy - -1. **Kontroler** - zamień `view\Xxx::edit()` na `FormEditViewModel` -2. **Repository** - dostosuj `save()` do formatu z `FormRequestHandler` (lub dodaj wsparcie dla obu formatów) -3. **Szablon** - usuń stary szablon lub zostaw jako fallback -4. **Testy** - zaktualizuj testy jeśli zmienił się format danych - - -## Aktualizacja 2026-02-12 - Users - -### Users (migracja kontrolera i repozytorium) -- **NOWE:** `Domain\User\UserRepository` (delete, find, save, checkLogin, logon, details, sendTwofaCode, verifyTwofaCode) -- **NOWE:** `admin\Controllers\UsersController` (view_list, user_edit, user_save, user_delete) -- **UPDATE:** Router `admin\Site` - nowy kontroler DI dla modu�u `Users` -- **UPDATE:** `admin\factory\Users` jako fasada delegujaca do repozytorium -- **UPDATE:** `admin/ajax/users.php` - endpoint `check_login` oparty o `UserRepository` -- Testy po zmianie: 95 tests, 204 assertions -- **UPDATE:** UsersController: `view_list` + `user_edit` migrowane na nowy system list/form (table-list + form-edit) - -## Aktualizacja 2026-02-12 (finalizacja Users) -- Users: pelna migracja na nowa architekture (Domain + DI Controller), bez fallbacku do legacy kontrolera/factory/view. -- `UsersController` obsluguje: `list/view_list`, `user_edit`, `user_save`, `user_delete`, `login_form`, `twofa`. -- Dodano walidacje warunkowa: `twofa_email` wymagany gdy `twofa_enabled = 1`. -- Widoki users migrowane z `grid/gridEdit` na `table-list` i `form-edit`. - -## Aktualizacja 2026-02-12 - Languages -- **NOWE:** `Domain\\Languages\\LanguagesRepository` (languages + translations CRUD/list) -- **NOWE:** `admin\\Controllers\\LanguagesController` (DI) -- **UPDATE:** `admin\\Site` - nowy kontroler DI dla modulu `Languages` -- **UPDATE:** `admin\\factory\\Languages` jako fasada delegujaca do repozytorium -- **UPDATE:** widoki `languages/*` migrowane na `components/table-list` i `components/form-edit` -- **CLEANUP:** usunieto legacy `admin\\controls\\Languages` i `admin\\view\\Languages` -- Testy po zmianie: 130 tests, 301 assertions - -## Aktualizacja 2026-02-12 (Languages final) -- **NOWE:** `Domain\\Languages\\LanguagesRepository` (list/save/delete dla jezykow i tlumaczen) -- **NOWE:** `admin\\Controllers\\LanguagesController` (DI) dla akcji `view_list/list`, `language_*`, `translation_*` -- **UPDATE:** `admin\\factory\\Languages` jako fasada delegujaca do repozytorium -- **CLEANUP:** usunieto legacy `admin\\controls\\Languages` oraz `admin\\view\\Languages` -- **UPDATE:** poprawki globalne `components/table-list` dla krotkich kolumn/filtr�w - -## Aktualizacja 2026-02-12 (ver. 0.255) -- UPDATE: SettingsController, BannerController, DictionariesController, ArticlesController pobieraja liste jezykow przez Domain/Languages/LanguagesRepository (DI) zamiast legacy admin/factory/Languages. -- UPDATE: router DI (admin/Site) przekazuje LanguagesRepository do kontrolerow Articles, Banners, Settings, Dictionaries. -- UPDATE: pozostale aktywne odwolania legacy (admin/controls, admin/factory/Shop*) zostaly przepiete na LanguagesRepository. -- FIX: autoload/admin/factory/class.Languages.php poprawione na restore` - - CLEANUP: usuniete `autoload/admin/controls/class.ArticlesArchive.php`, `autoload/admin/factory/class.ArticlesArchive.php`, `autoload/admin/view/class.ArticlesArchive.php` -- Testy po zmianie: **165 tests, 424 assertions** - -## Plan 2026-02-13 - Refaktoryzacja `/admin/articles/` -- [ ] Przeniesc zaleznosci listy artykulow z `admin\factory\Articles` do `Domain\Article\ArticleRepository` (etykiety stron, operacje pomocnicze). -- [ ] Dodac akcje routowane przez `admin\Controllers\ArticlesController` dla operacji AJAX (`article_image_alt_change`, `article_file_name_change`, `article_image_delete`, `article_file_delete`). -- [ ] Przepiac widok `admin/templates/articles/article-edit.php` z `/admin/ajax.php` na endpointy `/admin/articles/*`. -- [ ] Usunac legacy `admin\view\Articles` i zastapic rekurencje podstron przez `Tpl::view('articles/subpages-list', ...)`. -- [ ] Usunac `admin/ajax/articles.php` oraz odpiac include z `admin/ajax.php`. -- [ ] Przeszukac projekt pod pozostale zaleznosci i uruchomic testy modulu Articles. - -## Aktualizacja 2026-02-13 (ver. 0.261) -- **Articles** - dalsza refaktoryzacja `/admin/articles/` - - UPDATE: `Domain\Article\ArticleRepository` rozszerzone o metody UI/admin: `pagesSummaryForArticles()`, `updateImageAlt()`, `updateFileName()`, `markImageToDelete()`, `markFileToDelete()`. - - UPDATE: `admin\Controllers\ArticlesController` obsluguje nowe akcje routingu: `article_image_alt_change`, `article_file_name_change`, `article_image_delete`, `article_file_delete`. - - UPDATE: lista artykulow (`list`) nie korzysta juz z `admin\factory\Articles::article_pages()`. - - UPDATE: `admin/templates/articles/article-edit.php` przepiete z `/admin/ajax.php?a=article_*` na endpointy `/admin/articles/article_*/`. - - UPDATE: rekurencja podstron w widoku oparta o `Tpl::view('articles/subpages-list', ...)` (bez `admin\view\Articles`). - - CLEANUP: usuniete legacy pliki `autoload/admin/view/class.Articles.php` oraz `admin/ajax/articles.php`; `admin/ajax.php` nie includuje juz `ajax/articles.php`. -- Testy po zmianie: **176 tests, 439 assertions**. - -## Aktualizacja 2026-02-13 (ver. 0.261) -- **Articles (/admin/articles)** - - UPDATE: `Domain\Article\ArticleRepository` rozszerzone o `saveFilesOrder()` oraz zapis `files_order` przy `save()` (eliminuje koniecznosc drugiego zapisu po sortowaniu). - - UPDATE: routing DI (`admin\Site`) rozszerzony o mapowanie `files_order_save -> filesOrderSave`. - - UPDATE: `admin\Controllers\ArticlesController` - nowa akcja AJAX `filesOrderSave`. - - UPDATE: widok `admin/templates/articles/article-edit-custom-script.php` - drag&drop dla listy zalacznikow + hidden input `files_order`. - - 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)**. - -## Aktualizacja 2026-02-13 - Integrations (/admin/integrations) -- NOWE: `Domain\Integrations\IntegrationsRepository` (settings Apilo/ShopPRO, OAuth, product linking, API fetch lists, product search/create, ShopPRO import). -- NOWE: `admin\Controllers\IntegrationsController` (DI) dla akcji: `apilo_settings`, `apilo_settings_save`, `apilo_authorization`, `get_platform_list`, `get_status_types_list`, `get_carrier_account_list`, `get_payment_types_list`, `apilo_create_product`, `apilo_product_search`, `apilo_product_select_save`, `apilo_product_select_delete`, `shoppro_settings`, `shoppro_settings_save`, `shoppro_product_import`. -- UPDATE: `admin\factory\Integrations` jako fasada delegujaca do `Domain\Integrations\IntegrationsRepository` (tylko Apilo + ShopPRO). -- **CLEANUP: usunieto integracje Sellasist i Baselinker z calego projektu:** - - Usuniete klasy: `admin\controls\Integrations`, `admin\controls\Baselinker`, `admin\factory\Baselinker`, `front\factory\Shop`, `shop\ShopStatus` - - Usuniete szablony: `integrations/sellasist-settings.php`, `integrations/baselinker-settings.php`, `admin/templates/baselinker/` - - Wyczyszczone referencje w: `cron.php`, `cron/cron-xml.php`, `shop\Order`, `admin\controls\ShopStatuses`, `admin\controls\ShopTransport`, `admin\controls\ShopPaymentMethod`, `admin\controls\ShopProduct`, `admin\factory\ShopStatuses`, `admin\factory\ShopTransport`, `admin\factory\ShopProduct`, `front\factory\ShopStatuses`, `front\factory\ShopTransport`, `front\factory\ShopPaymentMethod`, `front\factory\ShopProduct`, `front\factory\ShopOrder`, `shop\Product`, `config.php` - - Wyczyszczone szablony: `shop-statuses/*`, `shop-transport/*`, `shop-payment-method/*`, `shop-product/*`, `site/main-layout.php` -- Testy: **OK (212 tests, 577 assertions)**. - -## Plan 2026-02-13 - Refaktoryzacja `/admin/shop_promotion/` (HITL) -- [x] Etap 1 (analiza i kontrakt): potwierdzic docelowy kontrakt URL i kompatybilnosc wsteczna: - - kontrakt docelowy: tylko `/admin/shop_promotion/list/`, `/admin/shop_promotion/edit/`, `/admin/shop_promotion/save/`, `/admin/shop_promotion/delete/` - - brak kompatybilnosci ze starymi URL i aliasami akcji (`view_list`, `promotion_delete`) -- [x] Etap 2 (Domain): dodac `Domain\Promotion\PromotionRepository`: - - `listForAdmin(filters, sort, dir, page, perPage)` z whitelist sortowania i bind params - - `find(int $id)` + domyslne dane dla nowego formularza - - `save(array $data): ?int` (insert/update, normalizacja switchy, JSON dla kategorii) - - `delete(int $id): bool` - - `categoriesTree(?int $parentId): array` (drzewo kategorii z tlumaczeniami, bez zaleznosci od `admin\factory\ShopCategory`) -- [x] Etap 3 (Admin Controller + routing DI): dodac `admin\Controllers\ShopPromotionController` i przepiac routing: - - rejestracja factory w `admin\Site::$newControllers` pod modulem `ShopPromotion` - - akcje: `list`, `edit`, `save`, `delete` - - zachowac obsluge legacy payload (`values` JSON) oraz obsluge `form-edit` (`$_POST`) -- [x] Etap 4 (widoki): przepiac modul z `grid/gridEdit` na nowe komponenty: - - nowy widok listy oparty o `components/table-list` (filtry: nazwa, aktywny) - - nowy widok edycji oparty o `components/form-edit` (+ pola custom dla drzew kategorii) - - nowe partiale dla drzewa kategorii w module `shop-promotion` (usuniecie zaleznosci od `shop-product/subcategories-list`) - - nowy `shop-promotion/promotion-edit-custom-script.php` (warunkowe pola po `condition_type`, obsluga drzewa kategorii) -- [x] Etap 5 (zaleznosci i cleanup): przeszukac i odpiac legacy zaleznosci: - - menu admin: link kanoniczny na `/admin/shop_promotion/list/` - - usunac legacy pliki po pelnym przepieciu: - - `autoload/admin/controls/class.ShopPromotion.php` - - `autoload/admin/factory/class.ShopPromotion.php` - - `admin/templates/shop-promotion/view-list.php` (grid) - - `admin/templates/shop-promotion/promotion-edit.php` (gridEdit) - - sprawdzic pozostale odwolania `ShopPromotion` i `shop_promotion/view_list` w calym repo -- [x] Etap 6 (testy): dodac/uzupelnic testy: - - `tests/Unit/Domain/Promotion/PromotionRepositoryTest.php` - - `tests/Unit/admin/Controllers/ShopPromotionControllerTest.php` - - uruchomic minimum: nowe testy modulu + pelny `composer test` -- [x] Etap 7 (dokumentacja po wdrozeniu): zaktualizowac: - - `DATABASE_STRUCTURE.md` (dodac `pp_shop_promotion`, jesli nadal brak) - - `PROJECT_STRUCTURE.md` - - `REFACTORING_PLAN.md` (sekcja "Aktualizacja ...") - - `TESTING.md` (nowy wynik suite) - -## Aktualizacja 2026-02-13 (ver. 0.264) -- **ShopPromotion** - migracja `/admin/shop_promotion` na Domain + DI + nowe widoki - - NOWE: `Domain\Promotion\PromotionRepository` (`listForAdmin`, `find`, `save`, `delete`, `categoriesTree`, invalidacja cache aktywnych promocji) - - NOWE: `admin\Controllers\ShopPromotionController` (DI) z akcjami `list`, `edit`, `save`, `delete` - - UPDATE: routing DI (`admin\Site`) rozszerzony o modul `ShopPromotion` - - UPDATE: modul `/admin/shop_promotion/*` dziala na `components/table-list` i `components/form-edit` - - NOWE: widoki/partiale `shop-promotion/promotions-list`, `shop-promotion/promotion-edit`, `shop-promotion/promotion-categories-selector`, `shop-promotion/promotion-categories-tree`, `shop-promotion/promotion-edit-custom-script` - - CLEANUP: usuniete legacy `autoload/admin/controls/class.ShopPromotion.php`, `autoload/admin/factory/class.ShopPromotion.php`, `admin/templates/shop-promotion/view-list.php` - - UPDATE: menu admin przepiete na kanoniczny URL `/admin/shop_promotion/list/` -- Testy po zmianie: **OK (222 tests, 609 assertions)**. - -## Aktualizacja 2026-02-13 (ver. 0.265) -- **ShopPromotion** - stabilizacja po migracji - - UPDATE: dodane `date_from` w `Domain\Promotion\PromotionRepository` (save/find/list/sort) - - UPDATE: `admin\Controllers\ShopPromotionController` rozszerzony o pole `Data od` na formularzu i kolumne `Data od` na liscie - - UPDATE: `shop\Promotion::get_active_promotions()` filtruje aktywnosc po `date_from` i `date_to` - - FIX: zapis edycji promocji nie tworzy nowego rekordu (hidden `id` + fallback `id` z URL) - - TEST: rozszerzono `PromotionRepositoryTest` o asercje `date_from` -- Testy po zmianie: **OK (222 tests, 614 assertions)**. - -## Plan 2026-02-13 - Refaktoryzacja `/admin/shop_coupon/` (HITL) -- [x] Etap 1 (analiza i kontrakt URL/routingu): - - potwierdzic docelowy kontrakt URL: `/admin/shop_coupon/list/`, `/admin/shop_coupon/edit/`, `/admin/shop_coupon/save/`, `/admin/shop_coupon/delete/` - - decyzja: utrzymujemy aliasy legacy (`view_list`, `coupon_edit`, `coupon_save`, `coupon_delete`) w nowym kontrolerze jako kompatybilnosc wsteczna, przy jednoczesnym przejsciu menu i nowych widokow na URL kanoniczne - - sprawdzic mapowanie modulu `ShopCoupon` w `admin\Site` (DI factory + fallback) -- [x] Etap 2 (Domain): - - dodac `Domain\Coupon\CouponRepository`: - - `listForAdmin(filters, sort, dir, page, perPage)` (whitelist sortowania + paginacja) - - `find(int $id)` (domyslne dane dla nowego formularza) - - `save(array $data): ?int` (insert/update, normalizacja switchy, JSON dla `categories`) - - `delete(int $id): bool` - - `categoriesTree(?int $parentId): array` (drzewo kategorii bez zaleznosci od `admin\factory\ShopCategory`) -- [x] Etap 3 (Admin Controller + routing DI): - - dodac `admin\Controllers\ShopCouponController` z akcjami `list`, `edit`, `save`, `delete` - - przepiac routing DI w `admin\Site::$newControllers` dla modulu `ShopCoupon` - - zachowac obsluge legacy payload `values` JSON i nowego payload `$_POST` z `components/form-edit` -- [x] Etap 4 (widoki): - - przepiac liste z `grid` na `components/table-list` (filtry: nazwa, aktywny, uzyty, wyslany) - - przepiac edycje z `gridEdit` na `components/form-edit` - - dodac partiale drzewa kategorii w module `shop-coupon` (usuniecie zaleznosci od `shop-product/subcategories-list`) - - dodac `shop-coupon/coupon-edit-custom-script.php` (obsluga drzewa kategorii i zachowania formularza) -- [x] Etap 5 (cleanup i zaleznosci): - - usunac legacy po pelnym przepieciu: - - `autoload/admin/controls/class.ShopCoupon.php` - - `autoload/admin/factory/class.ShopCoupon.php` - - `admin/templates/shop-coupon/view-list.php` (wersja grid) - - `admin/templates/shop-coupon/coupon-edit.php` (wersja gridEdit) - - przepiac menu admin na kanoniczny URL `/admin/shop_coupon/list/` - - przeszukac repo i usunac pozostale odwolania do `shop_coupon/view_list` i legacy klas `admin\controls\ShopCoupon`, `admin\factory\ShopCoupon` -- [x] Etap 6 (testy): - - dodac `tests/Unit/Domain/Coupon/CouponRepositoryTest.php` - - dodac `tests/Unit/admin/Controllers/ShopCouponControllerTest.php` - - uruchomic testy modulu + pelny `composer test` -- [x] Etap 7 (dokumentacja i release note): - - zaktualizowac `DATABASE_STRUCTURE.md` (dodac `pp_shop_coupon`) - - zaktualizowac `PROJECT_STRUCTURE.md` - - zaktualizowac `REFACTORING_PLAN.md` (sekcja "Aktualizacja ...") - - zaktualizowac `TESTING.md` (nowy wynik suite + nowe testy) - - dopisac wpis w `updates/changelog.php` - -### Tryb HITL dla realizacji -- Po kazdym etapie (1-7) zatrzymanie i krotkie podsumowanie diffu do akceptacji przed kolejnym krokiem. - -### Postep 2026-02-13 (ShopCoupon) -- Etap 2 zakonczony: - - NOWE: `autoload/Domain/Coupon/CouponRepository.php` - - Zakres: `listForAdmin`, `find`, `save`, `delete`, `categoriesTree` - - Walidacja: `php -l` OK -- Etap 3 zakonczony: - - NOWE: `autoload/admin/Controllers/ShopCouponController.php` - - UPDATE: `autoload/admin/class.Site.php` - rejestracja DI factory dla modulu `ShopCoupon` - - Kompatybilnosc: dodane aliasy akcji `view_list`, `coupon_edit`, `coupon_save`, `coupon_delete` - - Walidacja: `php -l` OK -- Etap 4 zakonczony: - - NOWE widoki: `admin/templates/shop-coupon/coupons-list.php`, `admin/templates/shop-coupon/coupon-edit-new.php` - - NOWE partiale: `admin/templates/shop-coupon/coupon-categories-selector.php`, `admin/templates/shop-coupon/coupon-categories-tree.php` - - NOWY skrypt: `admin/templates/shop-coupon/coupon-edit-custom-script.php` - - UPDATE: `ShopCouponController::edit()` buduje `FormEditViewModel` (zakladki ustawienia/kategorie) - - Walidacja: `php -l` OK -- Etap 5 zakonczony: - - CLEANUP: usuniete pliki legacy: - - `autoload/admin/controls/class.ShopCoupon.php` - - `autoload/admin/factory/class.ShopCoupon.php` - - `admin/templates/shop-coupon/view-list.php` - - `admin/templates/shop-coupon/coupon-edit.php` - - UPDATE: menu admin (`admin/templates/site/main-layout.php`) wskazuje kanoniczny URL `/admin/shop_coupon/list/` - - WERYFIKACJA: brak odwolan do `shop_coupon/view_list`, `admin\controls\ShopCoupon`, `admin\factory\ShopCoupon` w kodzie -- Etap 6 zakonczony: - - NOWE testy: - - `tests/Unit/Domain/Coupon/CouponRepositoryTest.php` (8 testow) - - `tests/Unit/admin/Controllers/ShopCouponControllerTest.php` (5 testow) - - Test modulu: `OK (8 tests, 49 assertions)` - - Pelny suite: `OK (235 tests, 682 assertions)` -- Etap 7 zakonczony: - - UPDATE: dokumentacja techniczna zaktualizowana (`DATABASE_STRUCTURE.md`, `PROJECT_STRUCTURE.md`, `TESTING.md`) - - UPDATE: dopisany release note w `updates/changelog.php` (ver. 0.266) - -## Aktualizacja 2026-02-13 (ver. 0.266) -- **ShopCoupon** - migracja `/admin/shop_coupon` na Domain + DI + nowe widoki - - NOWE: `Domain\Coupon\CouponRepository` (`listForAdmin`, `find`, `save`, `delete`, `categoriesTree`) - - NOWE: `admin\Controllers\ShopCouponController` (DI) z akcjami `list`, `edit`, `save`, `delete` - - UPDATE: kompatybilnosc aliasow legacy (`view_list`, `coupon_edit`, `coupon_save`, `coupon_delete`) obslugiwana przez nowy kontroler - - UPDATE: modul `/admin/shop_coupon/*` dziala na `components/table-list` i `components/form-edit` - - NOWE: widoki/partiale `shop-coupon/coupons-list`, `shop-coupon/coupon-edit-new`, `shop-coupon/coupon-categories-selector`, `shop-coupon/coupon-categories-tree`, `shop-coupon/coupon-edit-custom-script` - - CLEANUP: usuniete legacy `autoload/admin/controls/class.ShopCoupon.php`, `autoload/admin/factory/class.ShopCoupon.php`, `admin/templates/shop-coupon/view-list.php`, `admin/templates/shop-coupon/coupon-edit.php` - - UPDATE: menu admin przepiete na kanoniczny URL `/admin/shop_coupon/list/` - - FIX: po akceptacji HITL ujednolicone UI drzewek i checkboxow miedzy kuponami i layoutami (spojne strzalki, brak nieestetycznego focusu, iCheck dla checkboxow) -- Testy po zmianie: **OK (235 tests, 682 assertions)**. diff --git a/admin/templates/shop-statuses/status-edit.php b/admin/templates/shop-statuses/status-edit.php index f4387e8..5fe1611 100644 --- a/admin/templates/shop-statuses/status-edit.php +++ b/admin/templates/shop-statuses/status-edit.php @@ -1,79 +1 @@ - - - -global $db; -$apilo_status_types_list[''] = '--- wybierz status apilo.com ---'; -foreach ( $this -> apilo_order_status_list as $apilo_status ) -{ - $apilo_status_types_list[ $apilo_status['id'] ] = $apilo_status['name']; -} -ob_start(); -?> -