# 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 │ │ ├── ProductService.php # (przyszłość) │ │ └── ProductCacheService.php # (przyszłość) │ ├── Banner/ │ │ └── BannerRepository.php │ ├── Settings/ │ │ └── SettingsRepository.php │ ├── Cache/ │ │ └── CacheRepository.php │ ├── Order/ │ ├── Category/ │ └── ... │ ├── admin/ # Warstwa administratora (istniejący katalog!) │ ├── Controllers/ # Nowe kontrolery - namespace \admin\Controllers\ │ ├── 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 | # | Modul | Wersja | Zakres | |---|-------|--------|--------| | 1 | Cache | 0.237 | CacheHandler, RedisConnection, clear_product_cache | | 2 | Product | 0.238-0.252, 0.274 | getQuantity, getPrice, getName, archive/unarchive, allProductsForMassEdit, getProductsByCategory, applyDiscountPercent | | 3 | Banner | 0.239 | find, delete, save, kontroler DI | | 4 | Settings | 0.240/0.250 | saveSettings, getSettings, kontroler DI | | 5 | Dictionaries | 0.251 | listForAdmin, find, save, delete, kontroler DI | | 6 | ProductArchive | 0.252 | kontroler DI, table-list | | 7 | Filemanager | 0.252 | kontroler DI, fix Invalid Key | | 8 | Users | 0.253 | CRUD, logon, 2FA, kontroler DI | | 9 | Languages | 0.254 | languages + translations, kontroler DI | | 10 | Layouts | 0.256 | find, save, delete, menusWithPages, categoriesTree | | 11 | Newsletter | 0.257-0.258 | subskrybenci, szablony, ustawienia | | 12 | Scontainers | 0.259 | listForAdmin, find, save, delete | | 13 | ArticlesArchive | 0.260 | restore, deletePermanently | | 14 | Articles | 0.261 | pelna migracja (CRUD, AJAX, galeria, pliki) | | 15 | Pages | 0.262 | menu/page CRUD, drzewo stron, AJAX | | 16 | Integrations | 0.263 | Apilo/ShopPRO, cleanup Sellasist/Baselinker | | 17 | ShopPromotion | 0.264-0.265 | listForAdmin, find, save, delete, categoriesTree | | 18 | ShopCoupon | 0.266 | listForAdmin, find, save, delete, categoriesTree | | 19 | ShopStatuses | 0.267 | listForAdmin, find, save, color picker | | 20 | ShopPaymentMethod | 0.268 | listForAdmin, find, save, allActive, mapowanie Apilo, DI kontroler | | 21 | ShopTransport | 0.269 | listForAdmin, find, save, allActive, allForAdmin, findActiveById, getTransportCost, lowestTransportPrice, getApiloCarrierAccountId, powiazanie z PaymentMethod, DI kontroler | | 22 | ShopAttribute | 0.271 | list/edit/save/delete/values, nowy edytor wartosci, cleanup legacy, przepiecie zaleznosci kombinacji | | 23 | ShopProductSets | 0.272 | listForAdmin, find, save, delete, allSets, allProductsMap, multi-select Selectize, DI kontroler | | 24 | ShopProducer | 0.273 | listForAdmin, find, save, delete, allProducers, producerProducts, fasada shop\Producer, DI kontroler | | 25 | ShopProduct (mass_edit) | 0.274 | DI kontroler + routing dla `mass_edit`, `mass_edit_save`, `get_products_by_category`, cleanup legacy akcji | | 26 | ShopClients | 0.274 | DI kontroler + routing dla `list/details`, nowe listy na `components/table-list`, cleanup legacy controls/factory | | 27 | ShopCategory | 0.275 | CategoryRepository + DI kontroler + routing, endpointy AJAX (`save_categories_order`, `save_products_order`, `cookie_categories`), cleanup legacy controls/factory/view | | 28 | ShopOrder | 0.276 | OrderRepository + OrderAdminService + DI kontroler + routing + nowe widoki (`orders-list`, `order-details`, `order-edit`) + cleanup legacy controls/factory/view-list | ### Product - szczegolowy status - ✅ getQuantity (ver. 0.238) - ✅ getPrice (ver. 0.239) - ✅ getName (ver. 0.239) - ✅ archive / unarchive (ver. 0.241/0.252) - ✅ allProductsForMassEdit (ver. 0.274) - ✅ getProductsByCategory (ver. 0.274) - ✅ applyDiscountPercent (ver. 0.274) - [ ] is_product_on_promotion - [ ] getFromCache - [ ] getProductImg ### 📋 Do zrobienia - ShopProduct (factory) ## Kolejność refaktoryzacji (priorytet) 1-28: ✅ Cache, Product, Banner, Settings, Dictionaries, ProductArchive, Filemanager, Users, Pages, Integrations, ShopPromotion, ShopCoupon, ShopStatuses, ShopPaymentMethod, ShopTransport, ShopAttribute, ShopProductSets, ShopProducer, ShopProduct (mass_edit), ShopClients, ShopCategory, ShopOrder Nastepne: 29. **ShopProduct (factory)** ## 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 - Wspierane typy pól: text, number, email, password, date, datetime, switch, select, textarea, editor, image, file, hidden, lang_section, color - Obsługa zakładek (vertical) i sekcji językowych (horizontal) - **Do zrobienia**: Przerobić pozostałe kontrolery/formularze (Product, Category, Pages, itd.) Pelna dokumentacja: `docs/FORM_EDIT_SYSTEM.md` ## 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 ``` ## Testowanie ### Framework: PHPUnit ```bash composer test ``` ### Struktura testów ``` tests/ ├── Unit/ │ ├── Domain/ │ │ ├── Article/ArticleRepositoryTest.php │ │ ├── Banner/BannerRepositoryTest.php │ │ ├── Cache/CacheRepositoryTest.php │ │ ├── Coupon/CouponRepositoryTest.php │ │ ├── Dictionaries/DictionariesRepositoryTest.php │ │ ├── Integrations/IntegrationsRepositoryTest.php │ │ ├── PaymentMethod/PaymentMethodRepositoryTest.php │ │ ├── Producer/ProducerRepositoryTest.php │ │ ├── Product/ProductRepositoryTest.php │ │ ├── ProductSet/ProductSetRepositoryTest.php │ │ ├── Promotion/PromotionRepositoryTest.php │ │ ├── Settings/SettingsRepositoryTest.php │ │ ├── ShopStatus/ShopStatusRepositoryTest.php │ │ └── User/UserRepositoryTest.php │ └── admin/ │ └── Controllers/ │ ├── ArticlesControllerTest.php │ ├── DictionariesControllerTest.php │ ├── IntegrationsControllerTest.php │ ├── ProductArchiveControllerTest.php │ ├── SettingsControllerTest.php │ ├── ShopCouponControllerTest.php │ ├── ShopPaymentMethodControllerTest.php │ ├── ShopProducerControllerTest.php │ ├── ShopProductSetsControllerTest.php │ ├── ShopPromotionControllerTest.php │ ├── ShopStatusesControllerTest.php │ └── UsersControllerTest.php └── Integration/ ``` **Lacznie: 338 testow, 1063 asercji** Aktualizacja 2026-02-15 (ver. 0.273): - dodano testy `tests/Unit/Domain/Producer/ProducerRepositoryTest.php` - dodano testy `tests/Unit/admin/Controllers/ShopProducerControllerTest.php` Aktualizacja 2026-02-14 (ver. 0.271): - dodano testy `tests/Unit/Domain/Attribute/AttributeRepositoryTest.php` - dodano testy `tests/Unit/admin/Controllers/ShopAttributeControllerTest.php` Pelna dokumentacja testow: `TESTING.md` --- *Rozpoczęto: 2025-02-05* *Ostatnia aktualizacja: 2026-02-15* *Changelog zmian: `docs/CHANGELOG.md`*