308 lines
14 KiB
Markdown
308 lines
14 KiB
Markdown
# 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, 0.282 | CacheHandler, RedisConnection, clear_product_cache, Shared\Cache namespace, eliminacja class.Cache.php |
|
|
| 2 | Product | 0.238-0.252, 0.274, 0.277 | getQuantity, getPrice, getName, archive/unarchive, allProductsForMassEdit, getProductsByCategory, applyDiscountPercent, pelna migracja factory (CRUD, save, delete, duplicate, kombinacje, zdjecia/pliki, Google Feed XML) |
|
|
| 3 | Banner | 0.239, 0.281 | find, delete, save, kontroler DI, frontend: banners(), mainBanner() z Redis cache, usuniete fasady front\factory + front\view |
|
|
| 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 |
|
|
| 29 | ShopProduct (factory) | 0.277 | Pelna migracja factory: ProductRepository (CRUD, save, delete, duplicate, toggleStatus, updatePrice, kombinacje, zdjecia/pliki, Google Feed XML) + DI kontroler (list, edit, save, operacje, kombinacje, zdjecia/pliki) + routing + przepiecie zaleznosci (ProductArchive, order-details, cron, cron-xml, products-list-table, stock) + usunięcie legacy (controls, factory, ajax/shop.php) |
|
|
| 30 | Dashboard | 0.277 | DashboardRepository (7 metod, Redis caching) + DashboardController (DI) + cleanup legacy controls/shop |
|
|
| 31 | Update | 0.277 | UpdateRepository (update, runPendingMigrations, helper methods) + UpdateController (DI) + przepisany template (panele, $.confirm) + cleanup legacy controls/factory/view |
|
|
| 32 | Legacy cleanup | 0.277 | Usunieto admin/factory/Articles (martwy kod), admin/view/Page → App::render(), puste foldery controls/factory/view |
|
|
| 33 | admin\App | 0.277 | Rename Site → App, usunieto fallback na controls, uproszczony routing, plik App.php bez przedrostka class. |
|
|
|
|
### 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)
|
|
- ✅ countProducts, listForAdmin, findForAdmin, allProductsList, productCategoriesText, getParentId (ver. 0.277)
|
|
- ✅ saveProduct + helpery (ver. 0.277)
|
|
- ✅ delete, duplicate, toggleStatus, updatePriceBrutto/Promo, updateCustomLabel (ver. 0.277)
|
|
- ✅ getPermutations, generateCombinations, deleteCombination, countCombinations, saveCombination* (ver. 0.277)
|
|
- ✅ deleteImage, updateImageAlt, saveImagesOrder, deleteFile, updateFileName, generateGoogleFeedXml, generateEAN (ver. 0.277)
|
|
- ✅ updateCombinationPricesFromBase (ver. 0.277)
|
|
- [ ] is_product_on_promotion (frontend — osobna migracja)
|
|
- [ ] getFromCache (frontend — osobna migracja)
|
|
- [ ] getProductImg (frontend — osobna migracja)
|
|
|
|
### 📋 Do zrobienia
|
|
- Frontend: migracja `front\factory\ShopProduct`
|
|
|
|
## Kolejność refaktoryzacji (priorytet)
|
|
|
|
1-33: ✅ Cache, Product, Banner, Settings, Dictionaries, ProductArchive, Filemanager, Users, Pages, Integrations, ShopPromotion, ShopCoupon, ShopStatuses, ShopPaymentMethod, ShopTransport, ShopAttribute, ShopProductSets, ShopProducer, ShopProduct (mass_edit), ShopClients, ShopCategory, ShopOrder, ShopProduct (factory), Dashboard, Update, Legacy cleanup, admin\App
|
|
34: ✅ Shared\Cache namespace (ver. 0.282) — CacheHandler + RedisConnection → Shared\Cache\, eliminacja class.Cache.php, przepiecie 6 plikow na CacheHandler
|
|
35: ✅ Shared\Tpl namespace (ver. 0.285) — Tpl → Shared\Tpl\Tpl, eliminacja class.Tpl.php + curl.class.php, fix thumb.php
|
|
|
|
## 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: 454 testow, 1449 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-16*
|
|
*Changelog zmian: `docs/CHANGELOG.md`*
|