Refactor code structure for improved readability and maintainability

This commit is contained in:
2026-02-18 08:28:02 +01:00
parent 99d78abea9
commit 29821bccf2
11 changed files with 2266 additions and 2524 deletions

View File

@@ -8,7 +8,6 @@ Gdy użytkownik napisze `KONIEC PRACY`, wykonaj kolejno:
2. Aktualizacja dokumentacji technicznej, jeśli zmiany tego wymagają:
- `docs/DATABASE_STRUCTURE.md`
- `docs/PROJECT_STRUCTURE.md`
- `docs/FRONTEND_REFACTORING_PLAN.md`
- `docs/FORM_EDIT_SYSTEM.md`
- `docs/CHANGELOG.md`
- `docs/TESTING.md`
@@ -22,14 +21,7 @@ Przed rozpoczęciem implementacji sprawdź aktualną zawartość:
- `docs/DATABASE_STRUCTURE.md`
- `docs/PROJECT_STRUCTURE.md`
- `docs/REFACTORING_PLAN.md`
- `docs/FRONTEND_REFACTORING_PLAN.md`
- `docs/CHANGELOG.md`
- `docs/TESTING.md`
To ma pomóc zachować spójność zmian i dokumentacji.
## INNE
Przejdźmy teraz do refaktoringu wszystkiego co związane z https://shoppro.project-dc.pl/admin/shop_product/, nowe widoki, klasy (usuwanie starych), poprawa routingu, przeszukanie innych klas pod względem zależności. Zapisz plan i przedstaw mi go a po akceptacji realizuj krok po kroku w trybie Human In The Loop

View File

