Files
shopPRO/REFACTORING_PLAN.md

49 KiB
Raw Blame History

Plan Refaktoryzacji shopPRO - Domain-Driven Architecture

Cel

Stopniowe przeniesienie logiki biznesowej do architektury warstwowej:

  • Domain/ - logika biznesowa (core)
  • Admin/ - warstwa administratora
  • Frontend/ - warstwa użytkownika
  • Shared/ - współdzielone narzędzia

Docelowa struktura

autoload/
├── Domain/              # Logika biznesowa (CORE) - namespace \Domain\
│   ├── Product/
│   │   ├── ProductRepository.php    # ✅ Zmigrowane (getQuantity, getPrice, getName, find, updateQuantity, archive, unarchive)
│   │   ├── ProductService.php       # Logika biznesowa (przyszłość)
│   │   └── ProductCacheService.php  # Cache produktu (przyszłość)
│   ├── Banner/
│   │   └── BannerRepository.php     # ✅ Zmigrowane (find, delete, save)
│   ├── Settings/
│   │   └── SettingsRepository.php   # ✅ Zmigrowane (saveSettings, getSettings) - bezposrednio DB
│   ├── Dictionaries/
│   │   └── DictionariesRepository.php # ✅ Zmigrowane (listForAdmin, find, save, delete, allUnits)
│   ├── Cache/
│   │   └── CacheRepository.php      # ✅ Zmigrowane (clearCache)
│   ├── Order/
│   ├── Category/
│   └── ...
│
├── admin/               # Warstwa administratora (istniejący katalog!)
│   ├── Controllers/     # Nowe kontrolery - namespace \admin\Controllers\
│   │   ├── ArticlesController.php
│   │   ├── BannerController.php
│   │   ├── DictionariesController.php
│   │   ├── FilemanagerController.php
│   │   ├── ProductArchiveController.php
│   │   └── SettingsController.php
│   ├── controls/        # Stare kontrolery (legacy fallback)
│   ├── factory/         # Stare helpery (legacy)
│   └── view/            # Widoki (statyczne - OK bez zmian)
│
├── Frontend/            # Warstwa użytkownika (przyszłość)
│   ├── Controllers/
│   └── Services/
│
├── Shared/              # Współdzielone narzędzia
│   ├── Cache/
│   │   ├── CacheHandler.php
│   │   └── RedisConnection.php
│   └── Helpers/
│       └── S.php
│
└── [LEGACY]             # Stare klasy (stopniowo deprecated)
    ├── shop/
    ├── admin/factory/
    └── front/factory/

WAŻNE: Konwencja namespace → katalog (Linux case-sensitive!)

  • \Domain\autoload/Domain/ (duże D - nowy katalog)
  • \admin\Controllers\autoload/admin/Controllers/ (małe a - istniejący katalog)
  • NIE używać \Admin\ (duże A) bo na serwerze Linux katalog 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

// ❌ STARE - statyczne
class Product {
    public static function getQuantity($id) {
        global $mdb;
        return $mdb->get('pp_shop_products', 'quantity', ['id' => $id]);
    }
}

// ✅ NOWE - instancje z DI
class ProductRepository {
    private $db;

    public function __construct($db) {
        $this->db = $db;
    }

    public function getQuantity($id) {
        return $this->db->get('pp_shop_products', 'quantity', ['id' => $id]);
    }
}

3. Fasady dla kompatybilności

// Stara klasa wywołuje nową
namespace shop;

class Product {
    public static function getQuantity($id) {
        global $mdb;
        $repo = new \Domain\Product\ProductRepository($mdb);
        return $repo->getQuantity($id);
    }
}

Proces migracji funkcji

Krok 1: Wybór funkcji

  • Wybierz prostą funkcję statyczną
  • Sprawdź jej zależności
  • Przeanalizuj gdzie jest używana

Krok 2: Stworzenie nowej struktury

  • Utwórz folder Domain/{Module}/
  • Stwórz odpowiednią klasę (Repository/Service/Entity)
  • Przenieś logikę

Krok 3: Znalezienie użyć

grep -r "Product::getQuantity" .

Krok 4: Aktualizacja wywołań

  • Opcja A: Bezpośrednie wywołanie nowej klasy
  • Opcja B: Fasada w starej klasie (zalecane na początek)

Krok 5: Testy

  • Napisz test jednostkowy dla nowej funkcji
  • Sprawdź czy stare wywołania działają

Status migracji

Zmigrowane moduły

  • Cache (częściowo)
    • CacheHandler - ma delete/deletePattern
    • RedisConnection - singleton
    • S::clear_product_cache() - nowa metoda

