Files
shopPRO/docs/FRONTEND_REFACTORING_PLAN.md
Jacek Pyziak 782dd35d5b ver. 0.278: Settings + Languages frontend migration, bug fix get_single_settings_value
- Add cached frontend methods to existing Domain repositories (allSettings, getSingleValue, defaultLanguage, activeLanguages, translations)
- Convert front\factory\Settings and Languages to facades delegating to Domain repositories
- Fix get_single_settings_value() - was hardcoded to 'firm_name', now uses $param correctly
- Add CacheHandler stub methods (get/set/exists) to test bootstrap
- Establish architectural rule: Domain classes are shared between admin and frontend

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-16 13:50:27 +01:00

20 KiB
Raw Blame History

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 Router główny route(), check_url_params(), title()
ShopBasket MIXED Operacje koszyka, add/remove/quantity, checkout
ShopClient Fasada Deleguje do factory
ShopOrder KRYTYCZNY Webhooki płatności (tPay, Przelewy24, Hotpay) — bezpośrednie operacje DB
ShopProduct Fasada lazy_loading, warehouse_message, draw_product_attributes
ShopProducer Fasada list(), products()
ShopCoupon Fasada use_coupon(), delete_coupon()
Newsletter Fasada signin(), confirm(), unsubscribe()

front/factory/ (20 klas — pobieranie danych + logika)

Klasa Status Priorytet migracji
ShopProduct ORYGINALNA LOGIKA (~370 linii) KRYTYCZNY — product_details(), promoted/top/new products
ShopOrder ORYGINALNA LOGIKA (~180 linii) KRYTYCZNY — basket_save() tworzy zamówienie
ShopClient ORYGINALNA LOGIKA KRYTYCZNY — login (BUG: hardcoded bypass 'Legia1916'), signup, recover
ShopCategory ORYGINALNA LOGIKA WYSOKI — złożone SQL z language fallback
Articles ORYGINALNA LOGIKA WYSOKI — złożone SQL z language fallback
ShopPromotion ORYGINALNA LOGIKA WYSOKI — silnik promocji (5 typów)
ShopBasket Fasada ŚREDNI — summary_price, count
ShopTransport CZĘŚCIOWO zmigrowana ŚREDNI — transport_methods z filtrowaniem
ShopPaymentMethod ZMIGROWANA (Domain)
ShopStatuses ZMIGROWANA (Domain)
Scontainers ZMIGROWANA (Domain)
Newsletter CZĘŚCIOWO zmigrowana ŚREDNI
Settings Fasada (BUG: get_single_settings_value ignoruje $param) NISKI
Languages Fasada NISKI
Layouts Fasada NISKI
Banners Fasada NISKI
Menu Fasada NISKI
Pages Fasada NISKI
ShopAttribute Fasada NISKI
ShopCoupon Model danych NISKI

front/view/ (12 klas — renderowanie)

Klasa Status
Site KRYTYCZNY — show() ~600 linii, pattern substitution engine
ShopCategory VIEW z logiką routingu (infinite scroll vs pagination)
Articles, Banners, Languages, Menu, Newsletter, Scontainers Czyste VIEW
ShopClient, ShopOrder, ShopPaymentMethod Czyste VIEW
ShopTransport PUSTA klasa (placeholder)

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 ZMIGROWANA (fasada do Domain)
Producer ZMIGROWANA (fasada do Domain)
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 ~1130 htacces() ~500 linii — generowanie .htaccess; reszta to utility
Tpl ~90 OK — silnik szablonów, bez zmian
CacheHandler ~50 OK — Redis wrapper
RedisConnection ~40 OK — singleton
Email ~100 OK — PHPMailer wrapper (drobne poprawki)
Log ~20 OK — audit logging
DbModel ~60 OK — base ORM
Cache ~50 LEGACY — file-based cache, rozważyć usunięcie
Html ~80 OK — form helpers
Image ~100 OK — GD wrapper
Mobile_Detect Third-party, bez zmian

cms/ (1 klasa)

Klasa Status
Layout BUG w __get() — referuje $this->data które nie istnieje

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'
  2. front\factory\Settings::get_single_settings_value() — ignoruje $param, zawsze zwraca firm_name
  3. front\factory\Newsletter::newsletter_unsubscribe() — błędna składnia SQL w delete
  4. cms\Layout::__get() — referuje nieistniejące $this->data
  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/SettingsRepositoryallSettings($skipCache), getSingleValue($param) (FIX: uzywa poprawnie $param)
  • Domain/Languages/LanguagesRepositorydefaultLanguage(), 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: Category Frontend Service

Cel: Migracja front\factory\ShopCategory do Domain.