@@ -4,7 +4,7 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
## Project Overview
shopPRO is a PHP e-commerce platform with an admin panel and customer-facing storefront. It uses Medoo ORM (`$mdb`), Redis caching, and is undergoing a migration from legacy architecture to Domain-Driven Design with Dependency Injection.
shopPRO is a PHP e-commerce platform with an admin panel and customer-facing storefront. It uses Medoo ORM (`$mdb`), Redis caching, and a Domain-Driven Design architecture with Dependency Injection (migration from legacy architecture complete).
## PHP Version Constraint
@@ -50,21 +50,27 @@ shopPRO/
│ ├── Domain/ # Business logic repositories (\Domain\)
│ ├── Shared/ # Shared utilities (\Shared\)
│ │ ├── Cache/ # CacheHandler, RedisConnection
│ │ ├── Email/ # Email (PHPMailer wrapper)
│ │ ├── Helpers/ # Helpers (formerly class.S.php)
│ │ ├── Html/ # Html utility
│ │ ├── Image/ # ImageManipulator
│ │ └── Tpl/ # Template engine
│ ├── admin/ # Admin panel layer
│ │ ── Controllers/ # DI controllers (\admin\Controllers\)
│ ├── front/ # Frontend layer
│ │ ├── App.php # Frontend router (\front\App)
│ │ ├── LayoutEngine.php # Layout engine (\front\LayoutEngine)
│ │ ── Controllers/ # DI controllers (\front\Controllers\)
│ └── Views/ # Static views (\front\Views\)
└── shop/ # EMPTY — all legacy classes migrated to Domain\
│ │ ── App.php # Admin router (\admin\App)
│ ├── Controllers/ # DI controllers (\admin\Controllers\) — 28 controllers
│ │ ├── Support/ # TableListRequestFactory, Forms/FormRequestHandler, Forms/FormFieldRenderer
│ │ ├── Validation/ # FormValidator
│ │ ── ViewModels/ # Forms/ (FormEditViewModel, FormField, FormTab, FormAction, FormFieldType), Common/ (PaginatedTableViewModel)
│ └── front/ # Frontend layer
├── App.php # Frontend router (\front\App)
│ ├── LayoutEngine.php # Layout engine (\front\LayoutEngine)
│ ├── Controllers/ # DI controllers (\front\Controllers\) — 8 controllers
│ └── Views/ # Static views (\front\Views\) — 11 view classes
├── admin/ # Admin panel
│ ├── templates/ # Admin view templates
│ └── layout/ # Admin CSS/JS/icons
├── templates/ # Frontend view templates
├── libraries/ # Third-party libraries
├── libraries/ # Third-party libraries (Medoo, RedBeanPHP, PHPMailer)
├── tests/ # PHPUnit tests
│ ├── bootstrap.php
│ ├── stubs/ # Test stubs (CacheHandler, Helpers, ShopProduct)
@@ -89,25 +95,27 @@ Custom autoloader in each entry point (not Composer autoload at runtime). Tries
2. `autoload/{namespace}/{ClassName}.php` (PSR-4 style, fallback)
### Namespace Conventions (case-sensitive on Linux!)
- `\Domain\``autoload/Domain/` (uppercase D — new directory)
- `\admin\Controllers\``autoload/admin/Controllers/` (lowercase a — existing directory)
- `\Domain\``autoload/Domain/` (uppercase D)
- `\admin\Controllers\``autoload/admin/Controllers/` (lowercase a)
- `\Shared\``autoload/Shared/`
- `\front\``autoload/front/`
- ~~`\shop\`~~ → `autoload/shop/` (EMPTY — all classes migrated to `\Domain\`)
- Do NOT use `\Admin\` (uppercase A) — the server directory is `admin/` (lowercase)
- `\shop\` namespace is **deleted** — all 12 legacy classes migrated to `\Domain\`, `autoload/shop/` directory removed
### Domain-Driven Architecture (migration complete for admin + frontend)
### Domain-Driven Architecture (migration complete)
All modules use this pattern:
All legacy directories (`admin/controls/`, `admin/factory/`, `admin/view/`, `front/controls/`, `front/view/`, `front/factory/`, `shop/`) have been deleted. All modules now use this pattern:
**Domain Layer** (`autoload/Domain/{Module}/`):
- `{Module}Repository.php` — data access, business logic, Redis caching
- Constructor DI with `$db` (Medoo instance)
- Methods serve both admin and frontend (shared Domain, no separate services)
**Domain Modules**: Article, Attribute, Banner, Basket, Cache, Category, Client, Coupon, Dashboard, Dictionaries, Integrations, Languages, Layouts, Newsletter, Order, Pages, PaymentMethod, Producer, Product, ProductSet, Promotion, Scontainers, Settings, ShopStatus, Transport, Update, User
**Admin Controllers** (`autoload/admin/Controllers/`):
- DI via constructor (repositories injected)
- Wired in `admin\App::route()` via `$newControllers` map
- Wired in `admin\App::getControllerFactories()`
**Frontend Controllers** (`autoload/front/Controllers/`):
- DI via constructor
@@ -133,12 +141,20 @@ All modules use this pattern:
- Full schema: `docs/DATABASE_STRUCTURE.md`
### Form Edit System
Universal form system for admin edit views. Uses ViewModels (`FormEditViewModel`, `FormField`, `FormTab`, `FormAction`), validation (`FormValidator`), and rendering (`FormFieldRenderer`). Template: `admin/templates/components/form-edit.php`. Docs: `docs/FORM_EDIT_SYSTEM.md`.
Universal form system for admin edit views. Docs: `docs/FORM_EDIT_SYSTEM.md`.
- **ViewModels** (`admin\ViewModels\Forms\`): `FormEditViewModel`, `FormField`, `FormTab`, `FormAction`, `FormFieldType`
- **Validation**: `admin\Validation\FormValidator`
- **Rendering**: `admin\Support\Forms\FormFieldRenderer`, `admin\Support\Forms\FormRequestHandler`
- **Template**: `admin/templates/components/form-edit.php`
- **Table lists**: `admin\Support\TableListRequestFactory` + `admin\ViewModels\Common\PaginatedTableViewModel`
### Caching
- Redis via `\Shared\Cache\CacheHandler` (singleton `RedisConnection`)
- Key pattern for products: `shop\product:{id}:{lang}:{permutation_hash}`
- Clear product cache: `\Shared\Helpers\Helpers::clear_product_cache($id)`
- Pattern delete: `CacheHandler::deletePattern("shop\\product:{$id}:*")`
- Default TTL: 86400 (24h)
- Data is serialized — requires `unserialize()` after `get()`
- Config: `config.php` (`$config['redis']`)
## Code Patterns
@@ -161,6 +177,11 @@ $repo = new \Domain\Example\ExampleRepository($mdb);
$controller = new \admin\Controllers\ExampleController($repo);
```
### Medoo ORM pitfalls
- `$mdb->delete($table, $where)` takes **2 arguments**, NOT 3 — has caused bugs
- `$mdb->get()` returns `null` when no record, NOT `false`
- After `$mdb->insert()`, check `$mdb->id()` to confirm success
### File naming
- New classes: `ClassName.php` (no `class.` prefix)
- Legacy classes: `class.ClassName.php` (leave until migrated)
@@ -175,7 +196,7 @@ $controller = new \admin\Controllers\ExampleController($repo);
When user says **"KONIEC PRACY"**, execute in order:
1. Run tests
2. Update documentation if needed: `docs/DATABASE_STRUCTURE.md`, `docs/PROJECT_STRUCTURE.md`, `docs/FRONTEND_REFACTORING_PLAN.md`, `docs/FORM_EDIT_SYSTEM.md`, `docs/CHANGELOG.md`, `docs/TESTING.md`
2. Update documentation if needed: `docs/DATABASE_STRUCTURE.md`, `docs/PROJECT_STRUCTURE.md`, `docs/FORM_EDIT_SYSTEM.md`, `docs/CHANGELOG.md`, `docs/TESTING.md`
3. Prepare update package per `docs/UPDATE_INSTRUCTIONS.md`
4. Commit
5. Push
@@ -184,12 +205,9 @@ Before starting implementation, review current state of docs (see AGENTS.md for
## Key Documentation
- `docs/MEMORY.md` — project memory: known issues, confirmed patterns, ORM pitfalls, caching conventions
- `docs/PROJECT_STRUCTURE.md`detailed project structure and module status
- `docs/REFACTORING_PLAN.md` — Domain migration plan and status
- `docs/FRONTEND_REFACTORING_PLAN.md` — frontend migration plan (mostly complete)
- `docs/LEGACY_SHOP_REFACTORING_PLAN.md` — plan usunięcia 12 legacy klas z `autoload/shop/` (UKOŃCZONY — wszystkie 12 klas usunięte)
- `docs/PROJECT_STRUCTURE.md`current architecture, layers, cache, entry points, integrations
- `docs/DATABASE_STRUCTURE.md` — full database schema
- `docs/TESTING.md` — test suite status and history
- `docs/TESTING.md` — test suite guide and structure
- `docs/FORM_EDIT_SYSTEM.md` — form system architecture
- `docs/CHANGELOG.md` — version history
- `docs/UPDATE_INSTRUCTIONS.md` — how to build client update packages

2049
docs/CLASS_CATALOG.md Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1,634 +0,0 @@
# Plan refaktoryzacji frontendu shopPRO
## Kontekst
Panel administratora (33 moduły) został w pełni zmigrowany na architekturę Domain + DI + Controllers (ver. 0.2370.277). Teraz kolej na frontend: klasy `front/`, `shop/`, `cms/`, klasy utility z `autoload/` oraz szablony `templates/`.
**Cel:** przenieść logikę biznesową z warstwy frontendowej do warstwy domenowej (`Domain/`), zachowując kompatybilność wsteczną przez fasady. Zastosować te same wzorce co w adminie (DI, repozytoria/serwisy, testy PHPUnit).
---
## Inwentaryzacja — co istnieje
### front/controls/ (8 klas — handlery requestów)
| Klasa | Status | Logika biznesowa |
|-------|--------|-----------------|
| Site | ZMIGROWANY do `front\App` — usunięty | route(), checkUrlParams(), title(), pageTitle(), getControllerFactories() |
| ShopBasket | ZMIGROWANY do `front\Controllers\ShopBasketController` | Operacje koszyka, add/remove/quantity, checkout |
| ShopClient | ZMIGROWANY do `front\Controllers\ShopClientController` | Logowanie, rejestracja, odzyskiwanie hasla, adresy, zamowienia |
| ShopOrder | ZMIGROWANY do `front\Controllers\ShopOrderController` | Webhooki płatności + order details |
| ShopProduct | ZMIGROWANY — usunięty | logika w ProductRepository + szablony |
| ShopProducer | ZMIGROWANY do `front\Controllers\ShopProducerController` | list(), products() |
| ShopCoupon | ZMIGROWANY do `front\Controllers\ShopCouponController` | use_coupon(), delete_coupon() |
| Newsletter | ZMIGROWANY do `front\Controllers\NewsletterController` | signin(), confirm(), unsubscribe() |
### ~~front/factory/~~ (20 klas — USUNIĘTY w ver. 0.292, wszystkie zmigrowane do Domain)
| Klasa | Status | Priorytet migracji |
|-------|--------|--------------------|
| ShopProduct | ZMIGROWANA do `ProductRepository` — usunięta | — |
| ShopOrder | ZMIGROWANA do `OrderRepository` — usunięta | — |
| ShopClient | ZMIGROWANA do `ClientRepository` + `ShopClientController` — usunięta | — |
| ShopCategory | ZMIGROWANA do `CategoryRepository` — usunięta | — |
| Articles | ZMIGROWANA do `ArticleRepository` — usunięta | — |
| ShopPromotion | ZMIGROWANA do `PromotionRepository` — usunięta | — |
| ShopBasket | ZMIGROWANA do `Domain\Basket\BasketCalculator` — usunięta | — |
| ShopTransport | ZMIGROWANA do `TransportRepository` — usunięta | — |
| ShopPaymentMethod | ZMIGROWANA do `PaymentMethodRepository` — usunięta | — |
| ShopStatuses | ZMIGROWANA do `ShopStatusRepository` — usunięta | — |
| Scontainers | ZMIGROWANA (Domain) — usunięta | — |
| Newsletter | ZMIGROWANA (Domain) — usunięta | — |
| Settings | ZMIGROWANA do `SettingsRepository` — usunięta | — |
| Languages | USUNIĘTA — przepięta na Domain | — |
| Layouts | USUNIETA — przepieta na Domain | — |
| Banners | USUNIETA — przepieta na Domain | — |
| Menu | USUNIETA — przepieta na Domain | — |
| Pages | USUNIETA — przepieta na Domain | — |
| ShopAttribute | ZMIGROWANA (Domain) — usunięta | — |
| ShopCoupon | ZMIGROWANA do `CouponRepository` — usunięta | — |
### front/view/ (12 klas — renderowanie)
| Klasa | Status |
|-------|--------|
| Site | ZMIGROWANY do `front\LayoutEngine` — usunięty |
| 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 | PRZENIESIONA do `front\Views\ShopClient` |
| ShopOrder | ZMIGROWANA do `ShopOrderController` — usunięta |
| ShopPaymentMethod | USUNIĘTA (pusta klasa) |
| ShopTransport | USUNIĘTA (pusta klasa) |
### shop/ (14 klas — encje biznesowe)
| Klasa | Linii | Status | Priorytet |
|-------|-------|--------|-----------|
| Product | ~950 | KRYTYCZNY — pricing, atrybuty, search, cache, permutacje | KRYTYCZNY |
| Order | ~500+ | KRYTYCZNY — statusy, Apilo sync, emaile, webhooki | KRYTYCZNY |
| Promotion | ~200 | WYSOKI — matching aktywnych promocji + delegacja do factory | WYSOKI |
| Basket | ~80 | ŚREDNI — walidacja stanów magazynowych | ŚREDNI |
| Category | ~60 | NISKI — proste zapytania, pusty konstruktor | NISKI |
| Search | ~80 | NISKI — wrapper na szablony | NISKI |
| Coupon | ~60 | NISKI — niekompletne metody | NISKI |
| Transport | ~30 | NISKI — transport_list() | NISKI |
| PaymentMethod | — | USUNIETA — callery na PaymentMethodRepository | — |
| Producer | — | USUNIETA (callery na ProducerRepository) | — |
| ProductSet | — | ZMIGROWANA (fasada do Domain) | — |
| ProductAttribute | ~100 | OK — dobry caching | — |
| ProductCustomField | ~50 | OK — Redis caching | — |
| Shop | ~30 | OK — utility do cen | — |
### autoload/ root (klasy utility)
| Klasa | Linii | Status |
|-------|-------|--------|
| S | ~960 | PRZENIESIONA do Shared\Helpers\Helpers — 12 metod usunieto, bug fix |
| Tpl | ~90 | PRZENIESIONA do `Shared\Tpl\Tpl` — DRY render(), bug fix branch 3, ~135 plikow przepietych |
| CacheHandler | ~50 | ZMIGROWANY do `Shared\Cache\CacheHandler` — wrappery usuniete |
| RedisConnection | ~40 | ZMIGROWANY do `Shared\Cache\RedisConnection` — wrappery usuniete |
| Email | ~100 | OK — PHPMailer wrapper (drobne poprawki) |
| Log | ~20 | OK — audit logging |
| DbModel | — | USUNIETA — logika wbudowana w `shop\Promotion` |
| Cache | ~50 | USUNIETA — zastapiona CacheHandler (Redis) w ver. 0.282 |
| Html | ~80 | OK — form helpers |
| Image | ~100 | OK — GD wrapper |
| Mobile_Detect | — | USUNIETA — przestarzala detekcja UA, zastapiona responsive design |
### cms/ (1 klasa)
| Klasa | Status |
|-------|--------|
| Layout | USUNIETA — zastapiona przez `$layoutsRepo->find()` |
### templates/ (75 plików w 15 modułach)
articles(8), banner(2), controls(1), menu(4), newsletter(2), scontainers(1), shop-basket(9), shop-category(6), shop-client(8), shop-coupon(1), shop-order(3), shop-producer(3), shop-product(12), shop-search(3), site(11)
### Entry points
- `index.php` — główny frontend (autoload, sesja, DB, routing, DOM post-processing)
- `ajax.php` — AJAX handler (koszyk, transport, kontakt)
- `api.php` — REST API (Ekomi CSV export)
- `download.php` — pobieranie plików
- `cron-turstmate.php` — TrustMate integracja
---
## Znane bugi do naprawy podczas refaktoringu
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`~~ **NAPRAWIONE** — klasa usunięta, `SettingsRepository::getSingleValue()` z poprawnym `$param`
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()`
5. `shop\Search` — typo w use: `shop\Produt` (brak 'c')
---
## Kolejność migracji (graf zależności)
```
Settings, Languages (liście — brak zależności)
Banners, Menu, Pages, Articles, Layouts (zależą od Languages)
Category (zależy od Languages)
Promotion (zależy od Category — rozbicie circular dep)
Product Frontend (zależy od Category, Promotion, Languages)
Client/Auth (standalone + security fix)
Transport, Payment, Coupon (frontend serwisy)
Basket (zależy od Product, Promotion, Transport, Coupon)
Order Creation (zależy od Basket, Product, Transport, Payment)
Payment Webhooks (zależy od Order)
shop\Order instance + Apilo (zależy od Order Operations)
shop\Product instance + cache (zależy od ProductFrontendService)
Frontend App + Controllers (nowa warstwa DI)
Site Layout Engine (zależy od wszystkiego)
Entry Point Unification (index.php, ajax.php)
Legacy Cleanup
```
---
## Etapy migracji
### Etap: Settings + Languages — ZREALIZOWANY
**Cel:** Dodac metody frontendowe (z cache Redis) do istniejacych repozytoriow Domain.
**DODANE METODY (do istniejacych klas):**
- `Domain/Settings/SettingsRepository``allSettings($skipCache)`, `getSingleValue($param)` (FIX: uzywa poprawnie $param)
- `Domain/Languages/LanguagesRepository``defaultLanguage()`, `activeLanguages()`, `translations($lang)`
- Testy: dopisane do `SettingsRepositoryTest` (6 testow), `LanguagesRepositoryTest` (7 testow)
**ZMIANA:**
- `front/factory/Settings` → fasada delegujaca do `SettingsRepository`
- `front/factory/Languages` → fasada delegujaca do `LanguagesRepository`
- `tests/bootstrap.php` — uzupelniony stub CacheHandler o `get()`/`set()`/`exists()`
**BUG FIX:** `get_single_settings_value()` — zmiana `['param' => 'firm_name']` na `['param' => $param]`
---
### Etap: Newsletter Frontend — ZREALIZOWANY
**Cel:** Przeniesienie logiki frontendowej z `front\factory\Newsletter` do `Domain\Newsletter\NewsletterRepository`. Migracja view do nowego namespace `front\Views`.
**DODANE METODY (do istniejącej klasy `NewsletterRepository`):**
- `unsubscribe(string $hash): bool` — FIX: poprawna składnia medoo `delete()` (2 args zamiast 3)
- `confirmSubscription(string $hash): bool`
- `getHashByEmail(string $email): ?string`
- `removeByEmail(string $email): bool`
- `signup(string $email, string $serverName, bool $ssl, array $settings): bool`
- `sendQueued(int $limit, string $serverName, bool $ssl, string $unsubscribeLabel): bool`
- Konstruktor rozszerzony o opcjonalne: `ArticleRepository`, `NewsletterPreviewRenderer` (lazy-init)
- Testy: 10 nowych testów w `NewsletterRepositoryTest`
**ZMIANA:**
- `front/factory/Newsletter` → USUNIĘTA (logika przeniesiona do `NewsletterRepository`)
- `front/view/Newsletter` → USUNIĘTA, zastąpiona przez `front/Views/Newsletter` (nowy namespace, bez `class.` prefix)
- `front/controls/Newsletter` → thin wrapper na `NewsletterRepository`
- `front/view/Site::show()``\front\Views\Newsletter::render()`
- `index.php``$newsletterRepo->sendQueued()`
- `front/factory/ShopClient` (4 miejsca) → `NewsletterRepository::templateByName()`
- `tests/bootstrap.php` — dodane stuby: `S::email_check()`, `S::get_session()`, `S::set_session()`
**BUG FIX:** `newsletter_unsubscribe()` — medoo `delete()` wywoływane z 3 argumentami zamiast 2
---
### Etap: Category Frontend Service — ZREALIZOWANY
**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:**
- `front\Views\ShopCategory` — czysty VIEW (`categoryDescription()`, `categoryView()`, `categories()`)
- BUG FIX: `categoryView()``category_products_count()` wywoływane z tablicą zamiast ID
**ZMIANA:**
- `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
---
### Etap: Articles Frontend — ZREALIZOWANY
**Cel:** Migracja `front\factory\Articles`, `front\view\Articles` i statycznych metod `class.Article` do Domain + Views.
**DODANE METODY (do istniejącej klasy `ArticleRepository`):**
- `articleDetailsFrontend(int $articleId, string $langId): ?array` — z copy_from fallback + Redis cache
- `articlesIds(int $pageId, string $langId, int $limit, int $sortType, int $from): ?array` — złożone SQL z language fallback + sortowanie + LIMIT + Redis cache
- `pageArticlesCount(int $pageId, string $langId): int` — COUNT z Redis cache
- `pageArticles(array $page, string $langId, int $bs): array` — paginacja
- `news(int $pageId, int $limit, string $langId): ?array` — inline sort_type query (eliminacja zależności od `front\factory\Pages`)
- `articleNoindex(int $articleId, string $langId): bool` — jawny $langId zamiast `global $lang`
- `topArticles(int $pageId, int $limit, string $langId): ?array` — ORDER BY views DESC + Redis cache
- `newsListArticles(int $pageId, int $limit, string $langId): ?array` — ORDER BY date_add DESC + CacheHandler (Redis) zamiast legacy `\Cache`
**NOWE:**
- `front\Views\Articles` — czysty VIEW + utility:
- Renderowanie: `fullArticle()`, `miniatureArticlesList()`, `entryArticlesList()`, `fullArticlesList()`, `news()`, `newsList()`
- Utility: `generateTableOfContents()`, `processHeaders()`, `generateHeadersIds()`, `getImage()`
**ZMIANA:**
- `front\factory\Articles` → fasada (10 metod delegujących do repo + Views)
- `front\view\Articles` → fasada (5 metod delegujących do repo + Views)
- `class.Article` → USUNIĘTA (encja + metody statyczne przeniesione do `ArticleRepository` + `front\Views\Articles`)
- `front\view\Site::show()` → 5 sekcji przepiętych na repo + Views
- `front\controls\Site::route()` → single article + page_type switch przepięte na repo + Views
- 5 szablonów `templates/articles/*``\front\Views\Articles::`
- `tests/bootstrap.php` — dodany stub `S::is_array_fix()`
- Testy: 13 nowych w `ArticleRepositoryTest` (450 OK, 1431 asercji)
---
### Etap: Banners Frontend — ZREALIZOWANY
**Cel:** Migracja `front\factory\Banners` i `front\view\Banners` do Domain + Views.
**DODANE METODY (do istniejącej klasy `BannerRepository`):**
- `banners(string $langId): ?array` — aktywne banery (home_page=0), filtrowanie dat, Redis cache, plaski format languages
- `mainBanner(string $langId): ?array` — baner glowny (home_page=1), filtrowanie dat, Redis cache, plaski format languages
**NOWE:**
- `front\Views\Banners` — czysty VIEW (`banners()`, `mainBanner()`)
**ZMIANA:**
- `front\factory\Banners` → USUNIETA (logika przeniesiona do `BannerRepository`)
- `front\view\Banners` → USUNIETA (zastapiona przez `front\Views\Banners`)
- `front\view\Site::show()` — przepiecie na `$bannerRepo->banners()` / `$bannerRepo->mainBanner()` + `\front\Views\Banners::`
- Testy: 4 nowe w `BannerRepositoryTest` (454 OK, 1449 asercji)
---
### Etap: Menu, Pages, Layouts Frontend Services — ZREALIZOWANY
**Cel:** Migracja pozostałych fabryk "liściowych".
**UWAGA:** Zamiast tworzenia osobnych FrontendService, metody dodano do istniejących repozytoriów Domain (zgodnie z wzorcem projektu).
**DODANE METODY (do istniejących klas):**
- `Domain/Layouts/LayoutsRepository``categoryDefaultLayoutId()`, `getDefaultLayout()`, `getProductLayout()`, `getArticleLayout()`, `getCategoryLayout()`, `getActiveLayout()` (Redis cache, 3-level fallback)
- `Domain/Pages/PagesRepository``frontPageDetails()`, `frontPageSort()`, `frontMainPageId()`, `frontLangUrl()`, `frontMenuDetails()`, `frontMenuPages()` (Redis cache, rekurencja)
- Testy: +8 w `LayoutsRepositoryTest`, +8 w `PagesRepositoryTest`
**NOWE:**
- `front\Views\Menu` — czysty VIEW (`pages()`, `menu()`)
**ZMIANA:**
- `front/factory/Layouts` → USUNIETA (logika w `LayoutsRepository`)
- `front/factory/Menu` → USUNIETA (logika w `PagesRepository`)
- `front/factory/Pages` → USUNIETA (logika w `PagesRepository`)
- `front/view/Menu` → USUNIETA (zastapiona przez `front\Views\Menu`)
- `templates/menu/submenu.php` → USUNIETA (martwy kod)
- `front\view\Site::show()` — przepiecie na `$layoutsRepo` + `$pagesRepo`
- `front\controls\Site::check_url_params()` — przepiecie na `$pagesRepo->frontPageDetails()`
- `index.php` — przepiecie na `$pagesRepo->frontPageDetails()`
- `Shared\Helpers\Helpers::htacces()` — optymalizacja 3→1 wywolan
- Szablony `templates/menu/*` — przepiecie na `\front\Views\Menu::`
- `templates/site/languages.php` — przepiecie na `$pagesRepo->frontLangUrl()`
**BUG FIX:** `frontPageDetails()` — null `$lang_id` przy wczesnym `check_url_params()` (usuniety string type hint + cast + `?? ''` na call site)
**Testy:** 470 OK, 1484 asercji
---
### Etap: Promotion Engine (rozbicie circular dependency)
**Cel:** Przeniesienie silnika promocji do Domain. Rozbicie cyklicznej zależności `shop\Promotion ↔ front\factory\ShopPromotion`.
**Obecna zależność cykliczna:**
```
shop\Promotion::find_promotion() → front\factory\ShopPromotion::promotion_type_XX()
front\factory\ShopPromotion::promotion_type_XX() → shop\Product::is_product_on_promotion()
```
**Rozwiązanie:** Wszystko w jednym serwisie `PromotionFrontendService`.
**NOWE:**
- `Domain/Promotion/PromotionFrontendService.php`:
- `getActivePromotions()` (z `shop\Promotion`)
- `applyPromotions(array $basket)` (z `shop\Promotion::find_promotion()`)
- `private applyType01..05()` (z `front\factory\ShopPromotion`)
- `private isProductOnPromotion()` (z `shop\Product` — proste zapytanie)
- Testy: `PromotionFrontendServiceTest` (7 typów promocji + brak aktywnych)
**ZMIANA:**
- `shop/Promotion` → fasada do `PromotionFrontendService::applyPromotions()`
- `front/factory/ShopPromotion` → fasada
---
### Etap: Product Frontend Service
**Cel:** Migracja `front\factory\ShopProduct` i statycznych metod `shop\Product` do Domain.
**NOWE:**
- `Domain/Product/ProductFrontendService.php`:
- Z `front\factory\ShopProduct`: `productDetails()` (~330 linii z Redis), `promotedProducts()`, `topProducts()`, `newProducts()`, `productUrl()`, `getMinimalPrice()`, `isProductActive()`, `getProductSku()`, `getProductEan()`, `productImage()`, `productWp()`, `randomProducts()`, `warehouseMessageZero()`, `warehouseMessageNonzero()`
- Z `shop\Product` (statyczne): `isProductOnPromotion()`, `getProductImg()`, `getProductUrl()`, `addVisit()`, `productSetsForBasket()`, `searchProductsByName()`, `searchProductByNameAjax()`
- Testy: `ProductFrontendServiceTest`
**ZMIANA:**
- `front/factory/ShopProduct` → fasada
- `shop/Product` statyczne metody → fasady do `ProductFrontendService`
**UWAGA:** Konstruktor `shop\Product`, `getFromCache()`, `calculate_basket_product_price()` — zostają na razie (instancyjne, używane w szablonach). Migracja w etapie "Product Instance + Cache".
---
### Etap: Client Authentication (Security Fix) — ZREALIZOWANY
**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:**
- `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` → 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
---
### Etap: Transport, Payment, Coupon Frontend Services
**Cel:** Frontend serwisy dla transportu, płatności i kuponów.
**NOWE:**
- `Domain/Transport/TransportFrontendService.php``transportMethods()` (filtrowanie WP, free delivery), `transportCost()`, `transportDetails()`
- `Domain/PaymentMethod/PaymentMethodFrontendService.php``activePaymentMethods()`, `paymentMethodsByTransport()`, `paymentMethodDetails()`
- `Domain/Coupon/CouponFrontendService.php``validateCoupon()`, `applyCoupon()`, `markCouponUsed()`
- Testy: 3 pliki testowe
**ZMIANA:**
- `front/factory/ShopTransport` → fasada
- `front/factory/ShopCoupon` → fasada
- `shop/Coupon` → fasada
- `shop/Transport` → fasada
---
### Etap: Basket Service
**Cel:** Migracja logiki koszyka do `Domain\Basket\BasketService`.
**NOWE:**
- `Domain/Basket/BasketService.php`:
- `addProduct()`, `removeProduct()`, `changeQuantity()`, `increaseQuantity()`, `decreaseQuantity()`
- `summaryPrice()`, `countProducts()`, `countProductsText()`
- `validateStock()` (z `shop\Basket::check_product_quantity_in_stock()`)
- `calculateProductPrice()` (z `shop\Product::calculate_basket_product_price()` ~112 linii)
- Testy: `BasketServiceTest` (pricing z promocjami/kuponami, walidacja stanów)
**ZMIANA:**
- `front/factory/ShopBasket` → fasada
- `front/controls/ShopBasket` — wewnętrznie używa `BasketService`
- `shop/Basket` → fasada
- `shop/Product::calculate_basket_product_price()` → fasada
---
### Etap: shop\Product Instance + Cache
**Cel:** Refaktoring konstruktora `shop\Product` i `getFromCache()`.
**NOWE:**
- `Domain/Product/ProductDataLoader.php`:
- `loadFull(int $productId, ?string $langId, ?string $permutationHash)` — ładowanie pełnych danych produktu
- `loadCached()` — Redis cache wrapper
- Testy: `ProductDataLoaderTest`
**ZMIANA:**
- `shop/Product` — konstruktor i `getFromCache()` delegują do `ProductDataLoader`
- ArrayAccess interface zachowany (szablony dalej używają `$product->property`)
---
### Etap: Order Creation Frontend Service — ZREALIZOWANY (ver. 0.290)
**Cel:** Migracja `front\factory\ShopOrder::basket_save()` (~180 linii).
**ZREALIZOWANE:** (wg wytycznej "NIE tworzymy osobnych FrontendService/AdminService" — metody dodane do istniejącego `OrderRepository`)
- `Domain/Order/OrderRepository.php` — dodane metody frontendowe:
- `createFromBasket()` — tworzenie zamówienia z koszyka (21 parametrów, pełna logika basket_save)
- `generateOrderNumber()` — format YYYY/MM/NNN
- `orderDetailsFrontend()`, `findIdByHash()`, `findHashById()`
- `front/Controllers/ShopOrderController.php` — kontroler z DI (OrderRepository)
- Testy: `OrderRepositoryTest` (9 nowych), `ShopOrderControllerTest` (3 nowe)
**USUNIĘTE:**
- `front/factory/class.ShopOrder.php`
- `front/controls/class.ShopOrder.php`
- `front/view/class.ShopOrder.php`
**CALLERY ZAKTUALIZOWANE:**
- `ShopBasketController` — DI OrderRepository, zmiana basket_save/order_hash
- `ClientRepository::clientOrders()` — OrderRepository::orderDetailsFrontend()
- `shop\Order::order_resend_confirmation_email()` — OrderRepository::orderDetailsFrontend()
- `cron-turstmate.php` — OrderRepository::orderDetailsFrontend()
---
### Etap: Payment Webhook Service — ZREALIZOWANY (ver. 0.290)
**Cel:** Wyodrębnienie webhooków płatności z `front\controls\ShopOrder`.
**ZREALIZOWANE:** (webhooki przeniesione do `front\Controllers\ShopOrderController` — nadal używają `\shop\Order` do operacji statusów/płatności)
- `ShopOrderController::paymentStatusTpay()` — przeniesione 1:1
- `ShopOrderController::paymentStatusPrzelewy24pl()` — ujednolicone z tpay (set_as_paid + update_status zamiast ręcznego $mdb->update)
- `ShopOrderController::paymentStatusHotpay()` — analogiczna zamiana na \shop\Order metody
**UWAGA:** `\shop\Order` nie jest jeszcze zmigrowany — osobny etap (Order Instance + Apilo Service)
---
### Etap: shop\Order Instance + Apilo Service
**Cel:** Refaktoring `shop\Order` instancyjnych metod + wyodrębnienie integracji Apilo.
**NOWE:**
- `Domain/Integrations/ApiloService.php`:
- `syncPayment()`, `syncStatus()`, `processQueue()`
- `private queueSync()`, `private loadQueue()`, `private saveQueue()`
- `Domain/Order/OrderOperationsService.php`:
- `setAsPaid()`, `setAsUnpaid()`, `updateStatus()`, `sendStatusChangeEmail()`, `resendConfirmationEmail()`
- Testy: `ApiloServiceTest`, `OrderOperationsServiceTest`
**ZMIANA:**
- `shop/Order` instancyjne metody → fasady do `OrderOperationsService`
- Konstruktor i ArrayAccess bez zmian
---
### Etap: Frontend App + Controllers (DI layer)
**Cel:** Stworzenie `front\App` (wzorowanego na `admin\App`) z mapą kontrolerów i DI.
**NOWE:**
- `autoload/front/App.php``render()`, `handleAjax()`, `getControllerFactories()` (DI wiring)
- `autoload/front/Controllers/ShopBasketController.php` — DI z `BasketService`, `ProductFrontendService`
- `autoload/front/Controllers/ShopOrderController.php` — DI z `OrderFrontendService`, `PaymentWebhookService`
- `autoload/front/Controllers/ShopClientController.php` — DI z `ClientFrontendService`
- Testy: 3 pliki testowe kontrolerów
**ZMIANA:**
- `front/controls/ShopBasket`, `ShopOrder`, `ShopClient` → delegują do nowych kontrolerów
---
### Etap: Site Layout Engine
**Cel:** Refaktoring `front\view\Site::show()` (~600 linii) na testowalny `LayoutEngine`.
**NOWE:**
- `autoload/front/View/LayoutEngine.php`:
- `resolveLayout(array $page, array $params)` — wybór layoutu (product > category > article > page > default)
- `processPatterns(string $html, array $context)` — zamiana tagów szablonowych
- Osobne prywatne metody: `replaceCategories()`, `replaceProducts()`, `replaceMenus()`, `replaceLanguageTags()`, `replaceBanners()`, `replaceArticles()`, `replaceContainers()`, `replaceMetaTags()`, etc.
- Testy: `LayoutEngineTest`
**ZMIANA:**
- `front/view/Site::show()` → thin wrapper na `LayoutEngine`
---
### Etap: Entry Point Unification
**Cel:** Ujednolicenie bootstrapu `index.php` i `ajax.php`.
**NOWE:**
- `autoload/front/Bootstrap.php``init()` (autoloader, config, sesja, DB, lang/settings)
- `autoload/front/PostProcessor.php` — ekstrakcja DOM manipulacji z `index.php` (GTM, Facebook Pixel, WebP, lazy loading)
**ZMIANA:**
- `index.php` → uproszczony: `Bootstrap::init()``App::render()``PostProcessor::process()`
- `ajax.php` → uproszczony: `Bootstrap::init()``App::handleAjax()`
---
### Etap: Legacy Cleanup
**Cel:** Finalne porządki.
**USUNIĘCIE:**
- Martwy kod `eval()` dla `[PHP]` bloków (jeśli nieużywany)
- ~~`class.Cache.php` (legacy file-based)~~ **ZREALIZOWANE** w ver. 0.282
- Pusta klasa `front\view\ShopTransport`
**ZMIANA:**
- Dodanie `@deprecated` do wszystkich metod-fasad w `front/factory/`, `front/controls/`, `shop/`
- PHPDoc do wszystkich nowych klas Domain z `@since`
- Aktualizacja `tests/bootstrap.php`
- BUG FIX: `shop\Search` — typo `shop\Produt``shop\Product`
- ~~BUG FIX: `front\factory\Newsletter::newsletter_unsubscribe()` — poprawka SQL~~ **ZREALIZOWANE** w etapie Newsletter Frontend
---
## Podsumowanie
| Etap | Zakres | Priorytet | Nowe klasy Domain | Testy |
|------|--------|-----------|-------------------|-------|
| Settings + Languages | Fundamenty | FUNDAMENT | 2 serwisy | 2 |
| ~~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~~ | 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 |
| Order Creation | Zamówienia | WYSOKI | 1 serwis | 1 |
| Payment Webhooks | Webhooki | WYSOKI | 1 serwis | 1 |
| Order Instance + Apilo | Zamówienie + Apilo | ŚREDNI | 2 serwisy | 2 |
| Frontend App + Controllers | DI layer | WYSOKI | App + 3 kontrolery | 3 |
| Layout Engine | Silnik layoutu | ŚREDNI | 1 engine | 1 |
| Entry Point Unification | Entry points | ŚREDNI | Bootstrap + PostProcessor | 1 |
| Legacy Cleanup | Porządki | NISKI | — | — |
**Łącznie:** 16 etapów, ~24 nowe klasy Domain, ~25 plików testowych
### Wzorce do przestrzegania (z migracji admin)
- Konstruktor DI z `$db` (medoo)
- CacheHandler (Redis) dla cachingu — unifikacja (usunięcie starego `Cache`)
- Fasady w `shop\*` i `front\factory\*` dla kompatybilności wstecznej
- Testy PHPUnit z mockami medoo
- Namespace `\Domain\*``autoload/Domain/*/`
- Namespace `\front\Controllers\``autoload/front/Controllers/`
- **Klasy Domain sa wspolne dla admin i frontendu** — NIE tworzymy osobnych FrontendService/AdminService. Metody frontendowe (z cache Redis) dodajemy do istniejacych repozytoriow/serwisow Domain. Klasy sa ladowane lazy (instancja tworzona dopiero przy wywolaniu), wiec nie wplywaja na wydajnosc.
### Nazewnictwo plikow
- Nowe klasy: `NazwaKlasy.php` (bez przedrostka `class.`)
- Legacy: `class.NazwaKlasy.php` — zostawiamy do momentu migracji danej klasy
- Autoloader obsluguje oba formaty (probuje `class.X.php`, potem `X.php`)
- Nowe katalogi z duzej litery: `Views/`, `Controllers/` (legacy: `view/`, `controls/`, `factory/`)
### Statyczne vs instancyjne metody
- **Statyczne** — gdy klasa jest bezstanowa (brak konstruktora, brak properties, brak DI). Czyste funkcje: dane wchodzą, wynik wychodzi. Przykład: klasy VIEW (`front\Views\Languages::render($data)`, `front\view\Banners::banners($data)`)
- **Instancyjne** — gdy klasa ma zależności do wstrzyknięcia (repozytoria, serwisy) lub trzyma stan. Przykład: kontrolery z DI (`ShopProductController` z `ProductRepository`, `LanguagesRepository`)
### Weryfikacja po każdym etapie
1. `composer test` (pełny suite PHPUnit)
2. Manualne sprawdzenie frontendu: strona główna, kategoria, produkt, koszyk, zamówienie
3. Sprawdzenie AJAX: dodawanie do koszyka, zmiana transportu, kupon
4. Sprawdzenie webhooków płatności (tPay, Przelewy24, Hotpay)

View File

@@ -1,234 +0,0 @@
# Plan refaktoryzacji `autoload/shop/` — usunięcie legacy klas
## Kontekst
Katalog `autoload/shop/` zawierał **12 legacy klas** (~2 363 linii kodu), które pełniły rolę fasad/wrapperów nad warstwą `Domain\`. Wszystkie klasy zostały usunięte — logika przeniesiona do warstwy `Domain\` / `Shared\`, wywołania zaktualizowane.
**Status: UKOŃCZONE** (wszystkie 12 klas usunięte, katalog `autoload/shop/` pusty)
## Status
| Faza | Klasy | Status |
|------|-------|--------|
| 1 | Transport, ProductSet, Coupon | ✅ Ukończona |
| 2 | Shop, Search, Basket | ✅ Ukończona |
| 3 | ProductCustomField, Category, ProductAttribute | ✅ Ukończona |
| 4 | Promotion | ✅ Ukończona |
| 5 | Order, Product | ✅ Ukończona |
---
## Faza 1 — Trywialne fasady (0 logiki do migracji)
### 1.1 `class.Transport.php` ✅ (~31 linii)
**Jedyne zewnętrzne użycie:**
- `admin\Controllers\ShopOrderController.php``\shop\Transport::transport_list()`
**Plan:**
- Dodać metodę `allActiveOrdered()` do `Domain\Transport\TransportRepository` (odpowiednik `transport_list()`)
- Zamienić wywołanie w `ShopOrderController`
- Usunąć `class.Transport.php`
### 1.2 `class.ProductSet.php` ✅ (~49 linii)
**Jedyne zewnętrzne użycie:**
- `admin\Controllers\ShopProductController.php:224``\shop\ProductSet::sets_list()`
**Plan:**
- `ProductSetRepository::allSets()` już istnieje — zamienić wywołanie na `$this->productSetRepo->allSets()`
- Wstrzyknąć `ProductSetRepository` do `ShopProductController` (jeśli jeszcze nie jest)
- Usunąć `class.ProductSet.php`
### 1.3 `class.Coupon.php` ✅ (~84 linii)
**Zewnętrzne użycia (3×):**
- `shop\class.Order.php:171``new \shop\Coupon($id)` (do przeniesienia w fazie Order)
- `front\Controllers\ShopOrderController.php:139``new \shop\Coupon($id)`
- `admin\Controllers\ShopOrderController.php:170``new \shop\Coupon($id)`
**Plan:**
- `CouponRepository::findByName()` / `find()` już istnieje — dodać `findById(int $id): ?array` jeśli brak
- Zamienić `new \shop\Coupon($id)``$this->couponRepo->findById($id)` w obu kontrolerach
- Użycie w `class.Order.php` — rozwiąże się w fazie Order
- Usunąć `class.Coupon.php`
---
## Faza 2 — Proste wrappery (minimalna logika do przeniesienia)
### 2.1 `class.Shop.php` ✅ (~39 linii) — utility cenowe
**Zewnętrzne użycia (~24× w szablonach):**
- `templates/shop-product/product.php`, `product-mini.php`
- `templates/shop-search/product-search.php`
- `templates/shop-basket/alert-product-sets.php`
- `templates/controls/alert-product-sets.php`
**Plan:**
- Przenieść `shortPrice()` i `isWholeNumber()` do `Shared\Helpers\Helpers` jako metody statyczne
- Zamienić `\shop\Shop::shortPrice()``\Shared\Helpers\Helpers::shortPrice()` we wszystkich szablonach (replace_all)
- Usunąć `class.Shop.php`
### 2.2 `class.Search.php` ✅ (~70 linii)
**Jedyne zewnętrzne użycie:**
- `front\LayoutEngine.php:337``\shop\Search::simple_form()`
**Plan:**
- Przenieść `simple_form()` do `front\Views\ShopSearch` (nowa klasa View, statyczna)
- Przenieść `search_results()` i `search_products()` do `front\Controllers\ShopSearchController` lub odpowiedniej istniejącej lokalizacji
- Zamienić wywołanie w `LayoutEngine`
- Usunąć `class.Search.php`
- Poprawić bug: `use shop\Produt;` (literówka — brakuje 'c')
### 2.3 `class.Basket.php` ✅ (~92 linii)
**Zewnętrzne użycia (6× w `ShopBasketController`):**
- `validate_basket()` — prosta walidacja tablicy sesji
- `check_product_quantity_in_stock()` — sprawdzenie stanów magazynowych
**Plan:**
- Przenieść obie metody do `Domain\Basket\BasketCalculator` (już istnieje)
- Zamienić wywołania w `ShopBasketController`
- Usunąć `class.Basket.php`
---
## Faza 3 — Klasy z logiką cache/atrybutów
### 3.1 `class.ProductCustomField.php` ✅ (~74 linii)
**Zewnętrzne użycia (2×):**
- `Domain\Order\OrderRepository.php:643``\shop\ProductCustomField::getFromCache()`
- `templates/shop-basket/_partials/product-custom-fields.php:3``\shop\ProductCustomField::getFromCache()`
**Plan:**
- Dodać `findCached(int $id): ?array` do `Domain\Product\ProductRepository` (lub nowy `ProductCustomFieldRepository`)
- Zamienić wywołania w OrderRepository i szablonie
- Usunąć `class.ProductCustomField.php`
### 3.2 `class.Category.php` ✅ (~84 linii)
**Zewnętrzne użycia (2×):**
- `index.php:225``\shop\Category::get_category_products_id()` (FB Pixel)
- `templates/shop-category/category.php:19``\shop\Category::get_subcategory_by_category()`
**Plan:**
- `CategoryRepository::productsId()` prawdopodobnie istnieje — sprawdzić i użyć lub dodać
- Dodać `subcategoriesCached(int $categoryId): array` do `CategoryRepository`
- Zamienić wywołania
- Usunąć `class.Category.php`
### 3.3 `class.ProductAttribute.php` ✅ (~119 linii)
**Zewnętrzne użycia (3 lokalizacje):**
- `shop\class.Product.php` — użycia wewnętrzne (rozwiążą się w fazie Product)
- `admin/templates/shop-product/product-combination.php:32``getAttributeName()`, `get_value_name()`
- `templates/shop-product/_partial/product-attribute.php:13``get_value_name()`
**Plan:**
- `AttributeRepository::getAttributeNameById()` i `getAttributeValueById()` już istnieją
- Dodać brakujące metody do `AttributeRepository`: `isValueDefault()`, `getAttributeOrder()`, `getAttributeNameByValue()` (z Redis cache)
- Zamienić wywołania w szablonach
- Usunąć `class.ProductAttribute.php`
---
## Faza 4 — Klasy z logiką promocji
### 4.1 `class.Promotion.php` ✅ (~107 linii)
**Zewnętrzne użycia (3 lokalizacje):**
- `front\Controllers\ShopBasketController.php` (6×) → `\shop\Promotion::find_promotion()`
- `admin\Controllers\ShopPromotionController.php``::$condition_type`, `::$discount_type`
**Plan:**
- Przenieść `get_active_promotions()` do `PromotionRepository` (z Redis cache)
- Przenieść `find_promotion()` do `PromotionRepository` — orkiestracja logiki applyType*
- Przenieść stałe `$condition_type` / `$discount_type` jako stałe klasowe do `PromotionRepository`
- Zamienić wywołania w `ShopBasketController` i `ShopPromotionController`
- Usunąć `class.Promotion.php`
---
## Faza 5 — Duże klasy z wieloma zależnościami
### 5.1 `class.Order.php` ✅ (~562 linii)
**Główna logika do migracji:**
- `OrderAdminService` ma już: `setOrderAsPaid()`, `setOrderAsUnpaid()`, `changeStatus()`, `resendConfirmationEmail()`, `saveOrderByAdmin()`, `deleteOrder()`, `saveNotes()`
- **Brakuje:** logika Apilo sync (`process_apilo_sync_queue()`, `sync_apilo_payment()`, `sync_apilo_status()`, queue management)
- **Brakuje:** `send_status_change_email()` (ale może być zintegrowane w `changeStatus()`)
**Plan:**
1. Sprawdzić, czy `OrderAdminService` obsługuje już Apilo sync (metoda `sendOrderToApilo()` istnieje)
2. Przenieść `process_apilo_sync_queue()` + kolejkę Apilo do `Domain\Integrations\ApiloService` (lub do `IntegrationsRepository`)
3. Przenieść `send_status_change_email()` do `OrderAdminService` (jeśli nie jest częścią `changeStatus()`)
4. Usunąć referencję do `new \shop\Coupon()` — użyć `CouponRepository` (z fazy 1.3)
5. Zaktualizować `cron.php` (jeśli woła `process_apilo_sync_queue`)
6. Usunąć `class.Order.php`
### 5.2 `class.Product.php` ✅ (~952 linii) — NAJWIĘKSZA KLASA
**Stan:** Większość logiki zmigowana do `ProductRepository`, ale klasa pełni rolę entity z ArrayAccess (używana w szablonach jako `$product['name']`).
**Metody do przeniesienia:**
- `getFromCache()` — cache wrappera entity → przenieść do `ProductRepository::findCached()`
- `getDefaultCombinationPrices()``ProductRepository`
- `generateSubtitleFromAttributes()``ProductRepository`
- `getProductDataBySelectedAttributes()``ProductRepository`
- `is_product_on_promotion()``ProductRepository`
- `product_sets_when_add_to_basket()``ProductSetRepository`
- `add_visit()``ProductRepository`
- `getProductImg()` / `getProductUrl()``ProductRepository`
- `searchProductsByName()` / `searchProductByNameAjax()` / `searchProductsByNameCount()``ProductRepository`
- `is_stock_0_buy()``ProductRepository`
- `get_product_permutation_quantity_options()``ProductRepository`
- `calculate_basket_product_price()``Domain\Basket\BasketCalculator`
- `get_product_id_by_attributes()` / `get_product_permutation_hash()` / `get_product_attributes()``ProductRepository` lub `AttributeRepository`
- `array_cartesian()` / `permutations()``ProductRepository` (helper prywatny)
- `generate_sku_code()``ProductRepository`
- `product_meta()``ProductRepository`
**Kluczowy problem:** szablony używają `$product['field']` przez ArrayAccess. Po migracji szablony będą dostawać zwykłe `array` z `ProductRepository` — to jest kompatybilne, bo `$product['field']` działa tak samo na tablicy.
**Plan:**
1. Etapami przenosić metody statyczne do `ProductRepository` / `AttributeRepository`
2. Przenieść `calculate_basket_product_price()` do `BasketCalculator`
3. Zamienić `Product::getFromCache()``ProductRepository::findCached()` (zwraca tablicę)
4. Zaktualizować szablony i kontrolery
5. Usunąć `class.Product.php`
---
## Pliki do modyfikacji (podsumowanie)
| Plik | Zmiany |
|------|--------|
| `autoload/Domain/Transport/TransportRepository.php` | + `allActiveOrdered()` |
| `autoload/Domain/Basket/BasketCalculator.php` | + `validateBasket()`, `checkStock()`, `calculateProductPrice()` |
| `autoload/Domain/Promotion/PromotionRepository.php` | + `getActivePromotions()`, `findPromotion()`, stałe |
| `autoload/Domain/Product/ProductRepository.php` | + ~15 metod z class.Product.php |
| `autoload/Domain/Attribute/AttributeRepository.php` | + `isValueDefault()`, `getAttributeOrder()`, `getAttributeNameByValue()` |
| `autoload/Domain/Category/CategoryRepository.php` | + `subcategoriesCached()`, `categoryProductIds()` |
| `autoload/Domain/Order/OrderAdminService.php` | + email statusu, sprawdzenie Apilo |
| `autoload/Domain/Integrations/` | + `ApiloSyncService` (queue Apilo) |
| `autoload/Domain/Coupon/CouponRepository.php` | + `findById()` |
| `autoload/Shared/Helpers/Helpers.php` | + `shortPrice()`, `isWholeNumber()` |
| `autoload/front/Views/ShopSearch.php` | NOWY — `simple_form()` |
| `autoload/front/LayoutEngine.php` | zamiana `\shop\Search``\front\Views\ShopSearch` |
| `autoload/front/Controllers/ShopBasketController.php` | zamiana `\shop\Basket`, `\shop\Promotion` |
| `autoload/admin/Controllers/ShopOrderController.php` | zamiana `\shop\Coupon`, `\shop\Transport` |
| `autoload/admin/Controllers/ShopProductController.php` | zamiana `\shop\ProductSet` |
| `autoload/admin/Controllers/ShopPromotionController.php` | zamiana `::$condition_type`, `::$discount_type` |
| `autoload/front/Controllers/ShopOrderController.php` | zamiana `\shop\Coupon` |
| Szablony (`templates/`) | zamiana `\shop\Shop::shortPrice()`, `\shop\ProductAttribute::*`, `\shop\Category::*` |
| `index.php` | zamiana `\shop\Category::get_category_products_id()` |
| `autoload/Domain/Order/OrderRepository.php` | zamiana `\shop\ProductCustomField` |
## Weryfikacja
Po każdej fazie:
1. Uruchomić `./test.ps1` — wszystkie 610+ testów muszą przechodzić
2. Grep po `\shop\` w całym codebase — upewnić się, że usunięta klasa nie jest nigdzie używana
3. Po zakończeniu wszystkich faz: `grep -r "\\\\shop\\\\" autoload/ templates/ admin/ index.php ajax.php cron.php api.php` powinien zwracać 0 wyników
## Szacunek złożoności
| Faza | Klasy | Linii do usunięcia | Złożoność |
|------|-------|---------------------|-----------|
| 1 | Transport, ProductSet, Coupon | ~164 | Niska |
| 2 | Shop, Search, Basket | ~201 | Niska-średnia |
| 3 | ProductCustomField, Category, ProductAttribute | ~277 | Średnia |
| 4 | Promotion | ~107 | Średnia |
| 5 | Order, Product | ~1 514 | Wysoka |
| **Razem** | **12 klas** | **~2 363** | |

View File

@@ -12,7 +12,6 @@ Notatki i wnioski zebrane podczas pracy z kodem. Aktualizowane na bieżąco.
## Znane problemy / TODO
- `\Shared\Helpers\Helpers::send_email()` i `Shared\Email\Email::send()` — zduplikowana logika PHPMailer. Docelowo zunifikować w `Shared\Email\Email`
- `shop\Search` — typo w `use`: `shop\Produt` zamiast `shop\Product`
## Wzorce potwierdzone w projekcie

View File

@@ -1,504 +1,173 @@
# Struktura Projektu shopPRO
Dokumentacja struktury projektu shopPRO do szybkiego odniesienia.
Aktualna architektura po zakonczonej migracji na Domain-Driven Design + Dependency Injection.
## System Cache (Redis)
## Warstwa domenowa (`autoload/Domain/`)
### Klasy odpowiedzialne za cache
Kazdy modul zawiera Repository (i opcjonalnie dodatkowe klasy). Konstruktor DI z `$db` (Medoo). Metody sluza zarowno adminowi, jak i frontendowi (wspolna warstwa).
#### RedisConnection (`Shared\Cache\RedisConnection`)
- **Plik:** `autoload/Shared/Cache/RedisConnection.php`
- **Opis:** Singleton zarządzający połączeniem z Redis
- **Metody:**
- `getInstance()` - pobiera instancję połączenia
- `getConnection()` - zwraca obiekt Redis
| Modul | Klasy | Uwagi |
|-------|-------|-------|
| Article | ArticleRepository | blog, aktualnosci, galerie, pliki |
| Attribute | AttributeRepository | cechy produktow + wartosci |
| Banner | BannerRepository | banery glowne + boczne, Redis cache |
| Basket | BasketCalculator | summary, count, walidacja stanow |
| Cache | CacheRepository | czyszczenie cache z poziomu admin |
| Category | CategoryRepository | drzewa kategorii, produkty w kategorii, Redis cache |
| Client | ClientRepository | CRUD, auth, adresy, zamowienia |
| Coupon | CouponRepository | kupony rabatowe, walidacja, uzycie |
| Dashboard | DashboardRepository | statystyki admin, Redis cache |
| Dictionaries | DictionariesRepository | slowniki admin |
| Integrations | IntegrationsRepository | Apilo sync, ustawienia |
| Languages | LanguagesRepository | jezyki, tlumaczenia |
| Layouts | LayoutsRepository | layouty stron, 3-level fallback |
| Newsletter | NewsletterRepository, NewsletterPreviewRenderer | subskrypcje, szablony, kolejka wysylki |
| Order | OrderRepository, OrderAdminService | CRUD, Apilo sync, webhooki platnosci, kolejka retry |
| Pages | PagesRepository | strony, menu, drzewa stron |
| PaymentMethod | PaymentMethodRepository | metody platnosci, mapowanie Apilo |
| Producer | ProducerRepository | producenci |
| Product | ProductRepository | CRUD, cache, kombinacje, zdjecia, Google Feed XML |
| ProductSet | ProductSetRepository | zestawy produktow |
| Promotion | PromotionRepository | promocje, 5 typow applyType*, silnik dopasowania |
| Scontainers | ScontainersRepository | kontenery sidebaru |
| Settings | SettingsRepository | ustawienia sklepu |
| ShopStatus | ShopStatusRepository | statusy zamowien, mapowanie Apilo |
| Transport | TransportRepository | transport, koszty, powiazanie z platnosci |
| Update | UpdateRepository | aktualizacje, migracje SQL |
| User | UserRepository | uzytkownicy admin, 2FA, logowanie |
#### CacheHandler (`Shared\Cache\CacheHandler`)
- **Plik:** `autoload/Shared/Cache/CacheHandler.php`
- **Opis:** Handler do obsługi cache Redis
- **Metody:**
- `get($key)` - pobiera wartość z cache (zwraca zserializowany string, wymaga `unserialize()`)
- `set($key, $value, $ttl = 86400)` - zapisuje wartość do cache (serializuje wewnętrznie)
- `exists($key)` - sprawdza czy klucz istnieje
- `delete($key)` - usuwa pojedynczy klucz
- `deletePattern($pattern)` - usuwa klucze według wzorca
## Warstwa admin (`autoload/admin/`)
#### USUNIĘTA: Cache (legacy file-based)
- ~~`autoload/class.Cache.php`~~ — usunięta w ver. 0.282
- Zastąpiona przez `CacheHandler` (Redis) we wszystkich wywołaniach
### Router: `admin\App`
- `getControllerFactories()` — mapa kontrolerow z DI wiring
- Brak fallbacku na legacy — wszystkie moduly na nowych kontrolerach
#### Helpers (`Shared\Helpers\Helpers`)
- **Plik:** `autoload/Shared/Helpers/Helpers.php`
- **Metody cache:**
- `clear_product_cache(int $product_id)` - czyści cache konkretnego produktu
### Kontrolery (`admin\Controllers\`) — 28 kontrolerow
ArticlesArchive, Articles, Banner, Dashboard, Dictionaries, Filemanager, Integrations, Languages, Layouts, Newsletter, Pages, ProductArchive, Scontainers, Settings, ShopAttribute, ShopCategory, ShopClients, ShopCoupon, ShopOrder, ShopPaymentMethod, ShopProducer, ShopProduct, ShopProductSets, ShopPromotion, ShopStatuses, ShopTransport, Update, Users
### Wzorce kluczy Redis
### Support
- `admin\Support\TableListRequestFactory` — paginacja/sortowanie tabel
- `admin\Support\Forms\FormRequestHandler` — obsluga formularzy (persist przy bledach)
- `admin\Support\Forms\FormFieldRenderer` — renderowanie pol formularzy
#### Produkty
### ViewModels
- `admin\ViewModels\Forms\` — FormEditViewModel, FormField, FormTab, FormAction, FormFieldType
- `admin\ViewModels\Common\PaginatedTableViewModel`
### Walidacja
- `admin\Validation\FormValidator` — reguly per pole, sekcje jezykowe
## Warstwa frontend (`autoload/front/`)
### Router: `front\App`
- `route()`, `checkUrlParams()`, `getControllerFactories()`
### Layout Engine: `front\LayoutEngine`
- `show()` — zamiana tagow szablonowych (kategorie, produkty, menu, banery, artykuly, kontenery, meta)
- `contact()`, `cookieInformation()`
### Kontrolery (`front\Controllers\`) — 8 kontrolerow
Newsletter, Search, ShopBasket, ShopClient, ShopCoupon, ShopOrder, ShopProducer, ShopProduct
### Widoki (`front\Views\`) — 11 klas statycznych
Articles, Banners, Languages, Menu, Newsletter, Scontainers, ShopCategory, ShopClient, ShopPaymentMethod, ShopProduct, ShopSearch
## Warstwa wspoldzielona (`autoload/Shared/`)
| Klasa | Opis |
|-------|------|
| `Shared\Cache\CacheHandler` | Redis cache: get/set/delete/deletePattern |
| `Shared\Cache\RedisConnection` | Singleton polaczenia Redis |
| `Shared\Email\Email` | Wrapper PHPMailer |
| `Shared\Helpers\Helpers` | SEO, email, cache clearing, shortPrice, utility |
| `Shared\Html\Html` | Helpery HTML |
| `Shared\Image\ImageManipulator` | Obrobka obrazow GD |
| `Shared\Tpl\Tpl` | Silnik szablonow: render(), set() |
## Cache Redis
### Klucze
```
shop\product:{product_id}:{lang_id}:{permutation_hash}
```
- Przechowuje tablicę danych produktu (z kombinacjami, obrazkami, producentem itd.)
- TTL: 24 godziny (86400 sekund)
- Klasa: `Domain\Product\ProductRepository::findCached()` - `autoload/Domain/Product/ProductRepository.php`
#### Opcje ilościowe produktu
```
ProductRepository::getProductPermutationQuantityOptions:v2:{product_id}:{permutation}
```
- Przechowuje informacje o ilości i komunikatach magazynowych
- Klasa: `Domain\Product\ProductRepository::getProductPermutationQuantityOptions()` - `autoload/Domain/Product/ProductRepository.php`
#### Zestawy produktów
```
ProductRepository::productSetsWhenAddToBasket:{product_id}
```
- Przechowuje produkty często kupowane razem
- Klasa: `Domain\Product\ProductRepository::productSetsWhenAddToBasket()` - `autoload/Domain/Product/ProductRepository.php`
## 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
- **Synchronizacja zaleglych syncow platnosci/statusow:** kolejka retry dla chwilowej niedostepnosci Apilo (`temp/apilo-sync-queue.json`)
- Przetwarzanie: przy kazdym uruchomieniu `cron.php` (limit wsadowy)
**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
│ │ ├── Controllers/ # Nowe kontrolery DI
│ │ ├── controls/ # Kontrolery legacy (fallback)
│ │ └── factory/ # Fabryki/helpery
│ ├── Domain/ # Repozytoria/logika domenowa
│ ├── Shared/ # Wspoldzielone narzedzia
│ │ ├── Cache/ # CacheHandler, RedisConnection
│ │ ├── Helpers/ # Helpers (ex class.S.php)
│ │ └── Tpl/ # Tpl (silnik szablonow)
│ ├── front/ # Klasy frontendu
│ │ ├── App.php # Router (ex controls/Site) — route(), checkUrlParams(), getControllerFactories()
│ │ ├── LayoutEngine.php # Layout engine (ex view/Site) — show(), contact(), cookieInformation()
│ │ ├── Controllers/ # Kontrolery DI (Newsletter, ShopBasket, ShopClient, ShopCoupon, ShopOrder, ShopProducer, ShopProduct)
│ │ └── Views/ # Widoki (Newsletter, Articles, Languages, Banners, Menu, Scontainers, ShopCategory, ShopClient)
│ └── shop/ # Klasy sklepu
├── docs/ # Dokumentacja techniczna
├── libraries/ # Biblioteki zewnętrzne
├── temp/ # Cache tymczasowy
├── thumbs/ # Miniatury zdjęć
└── cron.php # Zadania CRON
shop\product:{id}:{lang}:{permutation_hash} — dane produktu (TTL 24h)
ProductRepository::getProductPermutationQuantityOptions:v2:{id}:{perm} — ilosc + komunikaty
ProductRepository::productSetsWhenAddToBasket:{id} — zestawy "kupowane razem"
```
## Baza danych
### Konwencje
- TTL domyslnie 86400 (24h)
- Dane serializowane — `unserialize()` po `get()`
- Czyszczenie: `CacheHandler::deletePattern("shop\\product:{$id}:*")`
- Czyszczenie z poziomu admin: `Shared\Helpers\Helpers::clear_product_cache($id)`
- Przycisk "Wyczysc cache" w admin: `SettingsController::clearCacheAjax()``flushAll()` Redis + `temp/` + `thumbs/`
### 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
## Entry pointy
### 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)
| Plik | Rola |
|------|------|
| `index.php` | Frontend — autoload, sesja, DB, routing (`front\App`), layout (`front\LayoutEngine`), DOM post-processing |
| `ajax.php` | Frontend AJAX — koszyk, transport, kontakt |
| `api.php` | REST API (Ekomi CSV) |
| `admin/index.php` | Admin — autoload, sesja, DB, routing (`admin\App`) |
| `admin/ajax.php` | Admin AJAX |
| `cron.php` | CRON: Apilo sync (ceny/stany co 10min, cennik co 1h, retry queue) |
| `cron-turstmate.php` | TrustMate integracja |
| `cron/cron-xml.php` | Google Feed XML |
| `download.php` | Pobieranie plikow |
### Tabele checkout
- `pp_shop_payment_methods` - metody platnosci sklepu (mapowanie `apilo_payment_type_id`)
- `pp_shop_transports` - rodzaje transportu sklepu (mapowanie `apilo_carrier_account_id`)
- `pp_shop_transport_payment_methods` - powiazanie metod transportu i platnosci
### Autoloader
Kazdy entry point rejestruje `__autoload_my_classes()`:
1. Probuje `autoload/{namespace}/class.{ClassName}.php` (legacy format)
2. Probuje `autoload/{namespace}/{ClassName}.php` (PSR-4 format)
Pelna dokumentacja tabel: `DATABASE_STRUCTURE.md`
### Routing frontend (index.php)
Przed `front\App::route()`:
1. Sprawdza tabele `pp_redirects` → 301 redirect
2. Sprawdza tabele `pp_routes` → regex pattern → destination
## Konfiguracja
### Newsletter queue
`index.php` wywoluje `$newsletterRepo->sendQueued()` na koncu kazdego requestu frontendowego (limit 1 mail/request).
### Redis
- Konfiguracja: `config.php` (zmienna `$config['redis']`)
- Parametry: host, port, password
## Integracje zewnetrzne
### Autoload
- Funkcja: `__autoload_my_classes()` w `cron.php:6`
- Wzorzec: `autoload/{namespace}/class.{ClassName}.php`
### Apilo (cron.php)
- Synchronizacja cen/stanow produktow (co 10 min)
- Synchronizacja cennika (co 1h)
- Kolejka retry: `temp/apilo-sync-queue.json``OrderAdminService::processApiloSyncQueue()`
- Mapowanie statusow i platnosci przez tabele `pp_shop_statuses` i `pp_shop_payment_methods`
## Klasy pomocnicze
### Webhooki platnosci (front\Controllers\ShopOrderController)
- tPay, Przelewy24, Hotpay — ujednolicone: `set_as_paid` + `update_status`
### \Shared\Helpers\Helpers (autoload/Shared/Helpers/Helpers.php)
Główna klasa helper (przeniesiona z `class.S.php`) 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
- `clear_product_cache($id)` - czyszczenie cache produktu
## Biblioteki (`libraries/`)
### Medoo
- Plik: `libraries/medoo/medoo.php`
- Zmienna: `$mdb`
- ORM do operacji na bazie danych
- `medoo/medoo.php` — Medoo ORM (`$mdb`)
- `rb.php` — RedBeanPHP ORM (`\R::`, `$pdo`)
- `phpmailer/` — PHPMailer
## Najważniejsze wzorce
## Wzorce architektoniczne
### 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\`~~ - USUNIĘTY — wszystkie fabryki zmigrowane do Domain
- ~~`\front\controls\`~~ - USUNIĘTY — router przeniesiony do `\front\App`
- ~~`\front\view\`~~ - USUNIĘTY — layout engine przeniesiony do `\front\LayoutEngine`
- ~~`\shop\`~~ - USUNIĘTY — wszystkie klasy zmigrowane do `\Domain\`
### Cachowanie produktów
### DI zamiast global
```php
// Pobranie produktu z cache
$product = (new \Domain\Product\ProductRepository($mdb))->findCached($product_id, $lang_id, $permutation_hash);
// Czyszczenie cache produktu
\Shared\Helpers\Helpers::clear_product_cache($product_id);
// Kontroler wiring (w admin\App lub front\App)
$repo = new \Domain\Example\ExampleRepository($mdb);
$controller = new \admin\Controllers\ExampleController($repo);
```
## Refaktoryzacja do Domain-Driven Architecture
### Wspolna warstwa Domain
Metody frontendowe (z Redis cache) dodawane do istniejacych repozytoriow — NIE tworzymy osobnych FrontendService/AdminService.
### Nowa struktura (w trakcie migracji)
```
autoload/
├── Domain/ # Nowa warstwa biznesowa (namespace \Domain\)
│ ├── Product/
│ │ └── ProductRepository.php
│ ├── Banner/
│ │ └── BannerRepository.php
│ ├── Settings/
│ │ └── SettingsRepository.php
│ ├── Cache/
│ │ └── CacheRepository.php
│ ├── Article/
│ │ └── ArticleRepository.php
│ ├── User/
│ │ └── UserRepository.php
│ ├── Languages/
│ │ └── LanguagesRepository.php
│ ├── Layouts/
│ │ └── LayoutsRepository.php
│ ├── Newsletter/
│ │ ├── NewsletterRepository.php
│ │ └── NewsletterPreviewRenderer.php
│ ├── Scontainers/
│ │ └── ScontainersRepository.php
│ ├── Dictionaries/
│ │ └── DictionariesRepository.php
│ ├── Pages/
│ │ └── PagesRepository.php
│ ├── Integrations/
│ │ └── IntegrationsRepository.php
│ ├── Promotion/
│ │ └── PromotionRepository.php
│ ├── Coupon/
│ │ └── CouponRepository.php
│ ├── ShopStatus/
│ │ └── ShopStatusRepository.php
│ ├── Transport/
│ │ └── TransportRepository.php
│ ├── ProductSet/
│ │ └── ProductSetRepository.php
│ ├── Producer/
│ │ └── ProducerRepository.php
│ └── ...
├── admin/
│ ├── Controllers/ # Nowe kontrolery (namespace \admin\Controllers\)
│ ├── 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)
├── front/
│ ├── App.php # Router (namespace \front\) — route(), checkUrlParams(), getControllerFactories()
│ ├── LayoutEngine.php # Layout engine (namespace \front\) — show(), contact(), cookieInformation()
│ ├── Controllers/ # Kontrolery frontendowe (namespace \front\Controllers\) z DI
│ └── Views/ # Widoki (namespace \front\Views\) — czyste VIEW, statyczne
├── shop/ # Legacy - fasady do Domain
```
### Klasy View — statyczne, bezstanowe
`front\Views\*` — nie wymagaja DI. Czyste funkcje: dane wchodza, HTML wychodzi.
**Aktualizacja 2026-02-14 (ver. 0.268):**
- Dodano modul domenowy `Domain/PaymentMethod/PaymentMethodRepository.php`.
- Dodano kontroler DI `admin/Controllers/ShopPaymentMethodController.php`.
- Modul `/admin/shop_payment_method/*` dziala na nowych widokach (`payment-methods-list`, `payment-method-edit`).
- Usunieto legacy: `autoload/admin/controls/class.ShopPaymentMethod.php`, `autoload/admin/factory/class.ShopPaymentMethod.php`, `autoload/admin/view/class.ShopPaymentMethod.php`, `admin/templates/shop-payment-method/view-list.php`.
### Kontrolery — instancyjne z DI
`Controllers\*` — repozytoria wstrzykiwane przez konstruktor.
**Aktualizacja 2026-02-14 (ver. 0.269):**
- Dodano modul domenowy `Domain/Transport/TransportRepository.php`.
- Dodano kontroler DI `admin/Controllers/ShopTransportController.php`.
- Modul `/admin/shop_transport/*` dziala na nowych widokach (`transports-list`, `transport-edit`).
- Usunieto legacy: `autoload/admin/controls/class.ShopTransport.php`, `autoload/admin/view/class.ShopTransport.php`, `admin/templates/shop-transport/view-list.php`.
- `admin\factory\ShopTransport` i `front\factory\ShopTransport` przepiete na repozytorium.
### Nazewnictwo plikow
- Nowe: `ClassName.php`
- Legacy (pozostalosci): `class.ClassName.php`
- Autoloader obsluguje oba formaty
**Aktualizacja 2026-02-14 (ver. 0.270):**
- `OrderAdminService` zapisuje nieudane syncy Apilo (status/platnosc) do kolejki `temp/apilo-sync-queue.json`.
- `cron.php` automatycznie ponawia zalegle syncy (`OrderAdminService::processApiloSyncQueue()`).
- `OrderAdminService::setOrderAsPaid()` wysyla mapowany typ platnosci Apilo (z mapowania metody platnosci), bez stalej wartosci `type`.
**Aktualizacja 2026-02-15 (ver. 0.276):**
- Dodano modul domenowy `Domain/Order/OrderRepository.php`.
- Dodano serwis aplikacyjny `Domain/Order/OrderAdminService.php`.
- Dodano kontroler DI `admin/Controllers/ShopOrderController.php`.
- Modul `/admin/shop_order/*` dziala na nowych widokach (`orders-list`, `order-details`, `order-edit`).
- Usunieto legacy: `autoload/admin/controls/class.ShopOrder.php`, `autoload/admin/factory/class.ShopOrder.php`, `admin/templates/shop-order/view-list.php`.
**Aktualizacja 2026-02-15 (ver. 0.277):**
- Dodano globalna wyszukiwarke admin w `admin/templates/site/main-layout.php` (produkty + zamowienia).
- Dodano endpoint AJAX `SettingsController::globalSearchAjax()` w `autoload/admin/Controllers/SettingsController.php`.
- Usunieto fasade `autoload/admin/factory/class.Integrations.php`.
- Wywołania integracji przepiete bezposrednio na `Domain/Integrations/IntegrationsRepository.php`.
### 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
Pelna dokumentacja testow: `TESTING.md`
## Dodatkowa aktualizacja 2026-02-14 (ver. 0.271)
- Dodano modul domenowy `Domain/Attribute/AttributeRepository.php`.
- Dodano kontroler DI `admin/Controllers/ShopAttributeController.php`.
- Modul `/admin/shop_attribute/*` zostal przepiety na nowe widoki (`attributes-list`, `attribute-edit`, `values-edit`).
- Usunieto legacy: `autoload/admin/controls/class.ShopAttribute.php`, `autoload/admin/factory/class.ShopAttribute.php`, `autoload/admin/view/class.ShopAttribute.php`, `admin/templates/shop-attribute/_partials/value.php`.
- Przepieto zaleznosci kombinacji produktu na `Domain\Attribute\AttributeRepository` i `shop\ProductAttribute`.
- Dla `ShopAttribute` routing celowo nie wykonuje fallbacku akcji do legacy kontrolera.
## Dodatkowa aktualizacja 2026-02-15 (ver. 0.272)
- Dodano modul domenowy `Domain/ProductSet/ProductSetRepository.php`.
- Dodano kontroler DI `admin/Controllers/ShopProductSetsController.php`.
- Modul `/admin/shop_product_sets/*` dziala na nowych widokach (`product-sets-list`, `product-set-edit`).
- Usunieto legacy: `autoload/admin/controls/class.ShopProductSets.php`, `autoload/admin/factory/class.ShopProductSet.php`, `admin/templates/shop-product-sets/view-list.php`, `admin/templates/shop-product-sets/set-edit.php`.
- `shop\ProductSet` przepiety na fasade do `Domain\ProductSet\ProductSetRepository`.
## Dodatkowa aktualizacja 2026-02-15 (ver. 0.273)
- Dodano modul domenowy `Domain/Producer/ProducerRepository.php`.
## Dodatkowa aktualizacja 2026-02-15 (ver. 0.274)
- Dodano modul domenowy `Domain/Client/ClientRepository.php`.
- Dodano kontroler DI `admin/Controllers/ShopClientsController.php`.
- Modul `/admin/shop_clients/*` dziala na nowych widokach opartych o `components/table-list`.
- Usunieto legacy: `autoload/admin/controls/class.ShopClients.php`, `autoload/admin/factory/class.ShopClients.php`.
- Routing i menu admin przepiete na kanoniczny URL `/admin/shop_clients/list/`.
- Dodano kontroler DI `admin/Controllers/ShopProducerController.php`.
- Modul `/admin/shop_producer/*` dziala na nowych widokach (`producers-list`, `producer-edit`).
- Usunieto legacy: `autoload/admin/controls/class.ShopProducer.php`, `admin/templates/shop-producer/list.php`, `admin/templates/shop-producer/edit.php`.
- `shop\Producer` przepiety na fasade do `Domain\Producer\ProducerRepository`.
- `admin\controls\ShopProduct` uzywa `ProducerRepository::allProducers()`.
- Usunieto 6 pustych factory facades: `admin\factory\Languages`, `admin\factory\Newsletter`, `admin\factory\Scontainers`, `admin\factory\ShopProducer`, `admin\factory\ShopTransport`, `admin\factory\Layouts`.
- Przepieto 2 wywolania `admin\factory\ShopTransport` w `admin\factory\ShopProduct` na `Domain\Transport\TransportRepository`.
- Usuniety fallback do `admin\factory\Layouts` w `admin\controls\ShopProduct`.
## Dodatkowa aktualizacja 2026-02-15 (ver. 0.274)
- Dodano kontroler DI `admin/Controllers/ShopProductController.php` (akcje `mass_edit`, `mass_edit_save`, `get_products_by_category`).
- Routing `admin\Site` rozszerzono o mapowanie `ShopProduct` do nowego kontrolera.
- `Domain/Product/ProductRepository.php` rozszerzono o metody dla mass-edit: `allProductsForMassEdit`, `getProductsByCategory`, `applyDiscountPercent`.
- Usunieto legacy akcje mass-edit z `autoload/admin/controls/class.ShopProduct.php`.
- Widok `/admin/shop_product/mass_edit/` przepiety na nowy partial `admin/templates/shop-product/mass-edit-custom-script.php`.
- Ujednolicono UI drzewek (strzalki/expand) w:
- `admin/templates/pages/pages-list.php` + `admin/templates/pages/subpages-list.php`
- `admin/templates/articles/subpages-list.php` + `admin/templates/articles/article-edit-custom-script.php`
## Dodatkowa aktualizacja 2026-02-15 (ver. 0.275)
- Dodano modul domenowy `Domain/Category/CategoryRepository.php`.
- Dodano kontroler DI `admin/Controllers/ShopCategoryController.php`.
- Modul `/admin/shop_category/*` dziala przez DI i kanoniczny URL `/admin/shop_category/list/` (z zachowaniem aliasu `view_list`).
- Widoki `shop-category/*` maja wydzielone skrypty `*-custom-script.php` i ujednolicone strzalki drzewa (`button + caret + aria-expanded`).
- Endpointy AJAX dla drzewka kategorii i kolejnosci produktow przepiete na `/admin/shop_category/save_categories_order/`, `/admin/shop_category/save_products_order/`, `/admin/shop_category/cookie_categories/`.
- Usunieto legacy: `autoload/admin/controls/class.ShopCategory.php`, `autoload/admin/factory/class.ShopCategory.php`, `autoload/admin/view/class.ShopCategory.php`.
- Przepieto zaleznosci `ShopProduct` z `admin\factory\ShopCategory` na `Domain\Category\CategoryRepository`.
- Usunieto preload `autoload/admin/factory/class.ShopCategory.php` z `libraries/grid/config.php`.
## Dodatkowa aktualizacja 2026-02-15 (ver. 0.277) - ShopProduct (factory)
- `Domain/Product/ProductRepository.php` rozszerzono o ~40 metod: CRUD, save, delete, duplicate, toggleStatus, updatePrice, kombinacje, zdjecia/pliki, Google Feed XML, custom labels.
- `admin/Controllers/ShopProductController.php` rozszerzono o ~30 akcji obslugujacych caly modul produktow.
- Konstruktor kontrolera teraz przyjmuje `ProductRepository` + `IntegrationsRepository`.
- Routing w `admin\Site` zaktualizowany (dodano `IntegrationsRepository`, blokada fallbacku na legacy).
- Przepieto zaleznosci zewnetrzne: `ProductArchiveController`, `order-details.php`, `cron.php`, `cron-xml.php`, `products-list-table.php`, `stock.php`.
- Przepieto endpointy AJAX z `admin/ajax.php` na kontroler: `product_file_delete`, `product_file_name_change`.
- Przepieto `cookie_categories` w widokach product-edit i mass-edit na `/admin/shop_category/cookie_categories/`.
- Usunieto legacy: `autoload/admin/controls/class.ShopProduct.php`, `autoload/admin/factory/class.ShopProduct.php`, `admin/ajax/shop.php`.
- Usunieto `require_once 'ajax/shop.php'` z `admin/ajax.php`.
## Dodatkowa aktualizacja 2026-02-16 (ver. 0.277) - Dashboard, Update, legacy cleanup, admin\App
- Dodano `Domain/Dashboard/DashboardRepository.php` (7 metod, Redis caching).
- Dodano `admin/Controllers/DashboardController.php` (DI z DashboardRepository + ShopStatusRepository).
- Dodano `Domain/Update/UpdateRepository.php` (update, runPendingMigrations, helper methods).
- Dodano `admin/Controllers/UpdateController.php` (DI z UpdateRepository).
- Przepisano `admin/templates/update/main-view.php` — usunieto `gridEdit`, `$.prompt()`, zastapiono panelami + `$.confirm()`.
- Usunieto `autoload/admin/factory/class.Articles.php` (martwy kod), przeniesiono `articles_by_date_add` do `ArticleRepository`.
- Przepieto `front\factory\Newsletter` na `ArticleRepository::articlesByDateAdd()`.
- Przeniesiono logike z `admin\view\Page::show()` do `admin\App::render()`.
- Przemianowano `admin\Site` na `admin\App` (plik `App.php`).
- Usunieto fallback na `\admin\controls\` w routing (martwy kod).
- Usunieto puste foldery: `autoload/admin/controls/`, `autoload/admin/factory/`, `autoload/admin/view/`.
- Usunieto stary plik `autoload/admin/class.Site.php`.
- Pelna migracja admin zakonczona — wszystkie moduly na Domain + DI + Controllers.
## Aktualizacja 2026-02-16 (ver. 0.279) - Newsletter + Languages frontend migration
- Usunięta fasada `front\factory\Languages` — wszystkie 26 zależności przepięte bezpośrednio na `Domain\Languages\LanguagesRepository`.
- Usunięta fasada `front\factory\Newsletter` — logika przeniesiona do `Domain\Newsletter\NewsletterRepository` (6 nowych metod frontendowych).
- Usunięty stary kontroler `front\controls\Newsletter` i widok `front\view\Newsletter`.
- Utworzony nowy namespace `front\Controllers\` — pierwszy frontowy kontroler z DI: `NewsletterController`.
- Utworzony nowy namespace `front\Views\` — czyste widoki statyczne: `Languages`, `Newsletter`, `Banners`.
- Zaktualizowany routing w `front\controls\Site::route()``getControllerFactories()` (DI) z fallbackiem na stare `front\controls\`.
- Przepięte 4 wywołania `Newsletter::get_template()` w `front\factory\ShopClient` na `NewsletterRepository::templateByName()`.
- FIX: `newsletter_unsubscribe()` — błędna składnia medoo `delete()`.
## Aktualizacja 2026-02-16 (ver. 0.281) - Banners frontend migration
- NOWE METODY w `Domain/Banner/BannerRepository.php`: `banners()`, `mainBanner()` (Redis cache, filtrowanie dat).
- NOWY: `front\Views\Banners` — czysty VIEW (renderowanie szablonow banner/).
- USUNIETA: `front\factory\Banners` — logika przeniesiona do `BannerRepository`.
- USUNIETA: `front\view\Banners` — zastapiona przez `front\Views\Banners`.
- UPDATE: `front\view\Site::show()` — przepiecie na repo + Views.
## Aktualizacja 2026-02-16 (ver. 0.282) - Cache cleanup, Shared namespace
- NOWY: `Shared\Cache\CacheHandler` + `Shared\Cache\RedisConnection` — namespace Shared.
- USUNIETA: `class.CacheHandler.php` — wrapper, 60 odwolan przepietych na `\Shared\Cache\CacheHandler`.
- USUNIETA: `class.RedisConnection.php` — wrapper, 12 odwolan przepietych na `\Shared\Cache\RedisConnection`.
- USUNIETA: `class.Cache.php` — legacy file-based cache.
- UPDATE: 6 plikow przepietych z `\Cache::fetch/store` na `CacheHandler` (ShopProduct, ShopPaymentMethod, ShopCategory, ShopTransport, ShopAttribute, DictionariesRepository).
## Aktualizacja 2026-02-16 - class.S.php migration, Mobile_Detect removal, S cleanup
- USUNIETA: `class.Mobile_Detect.php` — przestarzala detekcja mobilna (UA v2.8.16), zastapiona responsive design.
- USUNIETA: metoda `S::is_mobile()` i 3 warunki mobilne w `front\view\Site` (m_html/m_css/m_js zawsze puste).
- USUNIETE z `LayoutsRepository`: pola `m_html`, `m_css`, `m_js` (save + defaultLayout).
- CLEANUP `class.S.php`: usunieto 12 nieuzywanych metod (set_array_value, parse_name, clear_redis_cache, get_domain, pre_dump, escape, chmod_r, rrmdir, rcopy, pre, json_to_array, is_empty_dir).
- FIX: `array_cartesian_product()` — iteracja po niezdefiniowanej zmiennej `$array` zamiast parametru `$input`.
- PRZENIESIONA: `class.S.php``Shared\Helpers\Helpers` (namespace `Shared\Helpers`, klasa `Helpers`).
- ZAMIENIONE: ~140 plikow — `\S::``\Shared\Helpers\Helpers::`.
- NOWY: `tests/stubs/Helpers.php` — stub klasy Helpers dla testow.
- USUNIETA: `autoload/class.S.php` — zastapiona przez `Shared\Helpers\Helpers`.
## Aktualizacja 2026-02-17 (ver. 0.286) - Layouts, Menu, Pages frontend migration
- NOWE METODY w `Domain/Layouts/LayoutsRepository.php`: `categoryDefaultLayoutId()`, `getDefaultLayout()`, `getProductLayout()`, `getArticleLayout()`, `getCategoryLayout()`, `getActiveLayout()`.
- NOWE METODY w `Domain/Pages/PagesRepository.php`: `frontPageDetails()`, `frontPageSort()`, `frontMainPageId()`, `frontLangUrl()`, `frontMenuDetails()`, `frontMenuPages()`.
- NOWY: `front\Views\Menu` — czysty VIEW (`pages()`, `menu()`).
- USUNIETA: `front\factory\class.Layouts.php` — logika przeniesiona do `LayoutsRepository`.
- USUNIETA: `front\factory\class.Menu.php` — logika przeniesiona do `PagesRepository`.
- USUNIETA: `front\factory\class.Pages.php` — logika przeniesiona do `PagesRepository`.
- USUNIETA: `front\view\class.Menu.php` — zastapiona przez `front\Views\Menu`.
- USUNIETA: `templates\menu\submenu.php` — martwy kod.
## Aktualizacja 2026-02-17 - Tpl namespace, CurlServer removal, thumb.php fix
- NOWY: `autoload/Shared/Tpl/Tpl.php` — silnik szablonow w namespace `Shared\Tpl`.
- USUNIETA: `autoload/class.Tpl.php` — zastapiona przez `Shared\Tpl\Tpl`.
- USUNIETA: `autoload/curl.class.php` — klasa `CurlServer` bez referencji w projekcie.
- ZAMIENIONE: ~135 plikow — `\Tpl::` / `new \Tpl``\Shared\Tpl\Tpl::` / `new \Shared\Tpl\Tpl`.
- 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
---
## Aktualizacja 2026-02-17 (ver. 0.290) - ShopCoupon + ShopOrder frontend migration
- **ShopCoupon (frontend)** — migracja controls + factory na Domain + Controllers
- NOWE METODY w `CouponRepository`: `findByName()`, `isAvailable()`, `markAsUsed()`, `incrementUsedCount()`
- NOWY: `front\Controllers\ShopCouponController` — instancyjny kontroler z DI (`useCoupon()`, `deleteCoupon()`)
- KONWERSJA: `shop\Coupon` na fasade z dzialajacymi metodami (`is_one_time()`, `set_as_used()`)
- FIX: kupony jednorazowe nigdy nie byly oznaczane jako uzyte
- USUNIETA: `front\controls\class.ShopCoupon.php`, `front\factory\class.ShopCoupon.php`
- **ShopOrder (frontend)** — migracja controls + factory + view na Domain + Controllers
- NOWE METODY w `OrderRepository`: `findIdByHash()`, `findHashById()`, `orderDetailsFrontend()`, `generateOrderNumber()`, `createFromBasket()` (~180 linii logiki basket_save)
- NOWY: `front\Controllers\ShopOrderController` — instancyjny kontroler z DI (`paymentConfirmation()`, `paymentStatusTpay()`, `paymentStatusPrzelewy24pl()`, `paymentStatusHotpay()`, `orderDetails()`)
- POPRAWA: webhooks przelewy24/hotpay — ujednolicone z tpay (set_as_paid + update_status zamiast recznego $mdb->update)
- UPDATE: `ShopBasketController` — DI OrderRepository, zmiana wywolan basket_save/order_hash
- UPDATE: `ClientRepository::clientOrders()`, `shop\Order::order_resend_confirmation_email()`, `cron-turstmate.php` — przepiete na `OrderRepository`
- USUNIETA: `front\controls\class.ShopOrder.php`, `front\factory\class.ShopOrder.php`, `front\view\class.ShopOrder.php`
## Aktualizacja 2026-02-17 (ver. 0.291) - ShopProducer frontend migration
- NOWA METODA w `ProducerRepository`: `allActiveProducers()` — pełne dane aktywnych producentów
- NOWY: `front\Controllers\ShopProducerController` — instancyjny kontroler z DI (products, list)
- USUNIETA: `front\controls\class.ShopProducer.php` — logika przeniesiona do kontrolera + repo
- USUNIETA: `autoload\shop\class.Producer.php` — fasada niepotrzebna
- UPDATE: `front\view\Site::show()` — przepiecie na `$producerRepo->findForFrontend()`
- UPDATE: `front\controls\Site::getControllerFactories()` — zarejestrowany `ShopProducer`
## Aktualizacja 2026-02-17 (ver. 0.293) - front\controls\Site + front\view\Site → front\App + front\LayoutEngine
- Przemianowano `front\controls\Site` na `front\App` (plik `App.php`) — router z camelCase metodami.
- Przemianowano `front\view\Site` na `front\LayoutEngine` (plik `LayoutEngine.php`) — layout engine z camelCase metodami.
- Przepiete call sites: `index.php` (3 miejsca), `ajax.php` (1 miejsce).
- Usuniete pliki: `autoload/front/controls/class.Site.php`, `autoload/front/view/class.Site.php`.
- Usuniete puste foldery: `autoload/front/controls/`, `autoload/front/view/`.
- Pelna migracja frontendu zakonczona — struktura `autoload/front/`: `App.php`, `LayoutEngine.php`, `Controllers/`, `Views/`.
## Aktualizacja 2026-02-17 (ver. 0.292) - ShopProduct + ShopPaymentMethod + ShopPromotion + ShopStatuses + ShopTransport frontend migration
- **Pelna migracja front\factory\** — USUNIETY caly folder `autoload/front/factory/`; 5 ostatnich klas zmigrowanych:
- `front\factory\ShopProduct` (~410 linii) → `ProductRepository` (~20 nowych metod frontendowych)
- `front\factory\ShopPaymentMethod``PaymentMethodRepository` (metody frontendowe z Redis cache)
- `front\factory\ShopPromotion``PromotionRepository` (5 metod applyType*)
- `front\factory\ShopStatuses` → przepiecie bezposrednio na `ShopStatusRepository`
- `front\factory\ShopTransport``TransportRepository` (4 metody frontendowe z Redis cache)
- Usuniete legacy: `front\controls\class.ShopProduct.php`, `front\view\class.ShopPaymentMethod.php`, `front\view\class.ShopTransport.php`, `shop\class.PaymentMethod.php`
- FIX: broken `transports_list()` w ajax.php → nowa metoda `forPaymentMethod()`
- Pelna migracja frontendu zakonczona — `autoload/front/`: `App.php`, `LayoutEngine.php`, `Controllers/`, `Views/`
---
*Dokument aktualizowany: 2026-02-17 (ver. 0.293)*
### Nazewnictwo katalogow
- Nowe: z duzej litery (`Views/`, `Controllers/`)
- Namespace `\admin\` z malej (bo katalog `admin/` jest z malej na serwerze Linux)
- NIE uzywac `\Admin\` (duze A)

View File

@@ -1,308 +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
│ │ ├── 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
36: ✅ ShopProducer frontend (ver. 0.291) — front\controls\ShopProducer + shop\Producer usunięte, front\Controllers\ShopProducerController z DI, allActiveProducers() w ProducerRepository
## 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`*

View File

@@ -1,176 +0,0 @@
# Plan Refaktoryzacji - ShopAttribute (`/admin/shop_attribute`)
Data przygotowania: 2026-02-14
Tryb realizacji: Human In The Loop (HITL)
Status: Zrealizowano kroki 0-6 (2026-02-14)
## 1. Cel i zakres
Celem jest pelna migracja modulu `shop_attribute` z legacy (`admin/controls`, `admin/factory`, `admin/view`, `grid/gridEdit`) na:
- `Domain/*` (repozytorium + logika zapisu),
- `admin/Controllers/*` (DI),
- nowe widoki oparte o `components/table-list` i `components/form-edit`,
- kanoniczny routing (`list`, `edit`, `save`, `delete`, `values`, `values_save`) z kompatybilnoscia aliasow legacy.
Zakres obejmuje takze przeglad i przepiecie zaleznosci w innych klasach (admin/front/shop), aby usunac twarde powiazanie ze starym modulem.
## 2. Stan obecny (baseline)
### Legacy modułu
- `autoload/admin/controls/class.ShopAttribute.php`
- `autoload/admin/factory/class.ShopAttribute.php`
- `autoload/admin/view/class.ShopAttribute.php`
- `admin/templates/shop-attribute/*` (stare `grid` / `gridEdit` + AJAX `attribute_value_tpl`)
### Zaleznosci poza modulem
- `autoload/admin/controls/class.ShopProduct.php` (lista atrybutow do kombinacji)
- `admin/templates/shop-product/product-combination.php` (nazwy atrybut/wartosc)
- `autoload/admin/factory/class.ShopProduct.php` (m.in. `value_details`, aktualizacja cen kombinacji)
- `autoload/front/factory/class.ShopAttribute.php` i `autoload/shop/class.ProductAttribute.php` (odczyt front/shop)
- `templates/shop-product/_partial/product-attribute.php`, `autoload/front/factory/class.ShopOrder.php`
### Ryzyka znalezione w aktualnym UI wartosci
- domyslny jezyk w tytule jest hardcoded (`pl`),
- wybor domyslnej wartosci oparty o indeksy wierszy (podatne na bledy po usuwaniu),
- brak walidacji biznesowej (np. wymagane minimum 1 wartosc i 1 nazwa w jezyku domyslnym),
- UX edycji wartosci jest malo czytelny przy duzej liczbie pozycji.
## 3. Architektura docelowa
### Nowe klasy
- `autoload/Domain/Attribute/AttributeRepository.php`
- `autoload/admin/Controllers/ShopAttributeController.php`
### Nowe widoki
- `admin/templates/shop-attribute/attributes-list.php` (nowy `table-list`)
- `admin/templates/shop-attribute/attribute-edit.php` (nowy `form-edit`)
- `admin/templates/shop-attribute/attribute-values-edit.php` (nowy ekran wartosci)
- `admin/templates/shop-attribute/attribute-values-custom-script.php` (logika JS dla wartosci)
- `admin/templates/shop-attribute/_partials/value-row.php` (opcjonalny partial pojedynczego wiersza)
### Routing
- kanoniczne:
- `/admin/shop_attribute/list/`
- `/admin/shop_attribute/edit/id={id}`
- `/admin/shop_attribute/save/`
- `/admin/shop_attribute/delete/id={id}`
- `/admin/shop_attribute/values/id={id}`
- `/admin/shop_attribute/values_save/id={id}`
- brak aliasow kompatybilnosci legacy (decyzja: URL-e niekanoniczne nie sa utrzymywane)
## 4. Plan realizacji HITL (krok po kroku)
## Krok 0 - Freeze i test baseline
Zakres:
- uruchomienie testow referencyjnych (minimum smoke + wskazane pelne),
- zapisanie stanu wyjsciowego i listy plikow modulu.
Wyjscie:
- potwierdzony baseline testow przed zmianami.
Punkt akceptacji HITL:
- akceptacja startu implementacji po weryfikacji baseline.
## Krok 1 - Domain Repository (bez zmian UI)
Zakres:
- utworzenie `AttributeRepository` z metodami admin:
- `listForAdmin()`, `findAttribute()`, `saveAttribute()`, `deleteAttribute()`,
- `findValues()`, `saveValues()`,
- pomocnicze: `getAttributeNameById()`, `getAttributeValueById()`, `getAttributesListForCombinations()`, `valueDetails()`.
- normalizacja danych i bezpieczne parsowanie inputow (`switch`, liczby, tablice ID).
- centralizacja invalidacji cache/temp po zapisach.
Wyjscie:
- gotowa warstwa domenowa pod kontroler DI.
Punkt akceptacji HITL:
- review API repozytorium i nazw metod przed podpieciem kontrolera.
## Krok 2 - Kontroler DI i routing
Zakres:
- dodanie `ShopAttributeController` (akcje list/edit/save/delete/values/valuesSave),
- podpiecie do `admin\Site::$newControllers`,
- ustawienie kanonicznych URL bez aliasow legacy,
- aktualizacja linku menu do `/admin/shop_attribute/list/`.
Wyjscie:
- modul dziala przez nowy kontroler, bez usuwania legacy w tym kroku.
Punkt akceptacji HITL:
- potwierdzenie zgodnosci URL i backward compatibility.
## Krok 3 - Migracja widokow (lista + formularz cechy)
Zakres:
- przepisanie listy na `components/table-list`,
- przepisanie formularza cechy na `components/form-edit`,
- utrzymanie obecnej funkcjonalnosci (status, typ, kolejnosc, nazwy per jezyk).
Wyjscie:
- brak zaleznosci od `grid`/`gridEdit` w tych ekranach.
Punkt akceptacji HITL:
- akceptacja UX i danych na liscie oraz formularzu cechy.
## Krok 4 - Nowy panel edycji wartosci (UX)
Zakres:
- przebudowa `values-edit` na bardziej intuicyjny formularz:
- jeden czytelny widok tabelaryczny (wiersz = wartosc),
- stabilny identyfikator wiersza zamiast indeksu do wyboru wartosci domyslnej,
- walidacja: co najmniej 1 wartosc, nazwa w jezyku domyslnym, jedna domyslna wartosc,
- jasne komunikaty bledow i podsumowanie zmian.
- usuniecie zaleznosci od endpointu `attribute_value_tpl` (lub utrzymanie tylko jako alias fallback).
Wyjscie:
- nowy edytor wartosci odporny na bledy indeksowania i wygodniejszy dla operatora.
Punkt akceptacji HITL:
- decyzja biznesowa o finalnym UX (wariant A/B ponizej) i akceptacja wygladu.
### Warianty UX do decyzji
- Wariant A (rekomendowany): osobny ekran `values`, ale w nowym ukladzie tabelarycznym + walidacje.
- Wariant B: integracja wartosci bezposrednio w `attribute-edit` (mniej klikniec, ale wieksza zlozonosc formularza).
## Krok 5 - Przepiecie zaleznosci i usuniecie legacy
Zakres:
- przeszukanie i przepiecie wszystkich uzyc `admin\factory\ShopAttribute` w kodzie admina,
- aktualizacja zaleznosci w miejscach zwiazanych z kombinacjami produktu,
- usuniecie starych klas:
- `autoload/admin/controls/class.ShopAttribute.php`
- `autoload/admin/view/class.ShopAttribute.php`
- `autoload/admin/factory/class.ShopAttribute.php` (po przepieciu wszystkich odwolan)
- cleanup starych szablonow nieuzywanych.
Wyjscie:
- brak runtime zaleznosci od legacy `ShopAttribute`.
Punkt akceptacji HITL:
- akceptacja listy usuwanych plikow i finalnego cleanupu.
## Krok 6 - Testy + dokumentacja + release
Zakres:
- nowe testy:
- `tests/Unit/Domain/Attribute/AttributeRepositoryTest.php`
- `tests/Unit/admin/Controllers/ShopAttributeControllerTest.php`
- uruchomienie regresji (co najmniej testy modułowe + docelowo caly suite),
- aktualizacja dokumentacji:
- `docs/DATABASE_STRUCTURE.md` (tabele atrybutow),
- `docs/PROJECT_STRUCTURE.md`,
- `docs/REFACTORING_PLAN.md`,
- `docs/CHANGELOG.md`,
- `docs/TESTING.md`.
Wyjscie:
- modul gotowy do release, z domknietym testowaniem i dokumentacja.
Punkt akceptacji HITL:
- finalna akceptacja pakietu zmian przed procedura releasowa.
## 5. Kryteria akceptacji
- `shop_attribute` dziala przez `ShopAttributeController` + `AttributeRepository`.
- Lista i formularze nie korzystaja z `grid/gridEdit`.
- Panel wartosci nie opiera domyslnej wartosci na nietrwalych indeksach.
- Stare klasy `controls/view/factory` modulu zostaja usuniete po przepieciu zaleznosci.
- Testy jednostkowe dla nowego repozytorium i kontrolera przechodza.
- Dokumentacja techniczna jest zaktualizowana.

View File

@@ -1,138 +0,0 @@
# Plan Refaktoryzacji: shop_payment_method
Data utworzenia: 2026-02-14
Status: ZREALIZOWANY (Etapy 1-4 zakonczone: 2026-02-14)
## 1. Cel
Pelna migracja modulu `/admin/shop_payment_method/*` do obecnego standardu projektu:
- `Domain/*` dla logiki danych,
- `admin/Controllers/*` z DI dla routingu,
- widoki oparte o `components/table-list` i `components/form-edit`,
- usuniecie legacy klas/podpiecie zaleznosci.
## 2. Stan obecny (inwentaryzacja)
Aktualny modul jest legacy i opiera sie o `grid`:
- `autoload/admin/controls/class.ShopPaymentMethod.php`
- `autoload/admin/factory/class.ShopPaymentMethod.php`
- `autoload/admin/view/class.ShopPaymentMethod.php` (pusta)
- `admin/templates/shop-payment-method/view-list.php` (grid + inline edit)
- menu: `admin/templates/site/main-layout.php` -> `/admin/shop_payment_method/view_list/`
Zaleznosci wykryte poza modulem:
- `autoload/admin/controls/class.ShopTransport.php` korzysta z `admin\\factory\\ShopPaymentMethod::payments_list()`
- `autoload/front/factory/class.ShopPaymentMethod.php` ma bezposrednie zapytania do `pp_shop_payment_methods`
- `autoload/shop/class.PaymentMethod.php` ma bezposrednie zapytania do `pp_shop_payment_methods`
- `cron.php` korzysta z `front\\factory\\ShopPaymentMethod::get_apilo_payment_method_id()`
## 3. Zakres refaktoru
W zakresie:
1. Nowe repozytorium domenowe dla metod platnosci.
2. Nowy kontroler admin z DI i routingiem kanonicznym.
3. Nowe widoki listy i edycji (bez legacy `grid`).
4. Przepiecie zaleznosci (`ShopTransport`, `front\\factory\\ShopPaymentMethod`, `shop\\PaymentMethod`) na nowe API.
5. Cleanup legacy klas/plikow zwiazanych z modulem.
6. Testy jednostkowe + aktualizacja dokumentacji.
Poza zakresem (na ten etap):
1. Refaktoryzacja calego modulu `shop_transport` (zrobimy tylko przepiecie zaleznosci dot. payment methods).
2. Zmiany biznesowe w checkout poza zachowaniem obecnej logiki.
## 4. Architektura docelowa
Planowane nowe pliki:
- `autoload/Domain/PaymentMethod/PaymentMethodRepository.php`
- `autoload/admin/Controllers/ShopPaymentMethodController.php`
- `admin/templates/shop-payment-method/payment-methods-list.php`
- `admin/templates/shop-payment-method/payment-method-edit.php`
Planowane aktualizacje:
- `autoload/admin/class.Site.php` (rejestracja `ShopPaymentMethod` w DI routerze)
- `admin/templates/site/main-layout.php` (kanoniczny URL `/admin/shop_payment_method/list/`)
- `autoload/admin/controls/class.ShopTransport.php` (usuniecie zaleznosci od legacy factory)
- `autoload/front/factory/class.ShopPaymentMethod.php` (fasada delegujaca do Domain repo)
- `autoload/shop/class.PaymentMethod.php` (fasada delegujaca do Domain repo)
Planowane usuniecia:
- `autoload/admin/controls/class.ShopPaymentMethod.php`
- `autoload/admin/factory/class.ShopPaymentMethod.php`
- `autoload/admin/view/class.ShopPaymentMethod.php`
- `admin/templates/shop-payment-method/view-list.php`
## 5. Etapy realizacji (Human In The Loop)
### Etap 1: Domain + testy repozytorium
Zakres:
- utworzenie `PaymentMethodRepository` z metodami:
- `listForAdmin(...)`
- `find(int $id)`
- `save(int $id, array $data)`
- `allActive()`
- `findActiveById(int $id)`
- `isActive(int $id)`
- `getApiloPaymentTypeId(int $id)`
- `forTransport(int $transportId)`
- dodanie testu: `tests/Unit/Domain/PaymentMethod/PaymentMethodRepositoryTest.php`
Checkpoint:
- STOP i prosba o akceptacje po wdrozeniu etapu 1.
### Etap 2: Admin Controller + routing + nowe widoki
Zakres:
- nowy `ShopPaymentMethodController` (akcje: `list`, `edit`, `save`)
- migracja listy/edycji na `table-list` + `form-edit`
- podpiecie w `admin\\Site` (DI factory map)
- kompatybilnosc URL:
- kanoniczne: `/admin/shop_payment_method/list|edit|save/`
- aliasy legacy do decyzji po wdrozeniu (proponuje: tymczasowo wlaczyc)
- test kontrolera: `tests/Unit/admin/Controllers/ShopPaymentMethodControllerTest.php`
Checkpoint:
- STOP i prosba o akceptacje po wdrozeniu etapu 2.
### Etap 3: Przepiecie zaleznosci miedzymodulowych
Zakres:
- `ShopTransport` pobiera liste platnosci przez nowe repozytorium (bez legacy factory)
- `front\\factory\\ShopPaymentMethod` jako fasada do repozytorium domenowego
- `shop\\PaymentMethod` jako fasada do repozytorium domenowego
- zachowanie dotychczasowych podpisow metod (BC)
Checkpoint:
- STOP i prosba o akceptacje po wdrozeniu etapu 3.
### Etap 4: Cleanup + finalne testy + dokumentacja
Zakres:
- usuniecie legacy klas/plikow dla `shop_payment_method`
- uruchomienie testow:
- najpierw targetowane testy PaymentMethod,
- potem caly suite (`composer test` lub `./test.ps1`)
- aktualizacja dokumentacji:
- `docs/DATABASE_STRUCTURE.md`
- `docs/PROJECT_STRUCTURE.md`
- `docs/REFACTORING_PLAN.md`
- `docs/CHANGELOG.md`
- `docs/TESTING.md`
Checkpoint:
- STOP i prosba o finalna akceptacje przed etapem release (zip/commit/push wg procedury KONIEC PRACY, jesli zlecisz).
## 6. Ryzyka i kontrola regresji
1. Ryzyko: utrata kompatybilnosci URL (`view_list`).
Kontrola: tymczasowe aliasy lub redirect + test akcji.
2. Ryzyko: regresja checkout przy pobieraniu metod platnosci.
Kontrola: zachowanie podpisow metod we `front\\factory\\ShopPaymentMethod` i `shop\\PaymentMethod`, testy repozytorium.
3. Ryzyko: `ShopTransport` przestanie pokazywac metody platnosci.
Kontrola: jawne przepiecie zaleznosci i test manualny widoku edycji transportu.
## 7. Kryteria akceptacji
1. `/admin/shop_payment_method/list/` dziala na nowym kontrolerze i nowym widoku.
2. `/admin/shop_payment_method/edit/id={id}` i zapis dzialaja bez `grid`.
3. Brak zaleznosci od legacy `admin\\controls\\ShopPaymentMethod` i `admin\\factory\\ShopPaymentMethod`.
4. `ShopTransport`, frontend checkout i `cron.php` dzialaja na niezmienionych API publicznych.
5. Nowe testy przechodza, a pelny suite nie ma regresji.

View File

@@ -1,187 +1,48 @@
# Testowanie shopPRO
# Testowanie shopPRO
## Szybki start
### Pelny zestaw testow
```bash
composer test
```
Alternatywnie (Windows):
```bash
# Pelny suite (PowerShell — rekomendowane)
./test.ps1
./test.bat
./test-simple.bat
./test-debug.bat
```
Alternatywnie (Git Bash):
```bash
./test.sh
```
### Konkretny plik testowy
```bash
# Konkretny plik
./test.ps1 tests/Unit/Domain/Product/ProductRepositoryTest.php
./test.ps1 tests/Unit/admin/Controllers/ArticlesControllerTest.php
```
### Konkretny test (`--filter`)
```bash
# Konkretny test
./test.ps1 --filter testGetQuantityReturnsCorrectValue
# Alternatywne
composer test # standard
./test.bat # testdox (czytelna lista)
./test-simple.bat # kropki
./test-debug.bat # debug
./test.sh # Git Bash
```
## Aktualny stan suite
Ostatnio zweryfikowano: 2026-02-18
## Aktualny stan
```text
OK (610 tests, 1817 assertions)
```
Aktualizacja po usunieciu autoload/shop/ — 12 legacy klas (2026-02-18, ver. 0.294):
```text
Pelny suite: OK (610 tests, 1817 assertions)
Zmodyfikowane testy: PromotionRepositoryTest (cache key \shop\Promotion → PromotionRepository)
Zmodyfikowane testy: ShopOrderControllerTest (zamiana \shop\Coupon → CouponRepository DI)
```
Zweryfikowano: 2026-02-18 (ver. 0.294)
Aktualizacja po migracji front\controls\Site + front\view\Site (2026-02-17, ver. 0.293):
```text
Pelny suite: OK (610 tests, 1816 assertions)
Brak nowych testow — czysty rename/restructure (klasy statyczne, bez logiki biznesowej)
```
## Konfiguracja
Aktualizacja po migracji ShopProduct + ShopPaymentMethod + ShopPromotion + ShopStatuses + ShopTransport frontend (2026-02-17, ver. 0.292):
```text
Pelny suite: OK (610 tests, 1816 assertions)
Nowe testy: ProductRepositoryTest (+20: getSkuWithFallback, getEanWithFallback, isProductActiveCached, productCategoriesFront, getWarehouseMessageZero/Nonzero, topProductIds, newProductIds, promotedProductIdsCached, getMinimalPrice, productImageCached, productNameCached, productUrlCached, randomProductIds, productWp)
Nowe testy: PaymentMethodRepositoryTest (+5: paymentMethodsCached, paymentMethodCached, paymentMethodsByTransportCached, forTransportCached)
Nowe testy: PromotionRepositoryTest (+7: applyTypeWholeBasket, applyTypeCategoriesOr, applyTypeCategoryCondition 2 scenariusze, applyTypeCategoriesAnd)
Nowe testy: TransportRepositoryTest (+5: transportCostCached, findActiveByIdCached, findActiveByIdCachedNull, forPaymentMethod, forPaymentMethodEmpty)
Nowy stub: tests/stubs/ShopProduct.php (shop\Product::is_product_on_promotion, get_product_price)
```
Aktualizacja po migracji ShopProducer frontend (2026-02-17, ver. 0.291):
```text
Pelny suite: OK (573 tests, 1738 assertions)
Nowe testy: ProducerRepositoryTest (+5: allActiveProducers full/null, findForFrontend invalid/notFound/withLanguage)
Nowe testy: ShopProducerControllerTest (+3: constructorAcceptsRepository, hasMainActionMethods, constructorRequiresProducerRepository)
```
Aktualizacja po migracji ShopCoupon + ShopOrder frontend (2026-02-17, ver. 0.290):
```text
Pelny suite: OK (565 tests, 1716 assertions)
Nowe testy: CouponRepositoryTest (+12: findByName 3 scenariusze, isAvailable 5 scenariuszy, markAsUsed 2 scenariusze, incrementUsedCount 2 scenariusze)
Nowe testy: ShopCouponControllerTest (+3: constructorAcceptsRepository, hasMainActionMethods, constructorRequiresCouponRepository)
Nowe testy: OrderRepositoryTest (+10: findIdByHash 3 scenariusze, findHashById 2 scenariusze, orderDetailsFrontend 3 scenariusze, generateOrderNumber 2 scenariusze)
Nowe testy: ShopOrderControllerTest (+3: constructorAcceptsRepository, hasMainActionMethods, constructorRequiresOrderRepository)
```
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):
```text
Pelny suite: OK (484 tests, 1528 assertions)
Nowe testy: BasketCalculatorTest (+8: summaryWp, countProducts, countProductsText — singular/plural/cast)
```
Aktualizacja po migracji Scontainers + ShopAttribute frontend (2026-02-17, ver. 0.287):
```text
Pelny suite: OK (476 tests, 1512 assertions)
Nowe testy: ScontainersRepositoryTest (+2: frontScontainerDetails, frontScontainerDetailsFallback)
Nowe testy: AttributeRepositoryTest (+4: frontAttributeDetails, frontAttributeDetailsFallback, frontValueDetails, frontValueDetailsFallback)
```
Aktualizacja po migracji Layouts + Menu/Pages frontend (2026-02-17, ver. 0.286):
```text
Pelny suite: OK (470 tests, 1484 assertions)
Nowe testy: LayoutsRepositoryTest (+8: categoryDefaultLayoutId, getDefaultLayout, getProductLayout fallback, getArticleLayout, getCategoryLayout fallback, getActiveLayout, getActiveLayout fallback, getActiveLayout null)
Nowe testy: PagesRepositoryTest (+8: frontPageDetails, frontPageDetailsNull, frontMainPageId, frontMainPageIdFallback, frontPageSort, frontMenuDetails, frontMenuDetailsNull, frontMenuPages)
```
Aktualizacja po migracji Banners frontend (2026-02-16, ver. 0.281):
```text
Pelny suite: OK (454 tests, 1449 assertions)
Nowe testy: BannerRepositoryTest (+4: banners flat languages, banners null, mainBanner flat languages, mainBanner null)
```
Aktualizacja po migracji Articles frontend (2026-02-16, ver. 0.280):
```text
Pelny suite: OK (450 tests, 1431 assertions)
Nowe testy: ArticleRepositoryTest (+13: articleDetailsFrontend, copyFromFallback, articlesIds, pageArticlesCount, pageArticlesPagination, articleNoindex, news, topArticles, newsListArticles)
Zaktualizowane: tests/bootstrap.php (stub: S::is_array_fix)
```
Aktualizacja po migracji Newsletter + Languages frontend (2026-02-16, ver. 0.279):
```text
Pelny suite: OK (437 tests, 1398 assertions)
Nowe testy: NewsletterRepositoryTest (+10: unsubscribe, confirmSubscription, getHashByEmail, removeByEmail, signup, constructorOptionalDeps)
Zaktualizowane: tests/bootstrap.php (stuby: S::email_check, S::get_session, S::set_session)
```
Aktualizacja po migracji Settings + Languages frontend (2026-02-16, ver. 0.278):
```text
Pelny suite: OK (427 tests, 1378 assertions)
Nowe testy: SettingsRepositoryTest (+6: allSettings, getSingleValue, bugfix param), LanguagesRepositoryTest (+7: defaultLanguage, activeLanguages, translations)
Zaktualizowane: tests/bootstrap.php (stub CacheHandler: get/set/exists)
```
Aktualizacja po migracji Dashboard + Update + legacy cleanup (2026-02-16, ver. 0.277):
```text
Pelny suite: OK (414 tests, 1335 assertions)
Nowe testy: DashboardControllerTest (4), DashboardRepositoryTest (6), UpdateControllerTest (6), UpdateRepositoryTest (6)
```
Aktualizacja po stabilizacji ShopOrder / Integrations / Global Search (2026-02-15, ver. 0.277):
```text
Pelny suite: OK (385 tests, 1246 assertions)
SettingsControllerTest: OK (7 tests, 10 assertions)
```
Aktualizacja po migracji ShopClients (2026-02-15, ver. 0.274) - testy punktowe:
```text
OK (10 tests, 34 assertions)
```
Aktualizacja po migracji ShopCategory (2026-02-15, ver. 0.275) - testy punktowe:
```text
OK (16 tests, 72 assertions)
```
Pelny suite po migracji ShopCategory (2026-02-15, ver. 0.275):
```text
OK (377 tests, 1197 assertions)
```
Aktualizacja po migracji ShopOrder (2026-02-15, ver. 0.276) - testy punktowe:
```text
OK (8 tests, 49 assertions)
```
Nowe testy dodane 2026-02-15:
- `tests/Unit/Domain/Client/ClientRepositoryTest.php`
- `tests/Unit/admin/Controllers/ShopClientsControllerTest.php`
- `tests/Unit/Domain/Category/CategoryRepositoryTest.php`
- `tests/Unit/admin/Controllers/ShopCategoryControllerTest.php`
- `tests/Unit/Domain/Order/OrderRepositoryTest.php`
- `tests/Unit/admin/Controllers/ShopOrderControllerTest.php`
- **PHPUnit 9.6** via `phpunit.phar`
- **Bootstrap:** `tests/bootstrap.php`
- **Config:** `phpunit.xml`
## Struktura testow
```text
```
tests/
|-- bootstrap.php
|-- stubs/
| |-- CacheHandler.php
| |-- Helpers.php
| `-- ShopProduct.php
| |-- CacheHandler.php (inline w bootstrap)
| |-- Helpers.php (Shared\Helpers\Helpers stub)
| `-- ShopProduct.php (shop\Product stub)
|-- Unit/
| |-- Domain/
| | |-- Article/ArticleRepositoryTest.php
@@ -189,10 +50,14 @@ tests/
| | |-- Banner/BannerRepositoryTest.php
| | |-- Basket/BasketCalculatorTest.php
| | |-- Cache/CacheRepositoryTest.php
| | |-- Coupon/CouponRepositoryTest.php
| | |-- Category/CategoryRepositoryTest.php
| | |-- Coupon/CouponRepositoryTest.php
| | |-- Dictionaries/DictionariesRepositoryTest.php
| | |-- Integrations/IntegrationsRepositoryTest.php
| | |-- Languages/LanguagesRepositoryTest.php
| | |-- Layouts/LayoutsRepositoryTest.php
| | |-- Newsletter/NewsletterRepositoryTest.php
| | |-- Pages/PagesRepositoryTest.php
| | |-- PaymentMethod/PaymentMethodRepositoryTest.php
| | |-- Producer/ProducerRepositoryTest.php
| | |-- Product/ProductRepositoryTest.php
@@ -220,70 +85,17 @@ tests/
| |-- ShopStatusesControllerTest.php
| |-- ShopTransportControllerTest.php
| `-- UsersControllerTest.php
`-- Integration/
```
## Tryby uruchamiania
### 1. TestDox (czytelna lista)
```bash
./test.bat
```
Uruchamia:
```bash
C:\xampp\php\php.exe phpunit.phar --testdox
```
### 2. Standard (kropki)
```bash
./test-simple.bat
```
Uruchamia:
```bash
C:\xampp\php\php.exe phpunit.phar
```
### 3. Debug (pelne logowanie)
```bash
./test-debug.bat
```
Uruchamia:
```bash
C:\xampp\php\php.exe phpunit.phar --debug
```
### 4. PowerShell (najbardziej niezawodne)
```bash
./test.ps1
```
- najpierw probuje `php` z PATH
- jesli brak, probuje m.in. `C:\xampp\php\php.exe`
- zawsze dodaje `--do-not-cache-result`
## Interpretacja wynikow
```text
. = test przeszedl
E = error (blad wykonania)
F = failure (niezgodna asercja)
```
Przyklad sukcesu:
```text
................................................................. 65 / 82 ( 79%)
................. 82 / 82 (100%)
OK (82 tests, 181 assertions)
`-- Integration/ (puste — zarezerwowane)
```
## Dodawanie nowych testow
1. Dodaj plik w odpowiednim module, np. `tests/Unit/Domain/<Module>/<Class>Test.php`.
1. Plik w `tests/Unit/Domain/<Module>/<Class>Test.php` lub `tests/Unit/admin/Controllers/<Class>Test.php`.
2. Rozszerz `PHPUnit\Framework\TestCase`.
3. Nazwy metod zaczynaj od `test`.
4. Trzymaj sie wzorca AAA: Arrange, Act, Assert.
4. Wzorzec AAA: Arrange, Act, Assert.
## Mockowanie (przyklad)
## Mockowanie Medoo
```php
$mockDb = $this->createMock(\medoo::class);
@@ -295,317 +107,10 @@ $value = $repo->getQuantity(123);
$this->assertEquals(42, $value);
```
## Przydatne informacje
## Bootstrap — stuby
- Konfiguracja PHPUnit: `phpunit.xml`
- Bootstrap testow: `tests/bootstrap.php`
- Dodatkowy opis: `tests/README.md`
## Aktualizacja suite
Ostatnio zweryfikowano: 2026-02-12
```text
OK (119 tests, 256 assertions)
```
Nowe testy dodane 2026-02-12:
- `tests/Unit/Domain/User/UserRepositoryTest.php` (25 testow: CRUD, logon, 2FA verify/send, checkLogin, updateById)
- `tests/Unit/admin/Controllers/UsersControllerTest.php` (12 testow: kontrakty + normalizeUser)
Aktualizacja po migracji widokow Users (2026-02-12):
```text
OK (120 tests, 262 assertions)
```
## Aktualizacja suite (finalizacja Users)
Ostatnio zweryfikowano: 2026-02-12
```text
OK (120 tests, 262 assertions)
```
Aktualizacja po migracji Languages (2026-02-12):
```text
OK (130 tests, 301 assertions)
```
Nowe testy dodane 2026-02-12:
- `tests/Unit/Domain/Languages/LanguagesRepositoryTest.php`
- `tests/Unit/admin/Controllers/LanguagesControllerTest.php`
## Aktualizacja suite (release 0.254)
Ostatnio zweryfikowano: 2026-02-12
```text
OK (130 tests, 301 assertions)
```
Nowe testy dodane 2026-02-12:
- `tests/Unit/Domain/Languages/LanguagesRepositoryTest.php`
- `tests/Unit/admin/Controllers/LanguagesControllerTest.php`
## Aktualizacja suite (release 0.255)
Ostatnio zweryfikowano: 2026-02-12
```text
OK (130 tests, 303 assertions)
```
## Aktualizacja suite (release 0.256)
Ostatnio zweryfikowano: 2026-02-12
```text
OK (141 tests, 336 assertions)
```
Nowe testy dodane 2026-02-12:
- `tests/Unit/Domain/Layouts/LayoutsRepositoryTest.php`
- `tests/Unit/admin/Controllers/LayoutsControllerTest.php`
Zaktualizowane testy 2026-02-12:
- `tests/Unit/Domain/Languages/LanguagesRepositoryTest.php` (defaultLanguageId)
- `tests/Unit/admin/Controllers/ArticlesControllerTest.php` (konstruktor + LayoutsRepository)
## Aktualizacja suite (release 0.257)
Ostatnio zweryfikowano: 2026-02-12
```text
OK (150 tests, 372 assertions)
```
Nowe testy dodane 2026-02-12:
- `tests/Unit/Domain/Newsletter/NewsletterRepositoryTest.php`
- `tests/Unit/admin/Controllers/NewsletterControllerTest.php`
## Aktualizacja suite (release 0.258)
Ostatnio zweryfikowano: 2026-02-12
```text
OK (150 tests, 372 assertions)
```
## Aktualizacja suite (release 0.259)
Ostatnio zweryfikowano: 2026-02-12
```text
OK (158 tests, 397 assertions)
```
Nowe testy dodane 2026-02-12:
- `tests/Unit/Domain/Scontainers/ScontainersRepositoryTest.php`
- `tests/Unit/admin/Controllers/ScontainersControllerTest.php`
## Aktualizacja suite (release 0.260)
Ostatnio zweryfikowano: 2026-02-12
```text
OK (165 tests, 424 assertions)
```
Nowe testy dodane 2026-02-12:
- `tests/Unit/Domain/Article/ArticleRepositoryTest.php` (rozszerzenie o testy `restore`, `deletePermanently`, `listArchivedForAdmin`)
- `tests/Unit/admin/Controllers/ArticlesArchiveControllerTest.php`
## Aktualizacja suite (release 0.261)
Ostatnio zweryfikowano: 2026-02-13
```text
OK (176 tests, 439 assertions)
```
Nowe testy/rozszerzenia 2026-02-13:
- `tests/Unit/Domain/Article/ArticleRepositoryTest.php` (nowe przypadki dla `pagesSummaryForArticles`, `updateImageAlt`, `markFileToDelete`)
- `tests/Unit/admin/Controllers/ArticlesControllerTest.php` (nowe kontrakty dla akcji `imageAltChange`, `fileNameChange`, `imageDelete`, `fileDelete`)
## Aktualizacja suite (release 0.261)
Ostatnio zweryfikowano: 2026-02-13
```text
OK (178 tests, 443 assertions)
```
Nowe testy/rozszerzenia 2026-02-13:
- `tests/Unit/Domain/Article/ArticleRepositoryTest.php` (nowe przypadki dla `saveFilesOrder`)
## Aktualizacja suite (Pages migration)
Ostatnio zweryfikowano: 2026-02-13
```text
OK (186 tests, 478 assertions)
```
Nowe testy dodane 2026-02-13:
- `tests/Unit/Domain/Pages/PagesRepositoryTest.php`
- `tests/Unit/admin/Controllers/PagesControllerTest.php`
Zaktualizowane testy 2026-02-13:
- `tests/Unit/admin/Controllers/ArticlesControllerTest.php` (konstruktor z `Domain\\Pages\\PagesRepository`)
## Aktualizacja suite (Integrations refactor, ver. 0.263)
Ostatnio zweryfikowano: 2026-02-13
```text
OK (212 tests, 577 assertions)
```
Nowe testy dodane 2026-02-13:
- `tests/Unit/Domain/Integrations/IntegrationsRepositoryTest.php` (16 testow: getSettings, getSetting, saveSetting, linkProduct, unlinkProduct, getProductSku, apiloGetAccessToken, invalid provider, settings table mapping)
- `tests/Unit/admin/Controllers/IntegrationsControllerTest.php` (10 testow: kontrakty metod, return types, brak metod sellasist/baselinker)
Zaktualizowane pliki:
- `tests/bootstrap.php` (dodany stub `S::remove_special_chars()`)
## Aktualizacja suite (ShopPromotion refactor, ver. 0.264)
Ostatnio zweryfikowano: 2026-02-13
```text
OK (222 tests, 609 assertions)
```
Nowe testy dodane 2026-02-13:
- `tests/Unit/Domain/Promotion/PromotionRepositoryTest.php` (6 testow: find default, save insert, delete, whitelist sortowania, drzewo kategorii)
- `tests/Unit/admin/Controllers/ShopPromotionControllerTest.php` (4 testy: kontrakty metod i DI konstruktora)
## Aktualizacja suite (ShopPromotion fix + date_from, ver. 0.265)
Ostatnio zweryfikowano: 2026-02-13
```text
OK (222 tests, 614 assertions)
```
Zmiany testowe 2026-02-13:
- rozszerzenie `tests/Unit/Domain/Promotion/PromotionRepositoryTest.php` o asercje `date_from`
## Aktualizacja suite (ShopCoupon refactor, ver. 0.266)
Ostatnio zweryfikowano: 2026-02-13
```text
OK (235 tests, 682 assertions)
```
Nowe testy dodane 2026-02-13:
- `tests/Unit/Domain/Coupon/CouponRepositoryTest.php` (8 testow: find default/normalize, save insert/update, delete, whitelist sortowania, drzewo kategorii)
- `tests/Unit/admin/Controllers/ShopCouponControllerTest.php` (5 testow: kontrakty metod, aliasy legacy, DI konstruktora)
Ponowna weryfikacja po poprawkach UI (drzewko + checkboxy): 2026-02-13
- `OK (235 tests, 682 assertions)`
## Aktualizacja suite (ShopStatuses refactor, ver. 0.267)
Ostatnio zweryfikowano: 2026-02-14
```text
OK (254 tests, 736 assertions)
```
Nowe testy dodane 2026-02-14:
- `tests/Unit/Domain/ShopStatus/ShopStatusRepositoryTest.php` (9 testow: find z ID=0, find null apilo, save update, save z ID=0, empty apilo sets null, reject negative ID, getApiloStatusId, getByIntegrationStatusId, allStatuses, whitelist sortowania)
- `tests/Unit/admin/Controllers/ShopStatusesControllerTest.php` (5 testow: kontrakty metod, brak aliasow legacy, return types, DI konstruktora)
## Aktualizacja suite (ShopPaymentMethod refactor, ver. 0.268)
Ostatnio zweryfikowano: 2026-02-14
```text
OK (280 tests, 828 assertions)
```
Nowe testy dodane 2026-02-14:
- `tests/Unit/Domain/PaymentMethod/PaymentMethodRepositoryTest.php` (14 testow: find invalid/null/normalize, save update/null/non-numeric apilo, listForAdmin whitelist, allActive, allForAdmin, findActiveById, isActive, getApiloPaymentTypeId, forTransport)
- `tests/Unit/admin/Controllers/ShopPaymentMethodControllerTest.php` (5 testow: kontrakty metod, brak aliasow legacy, return types, DI konstruktora)
## Aktualizacja suite (ShopTransport refactor, ver. 0.269)
Ostatnio zweryfikowano: 2026-02-14
```text
OK (300 tests, 895 assertions)
```
Nowe testy dodane 2026-02-14:
- `tests/Unit/Domain/Transport/TransportRepositoryTest.php` (14 testow: find invalid/null/normalize/nullables, save insert/update/failure/default reset/switch normalization, listForAdmin whitelist, allActive, getApiloCarrierAccountId, getTransportCost, allForAdmin)
- `tests/Unit/admin/Controllers/ShopTransportControllerTest.php` (5 testow: kontrakty metod, brak aliasow legacy, return types, DI konstruktora z 2 repo)
## Aktualizacja suite (Apilo sync hardening, ver. 0.270)
Ostatnio zweryfikowano: 2026-02-14
```text
OK (300 tests, 895 assertions)
```
Zmiany testowe 2026-02-14:
- brak nowych testow; pelna regresja po zmianach sync Apilo (TPAY -> Apilo) przeszla bez bledow
## Aktualizacja suite (ShopAttribute refactor, ver. 0.271)
Ostatnio zweryfikowano: 2026-02-14
```text
OK (312 tests, 948 assertions)
```
Nowe testy dodane 2026-02-14:
- `tests/Unit/Domain/Attribute/AttributeRepositoryTest.php` (5 testow: domyslne dane cechy, whitelist sortowania/paginacji, zapis wartosci i domyslnej, usuwanie pustych tlumaczen, jezyk domyslny)
- `tests/Unit/admin/Controllers/ShopAttributeControllerTest.php` (7 testow: kontrakty metod, brak aliasow legacy, return types, DI konstruktora, walidacja `validateValuesRows`)
## Aktualizacja suite (ShopProductSets refactor, ver. 0.272)
Ostatnio zweryfikowano: 2026-02-15
```text
OK (324 tests, 1000 assertions)
```
Nowe testy dodane 2026-02-15:
- `tests/Unit/Domain/ProductSet/ProductSetRepositoryTest.php` (7 testow: find default/normalize, save insert/update, delete invalid, whitelist sortowania/paginacji, allSets)
- `tests/Unit/admin/Controllers/ShopProductSetsControllerTest.php` (5 testow: kontrakty metod, aliasy legacy, return types, DI konstruktora)
## Aktualizacja suite (ShopProducer refactor, ver. 0.273)
Ostatnio zweryfikowano: 2026-02-15
```text
OK (338 tests, 1063 assertions)
```
Nowe testy dodane 2026-02-15:
- `tests/Unit/Domain/Producer/ProducerRepositoryTest.php` (9 testow: find default/normalize, save insert/update, delete invalid/success, whitelist sortowania/paginacji, allProducers, producerProducts)
- `tests/Unit/admin/Controllers/ShopProducerControllerTest.php` (5 testow: kontrakty metod, aliasy legacy, return types, DI konstruktora)
## Aktualizacja suite (ShopProduct mass_edit, ver. 0.274)
Ostatnio zweryfikowano: 2026-02-15
```text
OK (351 tests, 1091 assertions)
```
Nowe testy dodane 2026-02-15:
- `tests/Unit/Domain/Product/ProductRepositoryTest.php` (rozszerzenie: `allProductsForMassEdit`, `getProductsByCategory`, `applyDiscountPercent`)
- `tests/Unit/admin/Controllers/ShopProductControllerTest.php` (7 testow: kontrakty metod, return types, DI konstruktora)
## Aktualizacja suite (Layouts + Menu/Pages frontend, ver. 0.286)
Ostatnio zweryfikowano: 2026-02-17
```text
OK (470 tests, 1484 assertions)
```
Nowe testy dodane 2026-02-17:
- `tests/Unit/Domain/Layouts/LayoutsRepositoryTest.php` (rozszerzenie: +8 testow frontend: categoryDefaultLayoutId, getDefaultLayout, getProductLayout, getArticleLayout, getCategoryLayout, getActiveLayout)
- `tests/Unit/Domain/Pages/PagesRepositoryTest.php` (rozszerzenie: +8 testow frontend: frontPageDetails, frontMainPageId, frontPageSort, frontLangUrl, frontMenuDetails, frontMenuPages)
## Aktualizacja suite (BasketCalculator + ShopBasketController, ver. 0.288)
Ostatnio zweryfikowano: 2026-02-17
```text
OK (484 tests, 1528 assertions)
```
Nowe testy dodane 2026-02-17:
- `tests/Unit/Domain/Basket/BasketCalculatorTest.php` (8 testow: summaryWp, summaryWpEmpty, countProducts, countProductsEmpty, countProductsTextSingular, countProductsTextPlural2to4, countProductsTextPlural5Plus, countProductsTextCastsToInt)
## Aktualizacja suite (Scontainers + ShopAttribute frontend, ver. 0.287)
Ostatnio zweryfikowano: 2026-02-17
```text
OK (476 tests, 1512 assertions)
```
Nowe testy dodane 2026-02-17:
- `tests/Unit/Domain/Scontainers/ScontainersRepositoryTest.php` (rozszerzenie: +2 testow frontend: frontScontainerDetails, frontScontainerDetailsFallback)
- `tests/Unit/Domain/Attribute/AttributeRepositoryTest.php` (rozszerzenie: +4 testow frontend: frontAttributeDetails, frontAttributeDetailsFallback, frontValueDetails, frontValueDetailsFallback)
`tests/bootstrap.php` rejestruje autoloader i definiuje stuby:
- `Redis`, `RedisConnection` — klasy Redis (aby nie wymagac rozszerzenia)
- `Shared\Cache\CacheHandler` — inline stub z `get()`/`set()`/`exists()`/`delete()`/`deletePattern()`
- `Shared\Helpers\Helpers` — z `tests/stubs/Helpers.php`
- `shop\Product` — z `tests/stubs/ShopProduct.php`