Files
shopPRO/docs/LEGACY_SHOP_REFACTORING_PLAN.md
Jacek Pyziak 69e78ca248 ver. 0.294: Remove all 12 legacy autoload/shop/ classes (~2363 lines)
Complete Domain-Driven Architecture migration:
- Phase 1-4: Transport, ProductSet, Coupon, Shop, Search, Basket,
  ProductCustomField, Category, ProductAttribute, Promotion
- Phase 5: Order (~562 lines) + Product (~952 lines)
- ~20 Product methods migrated to ProductRepository
- Apilo sync migrated to OrderAdminService
- Production hotfixes: stale Redis cache (prices 0.00), unqualified
  Product:: refs in LayoutEngine, object->array template conversion
- AttributeRepository::getAttributeValueById() Redis cache added

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-18 02:05:39 +01:00

12 KiB
Raw Blame History

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:171new \shop\Coupon($id) (do przeniesienia w fazie Order)
  • front\Controllers\ShopOrderController.php:139new \shop\Coupon($id)
  • admin\Controllers\ShopOrderController.php:170new \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:32getAttributeName(), get_value_name()
  • templates/shop-product/_partial/product-attribute.php:13get_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