Files
shopPRO/REFACTORING_PLAN.md

31 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)

📋 Do zrobienia

  • Order
  • Category
  • ShopAttribute
  • ShopProduct (factory)
  • Pages (browse_list i widoki drzewiaste nadal w legacy admin\controls / admin\view)

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
│   └── admin/
│       └── Controllers/
│           ├── ArticlesControllerTest.php
│           ├── DictionariesControllerTest.php
│           ├── ProductArchiveControllerTest.php
│           ├── SettingsControllerTest.php
│           └── UsersControllerTest.php
└── Integration/

Łącznie: 119 testów, 256 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. Order
  10. Category
  11. ShopAttribute
  12. Pages (browse_list i powiązane widoki nadal legacy)
  • 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