---
phase: 06-admin-base
plan: 02
status: complete
completed: 2026-04-30
---
# SUMMARY: Plan 06-02 — Support layer
## Co zrobiono
Domknięto Phase 6 (Admin Base Infrastructure) przez dodanie 3 klas warstwy Support: `TableListRequestFactory` (parser list z `$_GET`), `FormRequestHandler` (POST handler z CSRF + walidacja + persist), `FormFieldRenderer` (renderer HTML pól formularza). Wszystkie klasy ładują się przez PSR-4, smoke test runtime potwierdza poprawne działanie factory + autoload wszystkich klas + zero regresji w Domain/Shared/Phase 06-01.
## Pliki utworzone (3)
| Plik | Linii | Namespace |
|------|-------|-----------|
| `autoload/admin/Support/TableListRequestFactory.php` | 99 | `Admin\Support` |
| `autoload/admin/Support/Forms/FormRequestHandler.php` | 159 | `Admin\Support\Forms` |
| `autoload/admin/Support/Forms/FormFieldRenderer.php` | 494 | `Admin\Support\Forms` |
**Total**: 752 linii kodu PHP 7.4-kompatybilnego.
## Pliki zmodyfikowane (1)
- `vendor/composer/autoload_*` — regenerowane przez `composer dump-autoload`
(composer.json bez zmian — Phase 06-01 już ustawiło `php >=7.4` i poprawne PSR-4 paths.)
## Smoke test (literalny output)
```
=== A) AUTOLOAD ===
Admin\Support\TableListRequestFactory: OK
Admin\Support\Forms\FormRequestHandler: OK
Admin\Support\Forms\FormFieldRenderer: OK
=== B) FACTORY ===
page=2 perPage=25 sort=name dir=ASC
filters_status=1
OK_FACTORY
=== C) HANDLER ===
Admin\Support\Forms\FormRequestHandler
isFormSubmit returns: false
OK_HANDLER
=== D) RENDERER ===
(z cwd=admin/) len=2148, has_input=YES
OK_RENDERER
=== E) ZERO REGRESSION ===
Domain\Articles\ArticlesRepository: OK
Shared\Helpers\Helpers: OK
Admin\ViewModels\Forms\FormField: OK
Admin\Validation\FormValidator: OK
```
`php -l` na wszystkich 3 plikach: 3× "No syntax errors detected".
## Acceptance Criteria — status
| AC | Description | Status | Notes |
|----|-------------|--------|-------|
| AC-1 | Wszystkie 3 klasy ładują się przez PSR-4 | PASS | 3× class_exists() = true |
| AC-2 | TableListRequestFactory parsuje request | PASS | page=2, perPage=25, sort=name, dir=ASC, filters_status=1 |
| AC-3 | Poprawne `use` Admin\... do 06-01 | PASS | `grep "^use admin\\"` → 0 matches |
| AC-4 | Smoke test integracyjny (renderer + handler + Form VMs) | PARTIAL | Klasy ładują się, renderField() zwraca HTML 2148 znaków bez fatal error. Konkretne atrybuty `name="email"` w outpucie zależą od `admin/templates/html/input.php` (Phase 7 integration) |
| AC-5 | Zero regresji | PASS | Domain, Shared, Admin\ViewModels, Admin\Validation działają |
## Deviation 1: AC-4 częściowo — renderer markup zależy od templates
**Plan zakładał:** smoke test sprawdzi konkretny HTML `` z `name="email"` w outpucie `FormFieldRenderer::renderField()`.
**Rzeczywistość:** `FormFieldRenderer` deleguje do `Shared\Html\Html::input()`, który używa `Shared\Tpl\Tpl` z relative path `templates/html/input.php`. To templace istnieje TYLKO w `admin/templates/html/input.php` — nie w root `templates/`.
**Konsekwencje:**
- Kiedy cwd=root (CLI test): `Tpl` nie znajduje template → zwraca alert div (105 znaków)
- Kiedy cwd=admin/: template się znajduje → renderer produkuje 2148 znaków HTML z ``, ale generic markup (template nie jest jeszcze dostosowany do FormField → szablon ignoruje niektóre params)
**Decyzja:** AC-4 zaliczone jako PARTIAL — kluczowy fakt że *renderer się ładuje, instantiate, i wywołuje renderField bez fatal error* jest spełniony. Pełna walidacja markup HTML zostanie wykonana w Phase 7 (Articles), gdy:
1. Templates `admin/templates/html/*.php` zostaną zaktualizowane do nowego API
2. Phase 7 controller będzie pierwszym faktycznym konsumentem `FormFieldRenderer`
## Deviation 2: Drobna ostrzeżenie REQUEST_METHOD w CLI
`FormRequestHandler::isFormSubmit()` referuje `$_SERVER['REQUEST_METHOD']` które nie jest ustawione w `php -r` CLI mode. PHP zgłasza warning "Undefined array key" ale metoda zwraca `false` (poprawnie). To nie problem produkcyjny — w admin runtime `$_SERVER['REQUEST_METHOD']` zawsze jest ustawione. Zostawiamy 1:1 z shopPRO.
## Boundaries — przestrzegane
- ✓ Brak zmian w `autoload/admin/controls/`, `factory/`, `view/` (legacy)
- ✓ Brak zmian w 06-01 plikach (`autoload/admin/ViewModels/`, `autoload/admin/Validation/`)
- ✓ Brak zmian w `autoload/Domain/`, `autoload/Shared/`
- ✓ `autoload/autoloader.php` nieruszony
- ✓ `composer.json` nieruszony (06-01 już to ustawiło)
- ✓ `composer.lock` nieruszony
- ✓ `git diff --stat autoload/admin/controls autoload/admin/factory autoload/admin/view` → 0 zmian
## Deferred issues / observations
1. **Templates dostosowanie do FormField VM** — `admin/templates/html/input.php`, `select.php`, `textarea.php` itp. były pisane dla starego API `Shared\Html\Html::input(['label'=>X, 'name'=>Y])`. Renderer 06-02 woła te samo API, ale FormField niesie więcej info (np. error state, lang section ID). Phase 7 przy migracji pierwszego kontrolera (Articles) trzeba sprawdzić czy template renderuje wszystkie params; jeśli nie — zaktualizować templates. (Nie ujmuje to z 06-02 — renderer i template są zgodne API, brakuje tylko niektórych nowych features.)
2. **FormFieldRenderer.php 494 L — refaktor potencjał** — 17 metod `renderText`, `renderEmail`, `renderDate`, `renderImage` itp. w jednej klasie. Większość różni się tylko `'type' => 'X'`. Można uprościć przez table-driven dispatch. Zachowane 1:1 z shopPRO bo wzorzec jest stabilny i działa.
3. **`generateFilemanagerUrl()` hardcoded path** — `/libraries/filemanager-9.14.2/dialog.php` jest zaszyte. cmsPRO może mieć inną wersję filemanagera. Phase 7 walidacja: czy ten path istnieje w cmsPRO? Jeśli inny — zaktualizować jako Phase 7 fix.
4. **Brak BaseController** — decyzja udokumentowana. Phase 7+ kontrolery będą POJOs. Jeśli okaże się że istnieje powtarzalny kod między kontrolerami, można dodać BaseController w Phase 7+ jako odzysk.
## Phase 6 — STATUS: COMPLETE
Phase 6 (Admin Base Infrastructure) zamknięta po 2 planach. Pełny fundament dla Phase 7-13 gotowy:
**Available namespaces:**
- `Admin\ViewModels\Forms\` — FormEditViewModel, FormField, FormFieldType, FormTab, FormAction
- `Admin\Validation\` — FormValidator
- `Admin\Support\` — TableListRequestFactory
- `Admin\Support\Forms\` — FormRequestHandler, FormFieldRenderer
**Pattern dla Phase 7+ kontrolerów:**
```php
namespace Admin\Articles;
use Domain\Articles\ArticlesRepository;
use Admin\Support\TableListRequestFactory;
use Admin\Support\Forms\FormRequestHandler;
use Admin\Support\Forms\FormFieldRenderer;
use Admin\ViewModels\Forms\FormEditViewModel;
class ArticlesController
{
private ArticlesRepository $repo;
private FormRequestHandler $formHandler;
public function __construct(ArticlesRepository $repo)
{
$this->repo = $repo;
$this->formHandler = new FormRequestHandler();
}
public function listAction(): array
{
$listRequest = TableListRequestFactory::fromRequest($filterDefs, $sortable, 'date_add');
return $this->repo->listForAdmin($listRequest['filters'], ...);
}
}
```
## Next Phase Readiness
**Ready:**
- Cały fundament Admin\ namespace działa via PSR-4
- Phase 7 (Articles + ArticlesArchive) może zacząć migrować legacy controls/class.Articles.php na nowy POJO controller w Admin\Articles\
**Concerns:**
- `admin/templates/html/*.php` mogą wymagać dostosowania (ale nie blokują — Phase 7 to wykryje)
**Blockers:**
- None