- Introduced new `SettingsRepository` and `CacheRepository` classes in the `autoload\Domain` namespace. - Updated `SettingsController` in the `admin\Controllers` namespace to enhance settings management. - Added new templates for settings in `admin\templates\settings` and `admin\templates\site`. - Improved overall structure and organization of settings-related files.
9.7 KiB
9.7 KiB
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)
│ │ ├── 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) - fasada → factory
│ ├── Cache/
│ │ └── CacheRepository.php # ✅ Zmigrowane (clearCache)
│ ├── Order/
│ ├── Category/
│ └── ...
│
├── admin/ # Warstwa administratora (istniejący katalog!)
│ ├── Controllers/ # Nowe kontrolery - namespace \admin\Controllers\
│ │ ├── BannerController.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 toadmin/(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
// ❌ 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
// 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ć
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
🔄 W trakcie
-
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
- Nowa klasa:
- ✅ 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
- Nowa metoda:
- ✅ 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
- Nowa metoda:
- is_product_on_promotion() - NASTĘPNA 👉
- ✅ get_product_quantity() - ZMIGROWANE (2025-02-05) 🎉
-
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\Bannersdziała jako niezależny fallback - Stara factory
admin\factory\Bannerszachowana bez zmian (fallback) - Aktualizacja: ver. 0.239
- Nowa klasa:
- ✅ BannerRepository - ZMIGROWANE (2026-02-05) 🎉
-
Settings (migracja kontrolera - krok pośredni)
- ✅ SettingsRepository - ZMIGROWANE (2026-02-05) 🎉
- Nowa klasa:
Domain\Settings\SettingsRepository(saveSettings, getSettings) - Krok pośredni: fasada nad
admin\factory\Settings(docelowo DI z $db) - Nowy kontroler:
admin\Controllers\SettingsController(DI, instancyjny) - Testy: ✅ 3 testy (instancja, metody)
- Stary kontroler
admin\controls\Settingszachowany jako fallback - Aktualizacja: ver. 0.240
- Nowa klasa:
- ✅ 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
- Nowa klasa:
- ✅ SettingsRepository - ZMIGROWANE (2026-02-05) 🎉
📋 Do zrobienia
- Order
- Category
- ShopAttribute
- ShopProduct (factory)
Testowanie
Framework: PHPUnit
Instalacja:
composer require --dev phpunit/phpunit
Struktura testów
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
└── Integration/
Łącznie: 29 testów, 60 asercji
Przykład testu
// 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
- Single Responsibility - jedna klasa = jedna odpowiedzialność
- Open/Closed - otwarty na rozszerzenia, zamknięty na modyfikacje
- Liskov Substitution - podklasy mogą zastąpić nadklasy
- Interface Segregation - wiele małych interfejsów
- Dependency 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
// ✅ 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:
autoload/{namespace}/class.{ClassName}.php(legacy)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
composer require --dev phpstan/phpstan
vendor/bin/phpstan analyse autoload/Domain
Kolejność refaktoryzacji (priorytet)
- Cache ✅
- Product (w trakcie)
- ✅ getQuantity (ver. 0.238)
- ✅ getPrice (ver. 0.239)
- ✅ getName (ver. 0.239)
- is_product_on_promotion - NASTĘPNA 👉
- getFromCache
- getProductImg
- Banner ✅ (pełna migracja kontrolera, ver. 0.239)
- Settings ✅ (migracja kontrolera - krok pośredni, ver. 0.240)
- Order
- Category
- ShopAttribute
Rozpoczęto: 2025-02-05 Ostatnia aktualizacja: 2026-02-05