🔄 Status modułów

  • Product

    • get_product_quantity() - ZMIGROWANE (2025-02-05) 🎉
      • Nowa klasa: Domain\Product\ProductRepository::getQuantity()
      • Fasada w: shop\Product::get_product_quantity()
      • Test: tests/Unit/Domain/Product/ProductRepositoryTest.php
      • Testy: 5/5 przechodzą
      • Aktualizacja: ver. 0.238
      • Użycie DI: Konstruktor przyjmuje $db
    • get_product_price() - ZMIGROWANE (2026-02-05) 🎉
      • Nowa metoda: Domain\Product\ProductRepository::getPrice()
      • Fasada w: shop\Product::get_product_price()
      • Testy: 4 nowe testy (cena regularna, promocyjna, promo wyższa, nie znaleziono)
      • Użycie: front\factory\ShopPromotion (linia 132)
      • Aktualizacja: ver. 0.239
    • get_product_name() - ZMIGROWANE (2026-02-05) 🎉
      • Nowa metoda: Domain\Product\ProductRepository::getName()
      • Fasada w: shop\Product::get_product_name()
      • Testy: 2 nowe testy (nazwa znaleziona, nie znaleziona)
      • Użycie: brak aktywnych wywołań (przygotowane na przyszłość)
      • Aktualizacja: ver. 0.239
    • archive() / unarchive() - ZMIGROWANE (2026-02-06) 🎉
      • Nowe metody: Domain\Product\ProductRepository::archive(), unarchive()
      • Nowy kontroler: admin\Controllers\ProductArchiveController (DI, instancyjny)
      • Szablony: admin/templates/product-archive/ (rename z archive/, dawniej product_archive/)
      • Testy: 4 nowe testy repozytorium + 6 testów kontrolera
      • FIX: SQL bug w ajax_products_list_archive() (puste wyszukiwanie + brak archive = 1)
      • Dalsze porządki: ver. 0.252 (nowy table-list, wydzielony custom script, usunięte legacy pliki)
      • Aktualizacja: ver. 0.241 / 0.252
    • is_product_on_promotion() - NASTĘPNA 👉
  • Banner (DEMO pełnej migracji kontrolera)

    • BannerRepository - ZMIGROWANE (2026-02-05) 🎉
      • Nowa klasa: Domain\Banner\BannerRepository (find, delete, save, saveTranslations)
      • Nowy kontroler: admin\Controllers\BannerController (DI, instancyjny)
      • Router: admin\Site::route() → sprawdza nowy kontroler → fallback na stary
      • Testy: 4 testy (find z tłumaczeniami, not found, delete, save)
      • Stary kontroler admin\controls\Banners działa jako niezależny fallback
      • Stara factory admin\factory\Banners zachowana bez zmian (fallback)
      • Aktualizacja: ver. 0.239
  • Articles (migracja kontrolera - etap edit/details)

    • ArticleRepository::find() - ZMIGROWANE (2026-02-06) 🎉
      • Nowa klasa: Domain\Article\ArticleRepository (find: artykul + relacje)
      • Nowy kontroler: admin\Controllers\ArticlesController (DI, instancyjny)
      • Zmigrowana akcja: article_edit -> edit (mapowanie w admin\Site::$actionMap)
      • Kompatybilność: admin\factory\Articles::article_details() deleguje do nowego repozytorium
      • Legacy cleanup: metody przejęte przez nowe kontrolery oznaczone @deprecated w admin\controls\Articles|Banners|Settings
      • Testy repozytorium rozszerzone o czyszczenie nieprzypisanych plik<69>w/zdj<64><6A>
      • Aktualizacja: ver. 0.243
    • ArticleRepository::save() - ZMIGROWANE (2026-02-06) 🎉
      • Metoda save() z prywatnych helperow (buildArticleRow, buildLangRow, saveTranslations, savePages, assignTempFiles, assignTempImages, deleteMarkedFiles, deleteMarkedImages)
      • Zmigrowana akcja: article_save -> save (mapowanie w admin\Site::$actionMap)
      • Kompatybilnosc: admin\factory\Articles::article_save() deleguje do repozytorium
      • Testy: 7 nowych testow save (create, update, translations, pages, marked delete)
      • Aktualizacja: ver. 0.244
    • ArticleRepository::archive() - ZMIGROWANE (2026-02-06) 🎉
      • Metoda archive() (ustawia status = -1)
      • Zmigrowana akcja: article_delete -> delete (mapowanie w admin\Site::$actionMap)
      • Kompatybilnosc: admin\factory\Articles::articles_set_archive() deleguje do repozytorium
      • Testy: 2 nowe testy archive (success, failure)
      • Aktualizacja: ver. 0.245
    • ArticlesController::browseList() - ZMIGROWANE (2026-02-07) 🎉
      • Nowa metoda kontrolera: browseList() (DI, instancyjna)
      • Zmigrowana akcja: browse_list -> browseList (mapowanie w admin\Site::$actionMap)
      • Legacy cleanup: usuniety autoload/admin/controls/class.Articles.php (brak fallback dla modułu Articles)
      • Testy: 2 nowe testy kontraktu kontrolera (method exists + return type)
    • ArticlesController::galleryOrderSave() - ZMIGROWANE (2026-02-07) 🎉
      • Nowa metoda kontrolera: galleryOrderSave() (AJAX)
      • Zmigrowana akcja: gallery_order_save -> galleryOrderSave (mapowanie w admin\Site::$actionMap)
      • Implementacja: używa Domain\Article\ArticleRepository::saveGalleryOrder()
      • Testy: 2 nowe testy kontraktu kontrolera (method exists + return type)
    • Usuniecie legacy kontrolera Articles - ZMIGROWANE (2026-02-07) 🎉
      • Usuniety plik: autoload/admin/controls/class.Articles.php
      • Wymaganie dla aktualizacji: dodac wpis do ver_X.XXX_files.txt
      • Wpis do usuniecia: F: ../autoload/admin/controls/class.Articles.php
    • Stabilizacja generatora .htaccess - ZMIGROWANE (2026-02-07) 🎉
      • FIX: regula admin ma QSA (query string dla sortowania/filtrow)
      • FIX: \S::htacces() komentuje AddHandler|SetHandler|ForceType dla zgodnosci z hostingiem
      • UPDATE: libraries/htaccess.conf zaktualizowany, aby poprawki nie znikaly po regeneracji
  • Settings (migracja kontrolera)

    • SettingsRepository - ZMIGROWANE (2026-02-05) 🎉
      • Nowa klasa: Domain\Settings\SettingsRepository (saveSettings, getSettings)
      • Aktualny stan: bezpośredni dostęp do DB (usunięta delegacja do admin\factory\Settings) - ver. 0.250
      • Nowy kontroler: admin\Controllers\SettingsController (DI, instancyjny)
      • Testy: 3 testy (instancja, metody)
      • Stary kontroler admin\controls\Settings zachowany jako fallback
      • Aktualizacja: ver. 0.240 / 0.250
    • CacheRepository - ZMIGROWANE (2026-02-05) 🎉
      • Nowa klasa: Domain\Cache\CacheRepository (clearCache)
      • Używa \S::delete_dir() + \RedisConnection
      • Testy: 4 testy (z Redis, bez Redis, niedostępny, struktura)
      • Aktualizacja: ver. 0.240
  • Dictionaries (migracja kontrolera i repozytorium)

    • DictionariesRepository - ZMIGROWANE (2026-02-09) 🎉
      • Nowa klasa: Domain\Dictionaries\DictionariesRepository (listForAdmin, find, save, delete, allUnits)
      • Nowy kontroler: admin\Controllers\DictionariesController (DI, instancyjny)
      • Migracja na nowe komponenty: components/table-list + components/form-edit
      • Legacy cleanup: usunięto klasy z admin\controls, admin\factory, front\factory
      • Aktualizacja: ver. 0.251
  • Filemanager (migracja routingu)

    • FilemanagerController - ZMIGROWANE (2026-02-10) 🎉
      • Nowy kontroler: admin\Controllers\FilemanagerController
      • Naprawa błędu: Invalid Key
      • Legacy cleanup: usunięto autoload/admin/controls/class.Filemanager.php i autoload/admin/view/class.FileManager.php
      • Aktualizacja: ver. 0.252
  • Users (migracja kontrolera i repozytorium)

    • UserRepository - ZMIGROWANE (2026-02-12) 🎉
      • Nowa klasa: Domain\User\UserRepository (find, getById, save, delete, checkLogin, logon, details, updateById, sendTwofaCode, verifyTwofaCode)
      • Nowy kontroler: admin\Controllers\UsersController (DI, instancyjny: view_list, user_edit, user_save, user_delete, login_form, twofa)
      • Router: admin\Site - factory wpis dla modulu Users
      • Fasada: admin\factory\Users deleguje do repozytorium (backward compatibility dla login/2FA flow)
      • AJAX: admin/ajax/users.php - check_login oparty o UserRepository
      • Legacy cleanup: usuniety autoload/admin/controls/class.Users.php
      • Testy: 25 testow repozytorium (CRUD, logon, 2FA, checkLogin) + 12 testow kontrolera (kontrakty + normalizeUser)
  • Integrations (migracja kontrolera i repozytorium + cleanup Sellasist/Baselinker)

    • IntegrationsRepository - ZMIGROWANE (2026-02-13) 🎉
      • Nowa klasa: Domain\Integrations\IntegrationsRepository (settings Apilo/ShopPRO, OAuth, product linking, API fetch)
      • Nowy kontroler: admin\Controllers\IntegrationsController (DI, instancyjny)
      • Router: admin\Site - factory wpis dla modulu Integrations
      • Fasada: admin\factory\Integrations deleguje do repozytorium (tylko Apilo + ShopPRO)
      • CLEANUP: usunieto integracje Sellasist i Baselinker z calego projektu
      • Usuniete pliki: controls/Integrations, controls/Baselinker, factory/Baselinker, front/factory/Shop, shop/ShopStatus, szablony sellasist/baselinker
      • Wyczyszczone referencje w: cron.php, Order, ShopStatuses, ShopTransport, ShopPaymentMethod, ShopProduct, config.php, front/factory/*
      • Testy: 16 nowych testow (repozytorium) + 10 testow kontrolera
      • Aktualizacja: ver. 0.263

📋 Do zrobienia

  • Order
  • Category
  • ShopAttribute
  • ShopProduct (factory)

Testowanie

Framework: PHPUnit

Instalacja:

composer require --dev phpunit/phpunit

Struktura testów

tests/
├── Unit/
│   ├── Domain/
│   │   ├── Article/ArticleRepositoryTest.php
│   │   ├── Banner/BannerRepositoryTest.php
│   │   ├── Cache/CacheRepositoryTest.php
│   │   ├── Dictionaries/DictionariesRepositoryTest.php
│   │   ├── Product/ProductRepositoryTest.php
│   │   ├── Settings/SettingsRepositoryTest.php
│   │   ├── User/UserRepositoryTest.php
│   │   └── Integrations/IntegrationsRepositoryTest.php
│   └── admin/
│       └── Controllers/
│           ├── ArticlesControllerTest.php
│           ├── DictionariesControllerTest.php
│           ├── IntegrationsControllerTest.php
│           ├── ProductArchiveControllerTest.php
│           ├── SettingsControllerTest.php
│           └── UsersControllerTest.php
└── Integration/

Łącznie: 212 testów, 577 asercji

Przykład testu

// tests/Unit/Domain/Product/ProductRepositoryTest.php
use PHPUnit\Framework\TestCase;
use Domain\Product\ProductRepository;

class ProductRepositoryTest extends TestCase {
    public function testGetQuantityReturnsCorrectValue() {
        // Arrange
        $mockDb = $this->createMock(\medoo::class);
        $mockDb->method('get')->willReturn(10);

        $repo = new ProductRepository($mockDb);

        // Act
        $quantity = $repo->getQuantity(123);

        // Assert
        $this->assertEquals(10, $quantity);
    }
}

Zasady kodu

1. SOLID Principles

  • Single Responsibility - jedna klasa = jedna odpowiedzialność
  • Open/Closed - otwarty na rozszerzenia, zamknięty na modyfikacje
  • Liskov Substitution - podklasy mogą zastąpić nadklasy
  • Interface Segregation - wiele małych interfejsów
  • Dependency Inversion - zależności od abstrakcji

2. Nazewnictwo

  • Entity - Product.php (reprezentuje obiekt domenowy)
  • Repository - ProductRepository.php (dostęp do danych)
  • Service - ProductService.php (logika biznesowa)
  • Controller - ProductController.php (obsługa requestów)

3. Type Hinting

// ✅ DOBRE
public function getQuantity(int $id): ?int {
    return $this->db->get('pp_shop_products', 'quantity', ['id' => $id]);
}

// ❌ ZŁE
public function getQuantity($id) {
    return $this->db->get('pp_shop_products', 'quantity', ['id' => $id]);
}

Narzędzia pomocnicze

Autoloader (produkcja)

Autoloader w 9 entry pointach obsługuje dwie konwencje:

  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

composer require --dev phpstan/phpstan
vendor/bin/phpstan analyse autoload/Domain

Kolejność refaktoryzacji (priorytet)

  1. Cache
  2. Product (w trakcie)
    • getQuantity (ver. 0.238)
    • getPrice (ver. 0.239)
    • getName (ver. 0.239)
    • archive / unarchive (ver. 0.241)
    • is_product_on_promotion - NASTĘPNA 👉
    • getFromCache
    • getProductImg
  3. Banner (pełna migracja kontrolera, ver. 0.239)
  4. Settings (pełna migracja repo/kontrolera + cleanup legacy, ver. 0.250)
  5. Dictionaries (repo + kontroler + form/table, ver. 0.251)
  6. ProductArchive (migracja kontrolera + cleanup szablonów, ver. 0.252)
  7. Filemanager (migracja routingu + fix Invalid Key, ver. 0.252)
  8. Users (repo + kontroler + 2FA + legacy cleanup, ver. 0.253)
  9. Pages (repo + kontroler + drzewo stron + AJAX endpoints, ver. 0.262)
  10. Integrations (repo + kontroler + cleanup Sellasist/Baselinker, ver. 0.263)
  11. Order
  12. Category
  13. ShopAttribute
  • 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
    • BannerController - przerobiony na nowy system formularzy
    • Wspierane typy pól: text, number, email, password, date, datetime, switch, select, textarea, editor, image, file, hidden, lang_section
    • Obsługa zakładek (vertical) i sekcji językowych (horizontal)
    • Do zrobienia: Przerobić pozostałe kontrolery/formularze (Product, Category, Pages, itd.)

Rozpoczęto: 2025-02-05 Ostatnia aktualizacja: 2026-02-12

Form Edit System - Dokumentacja użycia

Architektura

┌─────────────────────────────────────────────────────────────┐
│                     Controller                              │
│  ┌─────────────────┐  ┌─────────────────┐                  │
│  │   edit()        │  │   save()        │                  │
│  │  - buduje VM    │  │  - walidacja    │                  │
│  │  - renderuje    │  │  - zapis        │                  │
│  └────────┬────────┘  └─────────────────┘                  │
└───────────┼─────────────────────────────────────────────────┘
            │
            ▼
┌─────────────────────────────────────────────────────────────┐
│              FormEditViewModel                              │
│  - title, formId, data, fields, tabs, actions               │
│  - validationErrors, persist, languages                     │
└───────────┬─────────────────────────────────────────────────┘
            │
            ▼
┌─────────────────────────────────────────────────────────────┐
│         components/form-edit.php (szablon)                  │
│  ┌─────────────────────────────────────────────────────┐   │
│  │  FormFieldRenderer - renderuje każde pole           │   │
│  │  ├─ input, select, textarea, switch                 │   │
│  │  ├─ date, datetime, editor, image                   │   │
│  │  └─ lang_section (zagnieżdżone pola)                │   │
│  └─────────────────────────────────────────────────────┘   │
└─────────────────────────────────────────────────────────────┘

Przykład użycia w kontrolerze

use admin\ViewModels\Forms\FormEditViewModel;
use admin\ViewModels\Forms\FormField;
use admin\ViewModels\Forms\FormTab;
use admin\ViewModels\Forms\FormAction;
use admin\Support\Forms\FormRequestHandler;

class BannerController
{
    public function edit(): string
    {
        $banner = $this->repository->find($id);
        $languages = \admin\factory\Languages::languages_list();

        $viewModel = new FormEditViewModel(
            formId: 'banner-edit',
            title: 'Edycja banera',
            data: $banner,
            tabs: [
                new FormTab('settings', 'Ustawienia', 'fa-wrench'),
                new FormTab('content', 'Zawartość', 'fa-file'),
            ],
            fields: [
                // Zakładka Ustawienia
                FormField::text('name', [
                    'label' => 'Nazwa',
                    'tab' => 'settings',
                    'required' => true,
                ]),
                FormField::switch('status', [
                    'label' => 'Aktywny',
                    'tab' => 'settings',
                ]),
                FormField::date('date_start', [
                    'label' => 'Data rozpoczęcia',
                    'tab' => 'settings',
                ]),

                // Sekcja językowa w zakładce Zawartość
                FormField::langSection('translations', 'content', [
                    FormField::image('src', ['label' => 'Obraz']),
                    FormField::text('url', ['label' => 'Url']),
                    FormField::editor('text', ['label' => 'Treść']),
                ]),
            ],
            actions: [
                FormAction::save('/admin/banners/save', '/admin/banners'),
                FormAction::cancel('/admin/banners'),
            ],
            languages: $languages,
            persist: true,
        );

        return \Tpl::view('components/form-edit', ['form' => $viewModel]);
    }

    public function save(): void
    {
        $formHandler = new FormRequestHandler();
        $viewModel = $this->buildFormViewModel(); // jak w edit()

        $result = $formHandler->handleSubmit($viewModel, $_POST);

        if (!$result['success']) {
            // Błędy walidacji - zapisane automatycznie do sesji
            echo json_encode(['success' => false, 'errors' => $result['errors']]);
            exit;
        }

        // Sukces - persist wyczyszczony automatycznie
        $this->repository->save($result['data']);
        echo json_encode(['success' => true]);
        exit;
    }
}

Dostępne typy pól

Typ Metoda Opcje
text FormField::text(name, ['label' => '...', 'required' => true]) placeholder, help
number FormField::number(name, [...]) -
email FormField::email(name, [...]) walidacja formatu
password FormField::password(name, [...]) -
date FormField::date(name, [...]) datetimepicker
datetime FormField::datetime(name, [...]) datetimepicker z czasem
switch FormField::switch(name, [...]) checked (bool)
select FormField::select(name, ['options' => [...]]) options: [key => label]
textarea FormField::textarea(name, ['rows' => 4]) rows
editor FormField::editor(name, ['toolbar' => 'MyTool']) CKEditor
image FormField::image(name, ['filemanager' => true]) filemanager URL
file FormField::file(name, [...]) filemanager
hidden FormField::hidden(name, value) -
lang_section FormField::langSection(name, 'tab', [fields]) pola per język

Walidacja

Walidacja jest automatyczna na podstawie właściwości pól:

  • required - pole wymagane
  • type = email - walidacja formatu e-mail
  • type = number - walidacja liczby
  • type = date - walidacja formatu YYYY-MM-DD

Dla sekcji językowych walidacja jest powtarzana dla każdego aktywnego języka.

Persist (zapamiętywanie danych)

Gdy persist = true:

  1. Przy błędzie walidacji dane są zapisywane w $_SESSION['form_persist'][$formId]
  2. Formularz automatycznie przywraca dane z sesji przy ponownym wyświetleniu
  3. Po udanym zapisie sesja jest czyszczona automatycznie przez FormRequestHandler

Przerabianie istniejących formularzy

  1. Kontroler - zamień view\Xxx::edit() na FormEditViewModel
  2. Repository - dostosuj save() do formatu z FormRequestHandler (lub dodaj wsparcie dla obu formatów)
  3. Szablon - usuń stary szablon lub zostaw jako fallback
  4. Testy - zaktualizuj testy jeśli zmienił się format danych

Aktualizacja 2026-02-12 - Users

Users (migracja kontrolera i repozytorium)

  • NOWE: Domain\User\UserRepository (delete, find, save, checkLogin, logon, details, sendTwofaCode, verifyTwofaCode)
  • NOWE: admin\Controllers\UsersController (view_list, user_edit, user_save, user_delete)
  • UPDATE: Router admin\Site - nowy kontroler DI dla modu<64>u Users
  • UPDATE: admin\factory\Users jako fasada delegujaca do repozytorium
  • UPDATE: admin/ajax/users.php - endpoint check_login oparty o UserRepository
  • Testy po zmianie: 95 tests, 204 assertions
  • UPDATE: UsersController: view_list + user_edit migrowane na nowy system list/form (table-list + form-edit)

Aktualizacja 2026-02-12 (finalizacja Users)

  • Users: pelna migracja na nowa architekture (Domain + DI Controller), bez fallbacku do legacy kontrolera/factory/view.
  • UsersController obsluguje: list/view_list, user_edit, user_save, user_delete, login_form, twofa.
  • Dodano walidacje warunkowa: twofa_email wymagany gdy twofa_enabled = 1.
  • Widoki users migrowane z grid/gridEdit na table-list i form-edit.

Aktualizacja 2026-02-12 - Languages

  • NOWE: Domain\\Languages\\LanguagesRepository (languages + translations CRUD/list)
  • NOWE: admin\\Controllers\\LanguagesController (DI)
  • UPDATE: admin\\Site - nowy kontroler DI dla modulu Languages
  • UPDATE: admin\\factory\\Languages jako fasada delegujaca do repozytorium
  • UPDATE: widoki languages/* migrowane na components/table-list i components/form-edit
  • CLEANUP: usunieto legacy admin\\controls\\Languages i admin\\view\\Languages
  • Testy po zmianie: 130 tests, 301 assertions

Aktualizacja 2026-02-12 (Languages final)

  • NOWE: Domain\\Languages\\LanguagesRepository (list/save/delete dla jezykow i tlumaczen)
  • NOWE: admin\\Controllers\\LanguagesController (DI) dla akcji view_list/list, language_*, translation_*
  • UPDATE: admin\\factory\\Languages jako fasada delegujaca do repozytorium
  • CLEANUP: usunieto legacy admin\\controls\\Languages oraz admin\\view\\Languages
  • UPDATE: poprawki globalne components/table-list dla krotkich kolumn/filtr<74>w

Aktualizacja 2026-02-12 (ver. 0.255)

  • UPDATE: SettingsController, BannerController, DictionariesController, ArticlesController pobieraja liste jezykow przez Domain/Languages/LanguagesRepository (DI) zamiast legacy admin/factory/Languages.
  • UPDATE: router DI (admin/Site) przekazuje LanguagesRepository do kontrolerow Articles, Banners, Settings, Dictionaries.
  • UPDATE: pozostale aktywne odwolania legacy (admin/controls, admin/factory/Shop*) zostaly przepiete na LanguagesRepository.
  • FIX: autoload/admin/factory/class.Languages.php poprawione na <?php (zgodnosc z short_open_tag=Off).
  • Testy po zmianie: 130 tests, 303 assertions.

Aktualizacja 2026-02-12 (ver. 0.256)

  • Layouts - ZMIGROWANE (2026-02-12) ??

    • NOWE: Domain\\Layouts\\LayoutsRepository (find, save, delete, listForAdmin, menusWithPages, categoriesTree)
    • NOWE: admin\\Controllers\\LayoutsController (DI)
    • UPDATE: lista /admin/layouts/view_list/ migrowana na components/table-list
    • UPDATE: widok layouts/layout-edit korzysta z danych dostarczonych przez repozytorium (bez wywolan legacy factory)
    • NOWE: partial admin/templates/layouts/subcategories-list.php
    • CLEANUP: usuniete autoload/admin/controls/class.Layouts.php i autoload/admin/view/class.Layouts.php
    • KOMPATYBILNOSC: autoload/admin/factory/class.Layouts.php deleguje do repozytorium
  • Languages

    • UPDATE: Domain\\Languages\\LanguagesRepository::defaultLanguageId() jako wspolna metoda do pobierania jezyka domyslnego
  • Articles

    • UPDATE: admin\\Controllers\\ArticlesController korzysta z Domain\\Layouts\\LayoutsRepository (DI) dla listy layoutow
  • Testy po zmianie: 141 tests, 336 assertions

Aktualizacja 2026-02-12 (ver. 0.257)

  • Newsletter - ZMIGROWANE (2026-02-12)

    • NOWE: Domain\\Newsletter\\NewsletterRepository (listy admin, szablony, ustawienia, kolejka wysylki)
    • NOWE: Domain\\Newsletter\\NewsletterPreviewRenderer (wspolny render podgladu)
    • NOWE: admin\\Controllers\\NewsletterController (DI)
    • UPDATE: routing DI (admin\\Site) rozszerzony o modul Newsletter
    • UPDATE: widoki /admin/newsletter/* migrowane na components/table-list i components/form-edit
    • UPDATE: admin\\factory\\Newsletter jako fasada do repozytorium
    • UPDATE: front\\factory\\Newsletter bez zaleznosci od admin\\view\\Newsletter
    • CLEANUP: usuniete autoload/admin/controls/class.Newsletter.php, autoload/admin/view/class.Newsletter.php
  • Testy po zmianie: 150 tests, 372 assertions

Aktualizacja 2026-02-12 (ver. 0.258)

  • Newsletter
    • UPDATE: tymczasowo wylaczono flow prepare/send/preview (wymaga przebudowy).
    • UPDATE: tymczasowo wylaczono modul Szablony uzytkownika.
    • UPDATE: aktywna obsluga tylko szablonow administracyjnych (is_admin = 1).
    • CLEANUP: usuniete nieuzywane widoki prepare.php, preview.php, email-templates-user.php.

Aktualizacja 2026-02-12 (ver. 0.259)

  • Scontainers - ZMIGROWANE (2026-02-12)
    • NOWE: Domain\Scontainers\ScontainersRepository (listForAdmin, find, save, delete, detailsForLanguage)
    • NOWE: admin\Controllers\ScontainersController (DI)
    • UPDATE: /admin/scontainers/view_list/ migrowane na components/table-list
    • UPDATE: /admin/scontainers/container_edit/ migrowane na components/form-edit
    • UPDATE: admin\factory\Scontainers jako fasada do repozytorium
    • UPDATE: front\factory\Scontainers korzysta z repozytorium domenowego
    • CLEANUP: usuniete autoload/admin/controls/class.Scontainers.php i autoload/admin/view/class.Scontainers.php
  • Testy po zmianie: 158 tests, 397 assertions

Aktualizacja 2026-02-12 (ver. 0.260)

  • ArticlesArchive - ZMIGROWANE (2026-02-12)
    • NOWE: admin\Controllers\ArticlesArchiveController (DI)
    • UPDATE: Domain\Article\ArticleRepository rozszerzone o listArchivedForAdmin(), restore(), deletePermanently()
    • UPDATE: /admin/articles_archive/view_list/ migrowane na components/table-list
    • UPDATE: routing DI (admin\Site) rozszerzony o modul ArticlesArchive + mapowanie article_restore -> restore
    • CLEANUP: usuniete autoload/admin/controls/class.ArticlesArchive.php, autoload/admin/factory/class.ArticlesArchive.php, autoload/admin/view/class.ArticlesArchive.php
  • Testy po zmianie: 165 tests, 424 assertions

Plan 2026-02-13 - Refaktoryzacja /admin/articles/

  • Przeniesc zaleznosci listy artykulow z admin\factory\Articles do Domain\Article\ArticleRepository (etykiety stron, operacje pomocnicze).
  • Dodac akcje routowane przez admin\Controllers\ArticlesController dla operacji AJAX (article_image_alt_change, article_file_name_change, article_image_delete, article_file_delete).
  • Przepiac widok admin/templates/articles/article-edit.php z /admin/ajax.php na endpointy /admin/articles/*.
  • Usunac legacy admin\view\Articles i zastapic rekurencje podstron przez Tpl::view('articles/subpages-list', ...).
  • Usunac admin/ajax/articles.php oraz odpiac include z admin/ajax.php.
  • Przeszukac projekt pod pozostale zaleznosci i uruchomic testy modulu Articles.

Aktualizacja 2026-02-13 (ver. 0.261)

  • Articles - dalsza refaktoryzacja /admin/articles/
    • UPDATE: Domain\Article\ArticleRepository rozszerzone o metody UI/admin: pagesSummaryForArticles(), updateImageAlt(), updateFileName(), markImageToDelete(), markFileToDelete().
    • UPDATE: admin\Controllers\ArticlesController obsluguje nowe akcje routingu: article_image_alt_change, article_file_name_change, article_image_delete, article_file_delete.
    • UPDATE: lista artykulow (list) nie korzysta juz z admin\factory\Articles::article_pages().
    • UPDATE: admin/templates/articles/article-edit.php przepiete z /admin/ajax.php?a=article_* na endpointy /admin/articles/article_*/.
    • UPDATE: rekurencja podstron w widoku oparta o Tpl::view('articles/subpages-list', ...) (bez admin\view\Articles).
    • CLEANUP: usuniete legacy pliki autoload/admin/view/class.Articles.php oraz admin/ajax/articles.php; admin/ajax.php nie includuje juz ajax/articles.php.
  • Testy po zmianie: 176 tests, 439 assertions.

