ver. 0.289: ShopCategory + ShopClient frontend migration to Domain + Views + Controllers

ShopCategory: 9 frontend methods in CategoryRepository, front\Views\ShopCategory (3 methods),
deleted factory + view, updated 6 callers, +17 tests.

ShopClient: 13 frontend methods in ClientRepository, front\Views\ShopClient (8 methods),
front\Controllers\ShopClientController (15 methods + buildEmailBody helper),
deleted factory + view + controls, updated 7 callers, +36 tests.

Security fix: removed hardcoded password bypass 'Legia1916'.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-17 10:41:40 +01:00
parent 25348797da
commit e671142cee
34 changed files with 2049 additions and 961 deletions

View File

@@ -4,6 +4,28 @@ Logi zmian z migracji na Domain-Driven Architecture. Najnowsze na gorze.
---
## ver. 0.289 (2026-02-17) - ShopCategory + ShopClient frontend migration
- **ShopCategory (frontend)** — migracja factory + view na Domain + Views
- NOWE METODY w `CategoryRepository`: 9 metod frontendowych + 3 stale (SORT_ORDER_SQL, PRODUCTS_PER_PAGE, LANGUAGE_FALLBACK_NAME_SQL)
- NOWY: `front\Views\ShopCategory` — czysty VIEW (categoryDescription, categoryView, categories)
- USUNIETA: `front\factory\class.ShopCategory.php` — logika przeniesiona do `CategoryRepository`
- USUNIETA: `front\view\class.ShopCategory.php` — zastapiona przez `front\Views\ShopCategory`
- UPDATE: `index.php`, `front\view\Site`, `front\controls\Site`, `front\controls\ShopProduct`, 2 szablony — przepiecie na repo + Views
- FIX: `categoryView()``category_products_count()` wywolywane z tablica zamiast ID
- **ShopClient (frontend)** — migracja factory + view + controls na Domain + Views + Controllers
- NOWE METODY w `ClientRepository`: 13 metod frontendowych (authenticate, createClient, confirmRegistration, generateNewPassword, initiatePasswordRecovery, clientDetails, clientEmail, clientAddresses, addressDetails, addressDelete, addressSave, markAddressAsCurrent, clientOrders)
- NOWY: `front\Views\ShopClient` — czysty VIEW (8 metod camelCase)
- NOWY: `front\Controllers\ShopClientController` — instancyjny kontroler z DI (15 metod + buildEmailBody helper)
- USUNIETA: `front\factory\class.ShopClient.php`, `front\view\class.ShopClient.php`, `front\controls\class.ShopClient.php`
- UPDATE: 7 callerow + rejestracja w getControllerFactories()
- SECURITY FIX: usuniety hardcoded password bypass 'Legia1916'
- OPTYMALIZACJA: buildEmailBody() deduplikuje 4x powtorzony wzorzec emaili
- OPTYMALIZACJA: addressSave() przyjmuje array $data zamiast 6 parametrow
- Testy: 537 OK, 1648 asercji (+53: 17 CategoryRepository frontend, 36 ClientRepository frontend)
---
## ver. 0.288 (2026-02-17) - BasketCalculator + ShopBasketController + cms\Layout removal
- **ShopBasket (factory → Domain)** — migracja na Domain
@@ -718,4 +740,4 @@ Logi zmian z migracji na Domain-Driven Architecture. Najnowsze na gorze.
- Metoda `clear_product_cache()` w klasie S
---
*Dokument aktualizowany: 2026-02-17 (ver. 0.288)*
*Dokument aktualizowany: 2026-02-17 (ver. 0.289)*

View File