NOWE:

  • Domain/Category/CategoryFrontendService.phpgetCategorySort(), categoryName(), categoryUrl(), blogCategoryProducts(), categoryProducts(), productsId() (złożone SQL z sortowaniem/language fallback/paginacją), categoryDetails(), categoriesDetails() (rekurencyjne), categoryProductsCount()
  • Testy: CategoryFrontendServiceTest

ZMIANA:

  • front/factory/ShopCategory → fasada
  • front/factory/ShopProduct::product_categories() → deleguje do CategoryFrontendService

Etap: Banners, Menu, Pages, Articles, Layouts Frontend Services

Cel: Migracja pozostałych fabryk "liściowych".

NOWE:

  • Domain/Banner/BannerFrontendService.phpmainBanner(), banners() (filtrowanie po datach)
  • Domain/Menu/MenuFrontendService.phpmenuDetails(), menuPages() (rekurencja)
  • Domain/Pages/PagesFrontendService.phppageDetails(), mainPageId(), langUrl(), pageSort()
  • Domain/Article/ArticleFrontendService.phparticleDetails(), news(), pageArticles(), pageArticlesCount(), generateTableOfContents(), generateHeadersIds()
  • Domain/Layouts/LayoutsFrontendService.phpactiveLayout(), articleLayout(), productLayout(), categoryLayout(), defaultLayout(), categoryDefaultLayout()
  • Testy: 5 plików testowych

ZMIANA:

  • front/factory/Banners, Menu, Pages, Articles, Layouts → fasady

BUG FIX: cms\Layout::__get() — poprawka referencji do $this->data


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)

Cel: Migracja front\factory\ShopClient + NAPRAWIENIE hardcoded password bypass.

NOWE:

  • Domain/Client/ClientFrontendService.php:
    • login()BEZ bypassa 'Legia1916', z opcjonalną migracją md5 → password_hash
    • signup(), registerConfirm(), sendPasswordRecovery(), resetPassword()
    • clientDetails(), clientOrders()
    • CRUD adresów: saveAddress(), deleteAddress(), getAddresses(), markAddressAsCurrent()
  • Testy: ClientFrontendServiceTestKRYTYCZNY test: login z 'Legia1916' NIE przechodzi

ZMIANA:

  • front/factory/ShopClient → fasada
  • front/controls/ShopClient → deleguje do serwisu

Etap: Transport, Payment, Coupon Frontend Services

Cel: Frontend serwisy dla transportu, płatności i kuponów.

NOWE:

  • Domain/Transport/TransportFrontendService.phptransportMethods() (filtrowanie WP, free delivery), transportCost(), transportDetails()
  • Domain/PaymentMethod/PaymentMethodFrontendService.phpactivePaymentMethods(), paymentMethodsByTransport(), paymentMethodDetails()
  • Domain/Coupon/CouponFrontendService.phpvalidateCoupon(), 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

Cel: Migracja front\factory\ShopOrder::basket_save() (~180 linii).

NOWE:

  • Domain/Order/OrderFrontendService.php:
    • createOrder() — tworzenie zamówienia z koszyka (walidacja, kalkulacja cen, insert, redukcja stanów, obsługa kuponu, wysyłka emaili, auto-status dla pobrania)
    • generateOrderNumber() — format YYYY/MM/NNN
    • orderDetails(), orderIdByHash(), orderHashById()
  • Testy: OrderFrontendServiceTest

ZMIANA:

  • front/factory/ShopOrder → fasada

Etap: Payment Webhook Service

Cel: Wyodrębnienie webhooków płatności z front\controls\ShopOrder.

NOWE:

  • Domain/Payment/PaymentWebhookService.php:
    • processTpay(array $params) — weryfikacja tPay
    • processPrzelewy24(array $params) — weryfikacja przez API + walidacja kwoty
    • processHotpay(array $params) — walidacja SHA256 hash
    • private markOrderPaid() — wspólna logika (update status + email + Apilo sync)
  • Testy: PaymentWebhookServiceTest

ZMIANA:

  • front/controls/ShopOrder — webhooki stają się thin wrappers

POPRAWA: Zamiana file_put_contents('tpay.txt') na \Log::save_log()


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.phprender(), 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.phpinit() (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) jeśli wszystkie użycia przeniesione na CacheHandler
  • 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\Produtshop\Product
  • BUG FIX: front\factory\Newsletter::newsletter_unsubscribe() — poprawka SQL

Podsumowanie

Etap Zakres Priorytet Nowe klasy Domain Testy
Settings + Languages Fundamenty FUNDAMENT 2 serwisy 2
Category Frontend Kategorie WYSOKI 1 serwis 1
Banners/Menu/Pages/Articles/Layouts Treści ŚREDNI 5 serwisów 5
Promotion Engine Promocje KRYTYCZNY 1 serwis 1
Product Frontend Produkty KRYTYCZNY 1 serwis 1
Client/Auth (security fix) Klienci KRYTYCZNY 1 serwis 1
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.

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)