Phase 6 zamknięta po 2 planach. Pełny fundament dla Phase 7-13 (migracja 17 admin controllers do Admin\ namespace). 06-01 (Forms infrastructure): - Admin\ViewModels\Forms\* — 5 ViewModeli (687 L) - Admin\Validation\FormValidator (196 L) - composer.json: php >=7.4, PSR-4 paths cross-platform safe (Admin\ → autoload/admin/, Frontend\ → autoload/front/) 06-02 (Support layer): - Admin\Support\TableListRequestFactory (99 L) — parser list z $_GET - Admin\Support\Forms\FormRequestHandler (159 L) — POST + CSRF + walidacja + persist - Admin\Support\Forms\FormFieldRenderer (494 L) — renderer HTML pól Decyzje: - Brak BaseController — Phase 7+ kontrolery jako POJOs z DI (jak shopPRO) - PSR-4 filename fix: TableListRequestFactory.php (bez shopPRO 'class.' prefix) - PascalCase namespace (Admin\Support) na lowercase folder admin/ ze względu na Windows fs case-insensitivity vs legacy admin/controls/ Pliki: 8 nowych klas, 1635 L kodu PHP 7.4-kompatybilnego, zero regresji. Smoke test: walidacja e-maila zwraca PL komunikat, factory parsuje ?page=&per_page=&sort=&filter=, Domain/Shared nadal ładują się. PHPUnit: 37/37 OK. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
13 KiB
phase, plan, type, wave, depends_on, files_modified, autonomous, delegation
| phase | plan | type | wave | depends_on | files_modified | autonomous | delegation | |||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 06-admin-base | 01 | execute | 1 |
|
true | off |
Purpose
ROADMAP Phase 6 (Admin: Base Infrastructure) wymaga bazowych klas Admin\ — Form Edit System jest pierwszym filarem (kontrolery z Phase 7-13 będą zwracać FormEditViewModel zamiast budować HTML inline). PROJECT.md deklarował to ukończone, ale audyt wykazał brak — Phase 6/Plan 01 to nadrabia, kopiując stabilny wzorzec z shopPRO.
Output
autoload/Admin/ViewModels/Forms/— 5 plików (FormEditViewModel, FormField, FormFieldType, FormTab, FormAction)autoload/Admin/Validation/FormValidator.phpcomposer.jsonz"php": ">=7.4".paul/phases/06-admin-base/06-01-SUMMARY.md
Project Context
@.paul/PROJECT.md @.paul/ROADMAP.md @.paul/STATE.md @.paul/codebase/architecture.md
Reference Source (shopPRO — wzorzec do skopiowania)
@C:\visual studio code\projekty\shopPRO\autoload\Admin\ViewModels\Forms\FormEditViewModel.php @C:\visual studio code\projekty\shopPRO\autoload\Admin\ViewModels\Forms\FormField.php @C:\visual studio code\projekty\shopPRO\autoload\Admin\ViewModels\Forms\FormFieldType.php @C:\visual studio code\projekty\shopPRO\autoload\Admin\ViewModels\Forms\FormTab.php @C:\visual studio code\projekty\shopPRO\autoload\Admin\ViewModels\Forms\FormAction.php @C:\visual studio code\projekty\shopPRO\autoload\Admin\Validation\FormValidator.php
cmsPRO target paths
autoload/Admin/ViewModels/Forms/autoload/Admin/Validation/
Composer
@composer.json
<acceptance_criteria>
AC-1: Form ViewModels load via PSR-4
Given composer.json mapuje "Admin\\" → "autoload/Admin/"
When wykonam `composer dump-autoload && php -r "var_dump(class_exists('Admin\\ViewModels\\Forms\\FormEditViewModel'));"`
Then otrzymam `bool(true)` dla wszystkich 5 klas (FormEditViewModel, FormField, FormFieldType, FormTab, FormAction)
AC-2: FormValidator namespace and dependency
Given FormValidator zawiera `use Admin\ViewModels\Forms\FormField; use Admin\ViewModels\Forms\FormFieldType;`
When `php -r "var_dump(class_exists('Admin\\Validation\\FormValidator'));"`
Then otrzymam `bool(true)` i nie wystąpi fatal error o brakujących klasach
AC-3: Smoke test — utworzenie i walidacja formularza
Given załadowane klasy z AC-1 i AC-2
When utworzę `FormField('email', FormFieldType::EMAIL, 'E-mail', '', 'main', true)` + uruchomię `FormValidator::validate(['email' => 'not-an-email'], [$field])`
Then otrzymam tablicę `['email' => '...musi być poprawnym adresem e-mail.']` (lub równoważny komunikat) — walidacja działa
AC-4: PHP version constraint i konwencja PascalCase
Given composer.json
When odczytam pole `require.php`
Then jest równe ">=7.4"
And wszystkie nowe pliki mają `namespace Admin\ViewModels\Forms;` lub `namespace Admin\Validation;` (PascalCase pierwszy segment, w przeciwieństwie do shopPRO `admin\`)
AC-5: Zero regresji na istniejącym kodzie
Given commit przed planem
When wykonam `php -l` na każdym zmodyfikowanym pliku oraz `php -r "require 'autoload/autoloader.php';"` (lub equivalent inicjalizacji projektu)
Then żadnych błędów składni i żadnych warning/notice o redefinicji klas; istniejące Domain repos (np. `Domain\Articles\ArticlesRepository`) nadal się ładują
</acceptance_criteria>
Task 1: Skopiuj 5 Form ViewModeli z shopPRO do Admin\ViewModels\Forms\ z PascalCase namespace autoload/Admin/ViewModels/Forms/FormEditViewModel.php, autoload/Admin/ViewModels/Forms/FormField.php, autoload/Admin/ViewModels/Forms/FormFieldType.php, autoload/Admin/ViewModels/Forms/FormTab.php, autoload/Admin/ViewModels/Forms/FormAction.php Utwórz katalog `autoload/Admin/ViewModels/Forms/` (PascalCase — jeśli system plików ma kolizję z istniejącym `autoload/admin/`, NIE łącz ich; `Admin/` to nowy namespace PSR-4, `admin/` to legacy lowercase i pozostaje nietknięty).Skopiuj 5 plików ze shopPRO 1:1 z TYLKO tymi modyfikacjami:
1. **Zmień `namespace admin\ViewModels\Forms;` → `namespace Admin\ViewModels\Forms;`** (każdy plik, pierwsza linia po `<?php`)
2. Wewnętrzne `use` (jeśli są) — zaktualizuj wszelkie odwołania `admin\ViewModels\Forms\X` → `Admin\ViewModels\Forms\X`
3. **NIE zmieniaj** sygnatur, typed properties, JSDoców, defaultów, statycznych helperów (np. `FormAction::save()`)
Pliki do skopiowania (źródło → cel):
- `C:\visual studio code\projekty\shopPRO\autoload\Admin\ViewModels\Forms\FormEditViewModel.php` → `autoload/Admin/ViewModels/Forms/FormEditViewModel.php`
- `...\FormField.php` → `autoload/Admin/ViewModels/Forms/FormField.php`
- `...\FormFieldType.php` → `autoload/Admin/ViewModels/Forms/FormFieldType.php`
- `...\FormTab.php` → `autoload/Admin/ViewModels/Forms/FormTab.php`
- `...\FormAction.php` → `autoload/Admin/ViewModels/Forms/FormAction.php`
Avoid:
- Wymienianie `public string $name;` na `string $name` (PHP 7.4 wspiera typed properties, jest OK)
- Dodawanie nowych funkcji „przy okazji"
- Mieszania case'a w nazwach katalogów (musi być dokładnie `Admin/ViewModels/Forms/`)
`php -l autoload/Admin/ViewModels/Forms/FormEditViewModel.php` (i pozostałe 4) → "No syntax errors detected"
`grep -c "^namespace Admin\\\\ViewModels\\\\Forms;" autoload/Admin/ViewModels/Forms/*.php` → 5
`grep -c "^namespace admin\\\\" autoload/Admin/ViewModels/Forms/*.php` → 0
AC-1 częściowo (klasy istnieją), AC-4 częściowo (PascalCase namespace).
Task 2: Skopiuj FormValidator do Admin\Validation\ z PascalCase namespace i poprawnymi `use`
autoload/Admin/Validation/FormValidator.php
Utwórz katalog `autoload/Admin/Validation/` i skopiuj `FormValidator.php` ze shopPRO z modyfikacjami:
1. `namespace admin\Validation;` → `namespace Admin\Validation;`
2. `use admin\ViewModels\Forms\FormField;` → `use Admin\ViewModels\Forms\FormField;`
3. `use admin\ViewModels\Forms\FormFieldType;` → `use Admin\ViewModels\Forms\FormFieldType;`
4. Cała reszta (logika walidacji, metody prywatne `validateField`, `validateLangSection`, `isEmpty`) bez zmian.
Avoid:
- Refaktoryzacji walidatora przy okazji (nawet jeśli widzisz coś do poprawy — zapisz w SUMMARY jako deferred issue)
- Zmiany komunikatów błędów (są używane w UI 1:1)
`php -l autoload/Admin/Validation/FormValidator.php` → "No syntax errors detected"
`grep -E "^namespace |^use " autoload/Admin/Validation/FormValidator.php` zwraca:
`namespace Admin\Validation;`
`use Admin\ViewModels\Forms\FormField;`
`use Admin\ViewModels\Forms\FormFieldType;`
AC-2 satisfied: FormValidator ładuje się i zna FormField/FormFieldType.
Task 3: Dodaj `php: >=7.4` do composer.json i zregeneruj autoloader
composer.json
W `composer.json` dodaj sekcję `require` z `"php": ">=7.4"` PRZED `require-dev`. Jeśli sekcja `require` już istnieje — dopisz tylko klucz `php`. Zachowaj istniejące mapowania PSR-4 (`Domain\\`, `Shared\\`, `Admin\\`, `Frontend\\`).
Po edycji uruchom `composer dump-autoload` (lub `php composer.phar dump-autoload` jeśli composer nie jest globalny).
Avoid:
- Aktualizacji composer.lock przez `composer update`
- Dodawania nowych dependencies
- Usuwania `Frontend\\` mapowania (nieużywane teraz, ale zostaje dla Phase 14+)
`php -r "echo json_decode(file_get_contents('composer.json'), true)['require']['php'] ?? 'MISSING';"` → ">=7.4"
`php -r "require 'vendor/autoload.php'; var_dump(class_exists('Admin\\\\ViewModels\\\\Forms\\\\FormEditViewModel'));"` → `bool(true)`
`php -r "require 'vendor/autoload.php'; var_dump(class_exists('Admin\\\\Validation\\\\FormValidator'));"` → `bool(true)`
AC-1 satisfied (autoload działa dla wszystkich 6 klas), AC-4 satisfied (php>=7.4).
Task 4: Smoke test — runtime sanity check formularza
(brak modyfikacji — tylko weryfikacja runtime)
Uruchom inline PHP smoke check:
```
php -r "require 'vendor/autoload.php';
use Admin\ViewModels\Forms\FormField;
use Admin\ViewModels\Forms\FormFieldType;
use Admin\Validation\FormValidator;
$field = new FormField('email', FormFieldType::EMAIL, 'E-mail', '', 'main', true);
$v = new FormValidator();
\$errors = \$v->validate(['email' => 'not-an-email'], [\$field]);
echo isset(\$errors['email']) ? 'OK: '.\$errors['email'] : 'FAIL';"
```
(Składnię cudzysłowów dostosuj do shell — bash vs cmd. Cel: dostać linię zaczynającą się od `OK:` z polskim komunikatem walidacji.)
Następnie sprawdź lint na wszystkich nowych plikach:
`for f in autoload/Admin/ViewModels/Forms/*.php autoload/Admin/Validation/*.php; do php -l "$f"; done`
Avoid:
- Tworzenia trwałego pliku testowego — to jednorazowy smoke check, wynik wkleimy do SUMMARY
- Modyfikacji jakichkolwiek plików legacy (admin/, autoload/admin/) — Phase 6 ich nie dotyczy
Output zawiera "OK:" + komunikat o niepoprawnym e-mailu
`php -l` na wszystkich 6 plikach → 6× "No syntax errors detected"
`git status` pokazuje TYLKO: 5 nowych plików w `autoload/Admin/ViewModels/Forms/`, 1 nowy plik w `autoload/Admin/Validation/`, zmodyfikowany `composer.json`, regenerowany `vendor/composer/autoload_*` (jeśli vendor/ jest tracked)
AC-3 satisfied (walidacja działa runtime), AC-5 satisfied (zero regresji — tylko nowe pliki + composer.json).
DO NOT CHANGE
autoload/admin/(legacy, lowercase) — zostaje nietknięte do Phase 19autoload/Domain/**— Phase 5 closed, repozytoria stabilneautoload/Shared/**— Phase 2 closedautoload/autoloader.php— Phase 1 (hybrid loader działa); composer dump zaktualizuje vendor/, autoloader.php nie wymaga edycjicomposer.lock— nie aktualizuj (composer updatezakazany w tym planie)- shopPRO source files — read-only reference
SCOPE LIMITS
- TableListRequestFactory → Plan 06-02 (NIE w tym planie)
- BaseController → Plan 06-02
- Admin\App.php (logowanie, special_actions, routing) → Phase 12 (Users + 2FA)
- Refaktoring/poprawki w skopiowanych klasach — zero zmian merytorycznych, tylko namespace
- Migracja istniejących admin\controls* na nowe Form VMs → Phase 7+ (per moduł)
- Tworzenie templates/partials renderujących
FormEditViewModel→ poza zakresem Phase 6 - PHPUnit testy dla FormValidator → Phase 18
<success_criteria>
- 5 Form ViewModeli + FormValidator dostępne pod namespace
Admin\ViewModels\Forms\iAdmin\Validation\ - composer.json deklaruje
php: >=7.4 - Smoke test walidacji e-maila zwraca komunikat błędu po polsku
- Zero zmian w legacy
autoload/admin/,Domain/,Shared/ - Plan gotowy do unify → następnie Plan 06-02 </success_criteria>