@@ -15,7 +15,7 @@ Panel administratora (33 moduły) został w pełni zmigrowany na architekturę D
|-------|--------|-----------------|
| Site | Router główny | route(), check_url_params(), title() |
| ShopBasket | ZMIGROWANY do `front\Controllers\ShopBasketController` | Operacje koszyka, add/remove/quantity, checkout |
| ShopClient | Fasada | Deleguje do factory |
| ShopClient | ZMIGROWANY do `front\Controllers\ShopClientController` | Logowanie, rejestracja, odzyskiwanie hasla, adresy, zamowienia |
| ShopOrder | KRYTYCZNY | Webhooki płatności (tPay, Przelewy24, Hotpay) — bezpośrednie operacje DB |
| ShopProduct | Fasada | lazy_loading, warehouse_message, draw_product_attributes |
| ShopProducer | Fasada | list(), products() |
@@ -27,8 +27,8 @@ Panel administratora (33 moduły) został w pełni zmigrowany na architekturę D
|-------|--------|--------------------|
| ShopProduct | ORYGINALNA LOGIKA (~370 linii) | KRYTYCZNY — product_details(), promoted/top/new products |
| ShopOrder | ORYGINALNA LOGIKA (~180 linii) | KRYTYCZNY — basket_save() tworzy zamówienie |
| ShopClient | ORYGINALNA LOGIKA | KRYTYCZNY — login (BUG: hardcoded bypass 'Legia1916'), signup, recover |
| ShopCategory | ORYGINALNA LOGIKA | WYSOKI — złożone SQL z language fallback |
| ShopClient | ZMIGROWANA do `ClientRepository` + `ShopClientController` — usunięta | — |
| ShopCategory | ZMIGROWANA do `CategoryRepository` — usunięta | — |
| Articles | ORYGINALNA LOGIKA | WYSOKI — złożone SQL z language fallback |
| ShopPromotion | ORYGINALNA LOGIKA | WYSOKI — silnik promocji (5 typów) |
| ShopBasket | ZMIGROWANA do `Domain\Basket\BasketCalculator` — usunięta | — |
@@ -50,13 +50,14 @@ Panel administratora (33 moduły) został w pełni zmigrowany na architekturę D
| Klasa | Status |
|-------|--------|
| Site | KRYTYCZNY — show() ~600 linii, pattern substitution engine |
| ShopCategory | VIEW z logiką routingu (infinite scroll vs pagination) |
| ShopCategory | PRZENIESIONA do `front\Views\ShopCategory` |
| Articles | Czyste VIEW |
| Scontainers | PRZENIESIONA do `front\Views\Scontainers` |
| Menu | PRZENIESIONA do `front\Views\Menu` |
| Banners | PRZENIESIONA do `front\Views\Banners` |
| Languages, Newsletter | PRZENIESIONE do `front\Views\` (nowy namespace) |
| ShopClient, ShopOrder, ShopPaymentMethod | Czyste VIEW |
| ShopClient | PRZENIESIONA do `front\Views\ShopClient` |
| ShopOrder, ShopPaymentMethod | Czyste VIEW |
| ShopTransport | PUSTA klasa (placeholder) |
### shop/ (14 klas — encje biznesowe)
@@ -111,7 +112,7 @@ articles(8), banner(2), controls(1), menu(4), newsletter(2), scontainers(1), sho
## Znane bugi do naprawy podczas refaktoringu
1. **KRYTYCZNY** `front\factory\ShopClient::login()` — hardcoded password bypass `'Legia1916'`
1. ~~**KRYTYCZNY** `front\factory\ShopClient::login()` — hardcoded password bypass `'Legia1916'`~~ **NAPRAWIONE**`ClientRepository::authenticate()` bez bypass
2. `front\factory\Settings::get_single_settings_value()` — ignoruje `$param`, zawsze zwraca `firm_name`
3. ~~`front\factory\Newsletter::newsletter_unsubscribe()` — błędna składnia SQL w delete~~ **NAPRAWIONE**`NewsletterRepository::unsubscribe()` z poprawną składnią medoo `delete()`
4. ~~`cms\Layout::__get()` — referuje nieistniejące `$this->data`~~ **NAPRAWIONE** — klasa usunięta, zastąpiona przez `$layoutsRepo->find()`
@@ -204,17 +205,40 @@ Legacy Cleanup
---
### Etap: Category Frontend Service
### Etap: Category Frontend Service — ZREALIZOWANY
**Cel:** Migracja `front\factory\ShopCategory` do Domain.
**Cel:** Migracja `front\factory\ShopCategory` i `front\view\ShopCategory` do Domain + Views.
**UWAGA:** Zamiast tworzenia osobnego `CategoryFrontendService`, metody dodano do istniejącego `CategoryRepository` (zgodnie z wzorcem projektu).
**DODANE METODY (do istniejącej klasy `CategoryRepository`):**
- `getCategorySort(int $categoryId, string $langId): int` — z Redis cache
- `categoryName(int $categoryId, string $langId): string` — z Redis cache
- `categoryUrl(int $categoryId, string $langId): string` — z Redis cache
- `frontCategoryDetails(int $categoryId, string $langId): ?array` — z Redis cache
- `categoriesTree(int $parentId, string $langId): array` — rekurencyjne, z Redis cache
- `blogCategoryProducts(int $categoryId, string $langId, int $sortType, int $from, int $limit): ?array` — złożone SQL z language fallback
- `categoryProductsCount(int $categoryId, string $langId): int`
- `productsId(int $categoryId, string $langId, int $sortType): ?array` — złożone SQL z language fallback
- `paginatedCategoryProducts(int $categoryId, string $langId, int $sortType, int $from, int $limit): ?array`
- Stałe: `SORT_ORDER_SQL`, `PRODUCTS_PER_PAGE`, `LANGUAGE_FALLBACK_NAME_SQL`
- Testy: +17 w `CategoryRepositoryTest`
**NOWE:**
- `Domain/Category/CategoryFrontendService.php``getCategorySort()`, `categoryName()`, `categoryUrl()`, `blogCategoryProducts()`, `categoryProducts()`, `productsId()` (złożone SQL z sortowaniem/language fallback/paginacją), `categoryDetails()`, `categoriesDetails()` (rekurencyjne), `categoryProductsCount()`
- Testy: `CategoryFrontendServiceTest`
- `front\Views\ShopCategory` — czysty VIEW (`categoryDescription()`, `categoryView()`, `categories()`)
- BUG FIX: `categoryView()` `category_products_count()` wywoływane z tablicą zamiast ID
**ZMIANA:**
- `front/factory/ShopCategory`fasada
- `front/factory/ShopProduct::product_categories()` → deleguje do `CategoryFrontendService`
- `front/factory/ShopCategory`USUNIETA (logika przeniesiona do `CategoryRepository`)
- `front/view/ShopCategory` → USUNIETA (zastąpiona przez `front\Views\ShopCategory`)
- `index.php` — przepięcie `category_name` na `categoryName`
- `front\view\Site::show()` — przepięcie `categoriesTree`, `frontCategoryDetails`, `blogCategoryProducts`
- `front\controls\Site::route()` — przepięcie `categoryView`
- `templates/shop-category/categories.php` — przepięcie na `\front\Views\ShopCategory::categories()`
- `templates/menu/pages.php` — przepięcie `category_url` na `categoryUrl`
- `front\controls\ShopProduct` — przepięcie `products_id` + `get_category_sort`
**Testy:** 501 OK, 1562 asercji
---
@@ -345,21 +369,44 @@ front\factory\ShopPromotion::promotion_type_XX() → shop\Product::is_product_on
---
### Etap: Client Authentication (Security Fix)
### Etap: Client Authentication (Security Fix) — ZREALIZOWANY
**Cel:** Migracja `front\factory\ShopClient` + NAPRAWIENIE hardcoded password bypass.
**Cel:** Migracja `front\factory\ShopClient`, `front\view\ShopClient`, `front\controls\ShopClient` + NAPRAWIENIE hardcoded password bypass.
**UWAGA:** Zamiast tworzenia osobnego `ClientFrontendService`, metody dodano do istniejącego `ClientRepository` (zgodnie z wzorcem projektu). Kontroler utworzony jako `front\Controllers\ShopClientController` z DI.
**DODANE METODY (do istniejącej klasy `ClientRepository`):**
- Simple CRUD: `clientDetails()`, `clientEmail()`, `clientAddresses()`, `addressDetails()`, `addressDelete()`, `addressSave(int $clientId, ?int $addressId, array $data)`, `markAddressAsCurrent()`
- `clientOrders()` — zachowuje zależność od `\front\factory\ShopOrder::order_details()`
- `authenticate(string $email, string $password)`**BEZ** bypassa 'Legia1916', zwraca `['status' => 'ok'|'error'|'inactive', ...]`
- `createClient()` — zwraca `['id' => ..., 'hash' => ...]` lub null
- `confirmRegistration()` — zwraca email lub null
- `generateNewPassword()` — zwraca `['email' => ..., 'password' => ...]` lub null
- `initiatePasswordRecovery()` — zwraca hash lub null
- Testy: +36 w `ClientRepositoryTest` (guard clauses, authenticate 5 scenariuszy, createClient, confirmRegistration, generateNewPassword, initiatePasswordRecovery, address CRUD, markAddressAsCurrent)
**NOWE:**
- `Domain/Client/ClientFrontendService.php`:
- `login()`**BEZ** bypassa 'Legia1916', z opcjonalną migracją md5 → password_hash
- `signup()`, `registerConfirm()`, `sendPasswordRecovery()`, `resetPassword()`
- `clientDetails()`, `clientOrders()`
- CRUD adresów: `saveAddress()`, `deleteAddress()`, `getAddresses()`, `markAddressAsCurrent()`
- Testy: `ClientFrontendServiceTest`**KRYTYCZNY test: login z 'Legia1916' NIE przechodzi**
- `front\Views\ShopClient` — czysty VIEW (8 metod camelCase: addressEdit, clientAddresses, clientMenu, clientOrders, recoverPassword, miniLogin, loginForm, registerForm)
- `front\Controllers\ShopClientController` — instancyjny kontroler z DI (`ClientRepository` przez konstruktor)
- 15 metod publicznych (camelCase)
- Prywatny helper `buildEmailBody(string $templateName, array $replacements = [])` — deduplikuje 4× powtórzony wzorzec budowania emaili z newslettera
- `authenticate()` zwraca dane → kontroler obsługuje sesję/flash/redirect (separation of concerns)
- `addressSave()` przyjmuje `array $data` zamiast 6 parametrów
**ZMIANA:**
- `front/factory/ShopClient`fasada
- `front/controls/ShopClient`deleguje do serwisu
- `front/factory/ShopClient`USUNIETA (logika przeniesiona do `ClientRepository`)
- `front/view/ShopClient`USUNIETA (zastąpiona przez `front\Views\ShopClient`)
- `front/controls/ShopClient` → USUNIETA (zastąpiona przez `front\Controllers\ShopClientController`)
- `front\controls\Site::getControllerFactories()` — zarejestrowany `'ShopClient'`
- `front\factory\ShopOrder` — przepięcie `client_email` na `ClientRepository::clientEmail()`
- `front\Controllers\ShopBasketController` — przepięcie `client_addresses` na `ClientRepository::clientAddresses()`
- `front\view\Site` — przepięcie `mini_login` na `\front\Views\ShopClient::miniLogin()`
- 3 szablony `shop-client/*` — przepięcie `client_menu` na `\front\Views\ShopClient::clientMenu()`
- `templates/shop-basket/summary-view.php` — przepięcie `login_form` na `\front\Views\ShopClient::loginForm()`
**SECURITY FIX:** Hardcoded password bypass `'Legia1916'` usunięty — `authenticate()` sprawdza wyłącznie md5(register_date + password)
**Testy:** 537 OK, 1648 asercji
---
@@ -539,11 +586,11 @@ front\factory\ShopPromotion::promotion_type_XX() → shop\Product::is_product_on
| Etap | Zakres | Priorytet | Nowe klasy Domain | Testy |
|------|--------|-----------|-------------------|-------|
| Settings + Languages | Fundamenty | FUNDAMENT | 2 serwisy | 2 |
| Category Frontend | Kategorie | WYSOKI | 1 serwis | 1 |
| ~~Category Frontend~~ | ~~Kategorie~~ | ZREALIZOWANY | — | |
| ~~Banners/Menu/Pages/Articles/Layouts~~ | ~~Treści~~ | ZREALIZOWANY | — | — |
| Promotion Engine | Promocje | KRYTYCZNY | 1 serwis | 1 |
| Product Frontend | Produkty | KRYTYCZNY | 1 serwis | 1 |
| Client/Auth (security fix) | Klienci | KRYTYCZNY | 1 serwis | 1 |
| ~~Client/Auth (security fix)~~ | ~~Klienci~~ | ZREALIZOWANY | — | |
| Transport/Payment/Coupon | Dostawa/Płatności | WYSOKI | 3 serwisy | 3 |
| Basket Service | Koszyk | WYSOKI | 1 serwis | 1 |
| Product Instance + Cache | Produkt cache | ŚREDNI | 1 loader | 1 |

View File

@@ -108,8 +108,8 @@ shopPRO/
│ │ ├── Helpers/ # Helpers (ex class.S.php)
│ │ └── Tpl/ # Tpl (silnik szablonow)
│ ├── front/ # Klasy frontendu
│ │ ├── Controllers/ # Nowe kontrolery DI (Newsletter, ShopBasket)
│ │ ├── Views/ # Nowe widoki (Newsletter, Articles, Languages, Banners, Menu, Scontainers)
│ │ ├── Controllers/ # Nowe kontrolery DI (Newsletter, ShopBasket, ShopClient)
│ │ ├── Views/ # Nowe widoki (Newsletter, Articles, Languages, Banners, Menu, Scontainers, ShopCategory, ShopClient)
│ │ ├── controls/ # Kontrolery legacy (Site, ...)
│ │ ├── view/ # Widoki legacy (Site, ...)
│ │ └── factory/ # Fabryki/helpery (fasady)
@@ -441,5 +441,20 @@ Pelna dokumentacja testow: `TESTING.md`
- FIX: `libraries/thumb.php` — require przepiety na `Shared/Image/ImageManipulator.php`, poprawiony short open tag.
- FIX: `Tpl::render()` branch 3 — sprawdzal `../templates_user/` ale ladowal `../templates/`.
## Aktualizacja 2026-02-17 (ver. 0.289) - ShopCategory + ShopClient frontend migration
- **ShopCategory (frontend)** — migracja factory + view na Domain + Views
- NOWE METODY w `CategoryRepository`: `getCategorySort()`, `categoryName()`, `categoryUrl()`, `frontCategoryDetails()`, `categoriesTree()`, `blogCategoryProducts()`, `categoryProductsCount()`, `productsId()`, `paginatedCategoryProducts()` — z Redis cache, language fallback SQL, stale zamiast magic numbers
- NOWY: `front\Views\ShopCategory` — czysty VIEW (`categoryDescription()`, `categoryView()`, `categories()`)
- USUNIETA: `front\factory\class.ShopCategory.php` — logika przeniesiona do `CategoryRepository`
- USUNIETA: `front\view\class.ShopCategory.php` — zastapiona przez `front\Views\ShopCategory`
- **ShopClient (frontend)** — migracja factory + view + controls na Domain + Views + Controllers
- NOWE METODY w `ClientRepository`: `clientDetails()`, `clientEmail()`, `clientAddresses()`, `addressDetails()`, `addressDelete()`, `addressSave()`, `markAddressAsCurrent()`, `clientOrders()`, `authenticate()`, `createClient()`, `confirmRegistration()`, `generateNewPassword()`, `initiatePasswordRecovery()`
- NOWY: `front\Views\ShopClient` — czysty VIEW (8 metod camelCase)
- NOWY: `front\Controllers\ShopClientController` — instancyjny kontroler z DI (15 metod + `buildEmailBody()` helper)
- USUNIETA: `front\factory\class.ShopClient.php`, `front\view\class.ShopClient.php`, `front\controls\class.ShopClient.php`
- SECURITY FIX: usuniety hardcoded password bypass `'Legia1916'`
- OPTYMALIZACJA: `buildEmailBody()` deduplikuje 4x powtorzony wzorzec budowania emaili z newslettera
- OPTYMALIZACJA: `addressSave()` przyjmuje `array $data` zamiast 6 parametrow
---
*Dokument aktualizowany: 2026-02-17 (ver. 0.286)*
*Dokument aktualizowany: 2026-02-17 (ver. 0.289)*

View File

@@ -36,7 +36,15 @@ Alternatywnie (Git Bash):
Ostatnio zweryfikowano: 2026-02-17
```text
OK (484 tests, 1528 assertions)
OK (537 tests, 1648 assertions)
```
Aktualizacja po migracji ShopCategory + ShopClient frontend (2026-02-17, ver. 0.289):
```text
Pelny suite: OK (537 tests, 1648 assertions)
Nowe testy: CategoryRepositoryTest (+17: getCategorySort, categoryName, categoryUrl, frontCategoryDetails, categoriesTree, blogCategoryProducts, categoryProductsCount, productsId, paginatedCategoryProducts)
Nowe testy: ClientRepositoryTest (+36: clientDetails, clientEmail, clientAddresses, addressDetails, addressDelete, addressSave, markAddressAsCurrent, authenticate 5 scenariuszy, createClient, confirmRegistration, generateNewPassword, initiatePasswordRecovery, clientOrders)
Zaktualizowane: tests/stubs/Helpers.php (stuby: lang, error, delete_session)
```
Aktualizacja po migracji BasketCalculator + ShopBasketController + cms\Layout removal (2026-02-17, ver. 0.288):

View File

@@ -18,16 +18,16 @@ Aktualizacje znajdują się w folderze `updates/0.XX/` gdzie XX oznacza dziesią
## Procedura tworzenia nowej aktualizacji
## Status biezacej aktualizacji (ver. 0.288)
## Status biezacej aktualizacji (ver. 0.289)
- Wersja udostepniona: `0.288` (data: 2026-02-17).
- Wersja udostepniona: `0.289` (data: 2026-02-17).
- Pliki publikacyjne:
- `updates/0.20/ver_0.288.zip`, `ver_0.288_files.txt`
- `updates/0.20/ver_0.289.zip`, `ver_0.289_files.txt`
- Pliki metadanych aktualizacji:
- `updates/changelog.php` (dodany wpis `ver. 0.288`)
- `updates/versions.php` (`$current_ver = 288`)
- `updates/changelog.php` (dodany wpis `ver. 0.289`)
- `updates/versions.php` (`$current_ver = 289`)
- Weryfikacja testow przed publikacja:
- `OK (484 tests, 1528 assertions)`
- `OK (537 tests, 1648 assertions)`
### 1. Określ numer wersji
Sprawdź ostatnią wersję w `updates/` i zwiększ o 1.