Aktualizacja 2026-02-13 (ver. 0.261)

  • Articles (/admin/articles)
    • UPDATE: Domain\Article\ArticleRepository rozszerzone o saveFilesOrder() oraz zapis files_order przy save() (eliminuje koniecznosc drugiego zapisu po sortowaniu).
    • UPDATE: routing DI (admin\Site) rozszerzony o mapowanie files_order_save -> filesOrderSave.
    • UPDATE: admin\Controllers\ArticlesController - nowa akcja AJAX filesOrderSave.
    • UPDATE: widok admin/templates/articles/article-edit-custom-script.php - drag&drop dla listy zalacznikow + hidden input files_order.
    • UPDATE: potwierdzenia usuwania zdjec i zalacznikow przepiete na jquery-confirm ze stylem table-list-confirm-dialog (jak na liscie artykulow).
    • FIX: dolaczona biblioteka jquery-impromptu w widoku edycji artykulu dla kompatybilnosci.
  • Testy po zmianie: 178 tests, 443 assertions.

Plan 2026-02-13 - Refaktoryzacja /admin/pages/

  • Dodac Domain\Pages\PagesRepository (CRUD menu/stron, drzewo stron, sortowanie, SEO, operacje AJAX).
  • Dodac admin\Controllers\PagesController (DI) i przepiac routing /admin/pages/* na nowy kontroler.
  • Przebudowac widoki admin/templates/pages/* tak, aby nie korzystaly z admin\factory\Pages i admin\view\Pages.
  • Przepiac endpointy AJAX z /admin/ajax.php?a=* na /admin/pages/* (save_pages_order, save_articles_order, generate_seo_link, cookie_*).
  • Przeszukac i zaktualizowac zaleznosci w innych modulach (articles, layouts, helpery) powiazane z Pages.
  • Usunac legacy klasy/pliki Pages (autoload/admin/controls/class.Pages.php, autoload/admin/view/class.Pages.php, autoload/admin/factory/class.Pages.php, admin/ajax/pages.php) po odpieciu zaleznosci.
  • Dodac/uzupelnic testy (PagesRepository, PagesController) i uruchomic testy.

Aktualizacja 2026-02-13 - Pages (/admin/pages)

  • NOWE: Domain\Pages\PagesRepository (CRUD menu/stron, drzewo stron, porzadkowanie, SEO link, URL preview, cookies tree-state).
  • NOWE: admin\Controllers\PagesController (DI) dla akcji: view_list/list, browse_list, pages_url_browser, menu_*, page_*, save_*_order, generate_seo_link, cookie_*.
  • UPDATE: /admin/pages/* dziala bez legacy admin\controls\Pages i admin\view\Pages.
  • UPDATE: widoki admin/templates/pages/* przepiete na dane z kontrolera/repozytorium (bez admin\factory\Pages).
  • UPDATE: endpointy zalezne od Pages w innych modulach (articles, layouts, shop-category, shop-product) przepiete z admin/ajax.php?a=* na /admin/pages/*.
  • CLEANUP: usuniete autoload/admin/controls/class.Pages.php, autoload/admin/view/class.Pages.php, autoload/admin/factory/class.Pages.php, admin/ajax/pages.php; admin/ajax.php nie includuje juz ajax/pages.php.
  • Testy: OK (186 tests, 478 assertions).

Aktualizacja 2026-02-13 - Integrations (/admin/integrations)

  • NOWE: Domain\Integrations\IntegrationsRepository (settings Apilo/ShopPRO, OAuth, product linking, API fetch lists, product search/create, ShopPRO import).
  • NOWE: admin\Controllers\IntegrationsController (DI) dla akcji: apilo_settings, apilo_settings_save, apilo_authorization, get_platform_list, get_status_types_list, get_carrier_account_list, get_payment_types_list, apilo_create_product, apilo_product_search, apilo_product_select_save, apilo_product_select_delete, shoppro_settings, shoppro_settings_save, shoppro_product_import.
  • UPDATE: admin\factory\Integrations jako fasada delegujaca do Domain\Integrations\IntegrationsRepository (tylko Apilo + ShopPRO).
  • CLEANUP: usunieto integracje Sellasist i Baselinker z calego projektu:
    • Usuniete klasy: admin\controls\Integrations, admin\controls\Baselinker, admin\factory\Baselinker, front\factory\Shop, shop\ShopStatus
    • Usuniete szablony: integrations/sellasist-settings.php, integrations/baselinker-settings.php, admin/templates/baselinker/
    • Wyczyszczone referencje w: cron.php, cron/cron-xml.php, shop\Order, admin\controls\ShopStatuses, admin\controls\ShopTransport, admin\controls\ShopPaymentMethod, admin\controls\ShopProduct, admin\factory\ShopStatuses, admin\factory\ShopTransport, admin\factory\ShopProduct, front\factory\ShopStatuses, front\factory\ShopTransport, front\factory\ShopPaymentMethod, front\factory\ShopProduct, front\factory\ShopOrder, shop\Product, config.php
    • Wyczyszczone szablony: shop-statuses/*, shop-transport/*, shop-payment-method/*, shop-product/*, site/main-layout.php
  • Testy: OK (212 tests, 577 assertions).

Plan 2026-02-13 - Refaktoryzacja /admin/shop_promotion/ (HITL)

  • Etap 1 (analiza i kontrakt): potwierdzic docelowy kontrakt URL i kompatybilnosc wsteczna:
    • kontrakt docelowy: tylko /admin/shop_promotion/list/, /admin/shop_promotion/edit/, /admin/shop_promotion/save/, /admin/shop_promotion/delete/
    • brak kompatybilnosci ze starymi URL i aliasami akcji (view_list, promotion_delete)
  • Etap 2 (Domain): dodac Domain\Promotion\PromotionRepository:
    • listForAdmin(filters, sort, dir, page, perPage) z whitelist sortowania i bind params
    • find(int $id) + domyslne dane dla nowego formularza
    • save(array $data): ?int (insert/update, normalizacja switchy, JSON dla kategorii)
    • delete(int $id): bool
    • categoriesTree(?int $parentId): array (drzewo kategorii z tlumaczeniami, bez zaleznosci od admin\factory\ShopCategory)
  • Etap 3 (Admin Controller + routing DI): dodac admin\Controllers\ShopPromotionController i przepiac routing:
    • rejestracja factory w admin\Site::$newControllers pod modulem ShopPromotion
    • akcje: list, edit, save, delete
    • zachowac obsluge legacy payload (values JSON) oraz obsluge form-edit ($_POST)
  • Etap 4 (widoki): przepiac modul z grid/gridEdit na nowe komponenty:
    • nowy widok listy oparty o components/table-list (filtry: nazwa, aktywny)
    • nowy widok edycji oparty o components/form-edit (+ pola custom dla drzew kategorii)
    • nowe partiale dla drzewa kategorii w module shop-promotion (usuniecie zaleznosci od shop-product/subcategories-list)
    • nowy shop-promotion/promotion-edit-custom-script.php (warunkowe pola po condition_type, obsluga drzewa kategorii)
  • Etap 5 (zaleznosci i cleanup): przeszukac i odpiac legacy zaleznosci:
    • menu admin: link kanoniczny na /admin/shop_promotion/list/
    • usunac legacy pliki po pelnym przepieciu:
      • autoload/admin/controls/class.ShopPromotion.php
      • autoload/admin/factory/class.ShopPromotion.php
      • admin/templates/shop-promotion/view-list.php (grid)
      • admin/templates/shop-promotion/promotion-edit.php (gridEdit)
    • sprawdzic pozostale odwolania ShopPromotion i shop_promotion/view_list w calym repo
  • Etap 6 (testy): dodac/uzupelnic testy:
    • tests/Unit/Domain/Promotion/PromotionRepositoryTest.php
    • tests/Unit/admin/Controllers/ShopPromotionControllerTest.php
    • uruchomic minimum: nowe testy modulu + pelny composer test
  • Etap 7 (dokumentacja po wdrozeniu): zaktualizowac:
    • DATABASE_STRUCTURE.md (dodac pp_shop_promotion, jesli nadal brak)
    • PROJECT_STRUCTURE.md
    • REFACTORING_PLAN.md (sekcja "Aktualizacja ...")
    • TESTING.md (nowy wynik suite)

Aktualizacja 2026-02-13 (ver. 0.264)

  • ShopPromotion - migracja /admin/shop_promotion na Domain + DI + nowe widoki
    • NOWE: Domain\Promotion\PromotionRepository (listForAdmin, find, save, delete, categoriesTree, invalidacja cache aktywnych promocji)
    • NOWE: admin\Controllers\ShopPromotionController (DI) z akcjami list, edit, save, delete
    • UPDATE: routing DI (admin\Site) rozszerzony o modul ShopPromotion
    • UPDATE: modul /admin/shop_promotion/* dziala na components/table-list i components/form-edit
    • NOWE: widoki/partiale shop-promotion/promotions-list, shop-promotion/promotion-edit, shop-promotion/promotion-categories-selector, shop-promotion/promotion-categories-tree, shop-promotion/promotion-edit-custom-script
    • CLEANUP: usuniete legacy autoload/admin/controls/class.ShopPromotion.php, autoload/admin/factory/class.ShopPromotion.php, admin/templates/shop-promotion/view-list.php
    • UPDATE: menu admin przepiete na kanoniczny URL /admin/shop_promotion/list/
  • Testy po zmianie: OK (222 tests, 609 assertions).

Aktualizacja 2026-02-13 (ver. 0.265)

  • ShopPromotion - stabilizacja po migracji
    • UPDATE: dodane date_from w Domain\Promotion\PromotionRepository (save/find/list/sort)
    • UPDATE: admin\Controllers\ShopPromotionController rozszerzony o pole Data od na formularzu i kolumne Data od na liscie
    • UPDATE: shop\Promotion::get_active_promotions() filtruje aktywnosc po date_from i date_to
    • FIX: zapis edycji promocji nie tworzy nowego rekordu (hidden id + fallback id z URL)
    • TEST: rozszerzono PromotionRepositoryTest o asercje date_from
  • Testy po zmianie: OK (222 tests, 614 assertions).

Plan 2026-02-13 - Refaktoryzacja /admin/shop_coupon/ (HITL)

  • Etap 1 (analiza i kontrakt URL/routingu):
    • potwierdzic docelowy kontrakt URL: /admin/shop_coupon/list/, /admin/shop_coupon/edit/, /admin/shop_coupon/save/, /admin/shop_coupon/delete/
    • decyzja: utrzymujemy aliasy legacy (view_list, coupon_edit, coupon_save, coupon_delete) w nowym kontrolerze jako kompatybilnosc wsteczna, przy jednoczesnym przejsciu menu i nowych widokow na URL kanoniczne
    • sprawdzic mapowanie modulu ShopCoupon w admin\Site (DI factory + fallback)
  • Etap 2 (Domain):
    • dodac Domain\Coupon\CouponRepository:
      • listForAdmin(filters, sort, dir, page, perPage) (whitelist sortowania + paginacja)
      • find(int $id) (domyslne dane dla nowego formularza)
      • save(array $data): ?int (insert/update, normalizacja switchy, JSON dla categories)
      • delete(int $id): bool
      • categoriesTree(?int $parentId): array (drzewo kategorii bez zaleznosci od admin\factory\ShopCategory)
  • Etap 3 (Admin Controller + routing DI):
    • dodac admin\Controllers\ShopCouponController z akcjami list, edit, save, delete
    • przepiac routing DI w admin\Site::$newControllers dla modulu ShopCoupon
    • zachowac obsluge legacy payload values JSON i nowego payload $_POST z components/form-edit
  • Etap 4 (widoki):
    • przepiac liste z grid na components/table-list (filtry: nazwa, aktywny, uzyty, wyslany)
    • przepiac edycje z gridEdit na components/form-edit
    • dodac partiale drzewa kategorii w module shop-coupon (usuniecie zaleznosci od shop-product/subcategories-list)
    • dodac shop-coupon/coupon-edit-custom-script.php (obsluga drzewa kategorii i zachowania formularza)
  • Etap 5 (cleanup i zaleznosci):
    • usunac legacy po pelnym przepieciu:
      • autoload/admin/controls/class.ShopCoupon.php
      • autoload/admin/factory/class.ShopCoupon.php
      • admin/templates/shop-coupon/view-list.php (wersja grid)
      • admin/templates/shop-coupon/coupon-edit.php (wersja gridEdit)
    • przepiac menu admin na kanoniczny URL /admin/shop_coupon/list/
    • przeszukac repo i usunac pozostale odwolania do shop_coupon/view_list i legacy klas admin\controls\ShopCoupon, admin\factory\ShopCoupon
  • Etap 6 (testy):
    • dodac tests/Unit/Domain/Coupon/CouponRepositoryTest.php
    • dodac tests/Unit/admin/Controllers/ShopCouponControllerTest.php
    • uruchomic testy modulu + pelny composer test
  • Etap 7 (dokumentacja i release note):
    • zaktualizowac DATABASE_STRUCTURE.md (dodac pp_shop_coupon)
    • zaktualizowac PROJECT_STRUCTURE.md
    • zaktualizowac REFACTORING_PLAN.md (sekcja "Aktualizacja ...")
    • zaktualizowac TESTING.md (nowy wynik suite + nowe testy)
    • dopisac wpis w updates/changelog.php

Tryb HITL dla realizacji

  • Po kazdym etapie (1-7) zatrzymanie i krotkie podsumowanie diffu do akceptacji przed kolejnym krokiem.

Postep 2026-02-13 (ShopCoupon)

  • Etap 2 zakonczony:
    • NOWE: autoload/Domain/Coupon/CouponRepository.php
    • Zakres: listForAdmin, find, save, delete, categoriesTree
    • Walidacja: php -l OK
  • Etap 3 zakonczony:
    • NOWE: autoload/admin/Controllers/ShopCouponController.php
    • UPDATE: autoload/admin/class.Site.php - rejestracja DI factory dla modulu ShopCoupon
    • Kompatybilnosc: dodane aliasy akcji view_list, coupon_edit, coupon_save, coupon_delete
    • Walidacja: php -l OK
  • Etap 4 zakonczony:
    • NOWE widoki: admin/templates/shop-coupon/coupons-list.php, admin/templates/shop-coupon/coupon-edit-new.php
    • NOWE partiale: admin/templates/shop-coupon/coupon-categories-selector.php, admin/templates/shop-coupon/coupon-categories-tree.php
    • NOWY skrypt: admin/templates/shop-coupon/coupon-edit-custom-script.php
    • UPDATE: ShopCouponController::edit() buduje FormEditViewModel (zakladki ustawienia/kategorie)
    • Walidacja: php -l OK
  • Etap 5 zakonczony:
    • CLEANUP: usuniete pliki legacy:
      • autoload/admin/controls/class.ShopCoupon.php
      • autoload/admin/factory/class.ShopCoupon.php
      • admin/templates/shop-coupon/view-list.php
      • admin/templates/shop-coupon/coupon-edit.php
    • UPDATE: menu admin (admin/templates/site/main-layout.php) wskazuje kanoniczny URL /admin/shop_coupon/list/
    • WERYFIKACJA: brak odwolan do shop_coupon/view_list, admin\controls\ShopCoupon, admin\factory\ShopCoupon w kodzie
  • Etap 6 zakonczony:
    • NOWE testy:
      • tests/Unit/Domain/Coupon/CouponRepositoryTest.php (8 testow)
      • tests/Unit/admin/Controllers/ShopCouponControllerTest.php (5 testow)
    • Test modulu: OK (8 tests, 49 assertions)
    • Pelny suite: OK (235 tests, 682 assertions)
  • Etap 7 zakonczony:
    • UPDATE: dokumentacja techniczna zaktualizowana (DATABASE_STRUCTURE.md, PROJECT_STRUCTURE.md, TESTING.md)
    • UPDATE: dopisany release note w updates/changelog.php (ver. 0.266)

Aktualizacja 2026-02-13 (ver. 0.266)

  • ShopCoupon - migracja /admin/shop_coupon na Domain + DI + nowe widoki
    • NOWE: Domain\Coupon\CouponRepository (listForAdmin, find, save, delete, categoriesTree)
    • NOWE: admin\Controllers\ShopCouponController (DI) z akcjami list, edit, save, delete
    • UPDATE: kompatybilnosc aliasow legacy (view_list, coupon_edit, coupon_save, coupon_delete) obslugiwana przez nowy kontroler
    • UPDATE: modul /admin/shop_coupon/* dziala na components/table-list i components/form-edit
    • NOWE: widoki/partiale shop-coupon/coupons-list, shop-coupon/coupon-edit-new, shop-coupon/coupon-categories-selector, shop-coupon/coupon-categories-tree, shop-coupon/coupon-edit-custom-script
    • CLEANUP: usuniete legacy autoload/admin/controls/class.ShopCoupon.php, autoload/admin/factory/class.ShopCoupon.php, admin/templates/shop-coupon/view-list.php, admin/templates/shop-coupon/coupon-edit.php
    • UPDATE: menu admin przepiete na kanoniczny URL /admin/shop_coupon/list/
    • FIX: po akceptacji HITL ujednolicone UI drzewek i checkboxow miedzy kuponami i layoutami (spojne strzalki, brak nieestetycznego focusu, iCheck dla checkboxow)
  • Testy po zmianie: OK (235 tests, 682 assertions).