--- phase: 06-admin-base plan: 01 type: execute wave: 1 depends_on: [] files_modified: - 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 - autoload/Admin/Validation/FormValidator.php - composer.json autonomous: true delegation: off --- ## Goal Założyć fundament `Admin\` namespace przez przeniesienie warstwy formularzy z shopPRO: 5 ViewModeli (FormEditViewModel, FormField, FormFieldType, FormTab, FormAction) w `Admin\ViewModels\Forms\` oraz `FormValidator` w `Admin\Validation\`. Plan kończy się działającym, autoloadowanym systemem definicji + walidacji formularzy gotowym do użycia w Phase 7+. ## 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.php` - `composer.json` z `"php": ">=7.4"` - `.paul/phases/06-admin-base/06-01-SUMMARY.md` - **Form VMs** — Czy mamy już Form ViewModele, czy kopiować z shopPRO? → Odpowiedź: Skopiuj z shopPRO teraz (PROJECT.md deklarował, ale plików nie ma). - **NS case** — Jaka konwencja namespace dla Admin\? → Odpowiedź: Fully PascalCase (`Admin\Base`, `Admin\Support`, `Admin\ViewModels\Forms`, `Admin\Validation`). Nie powielać błędu shopPRO (`admin\` lowercase). - **PHP target** — Cel PHP dla nowego kodu? → Odpowiedź: `>=7.4` w composer.json. Docelowo musi działać też na 8.4/8.5+, więc kod ma być forward-compatible (typed properties OK, ale unikać deprecated wzorców 8.x). - **Scope** — Zakres Phase 6? → Odpowiedź: Splituję Phase 6 na 2 plany. 06-01 = Forms (ten plan). 06-02 = TableListRequestFactory + BaseController. ## 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 ## AC-1: Form ViewModels load via PSR-4 ```gherkin 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 ```gherkin 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 ```gherkin 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 ```gherkin 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 ```gherkin 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ą ``` 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 -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 19 - `autoload/Domain/**` — Phase 5 closed, repozytoria stabilne - `autoload/Shared/**` — Phase 2 closed - `autoload/autoloader.php` — Phase 1 (hybrid loader działa); composer dump zaktualizuje vendor/, autoloader.php nie wymaga edycji - `composer.lock` — nie aktualizuj (`composer update` zakazany 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 Przed declared complete: - [ ] `php -l` zielony dla wszystkich 6 nowych plików - [ ] `composer dump-autoload` zwraca exit 0 - [ ] Smoke test (Task 4) zwraca "OK:..." - [ ] `grep -r "namespace admin\\\\" autoload/Admin/` → brak wyników (zero lowercase namespace w nowym Admin/) - [ ] `git diff` pokazuje tylko: nowe pliki Admin/ + composer.json + vendor/composer/autoload_classmap.php (regen) - [ ] Wszystkie AC (1-5) spełnione - 5 Form ViewModeli + FormValidator dostępne pod namespace `Admin\ViewModels\Forms\` i `Admin\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 Po wykonaniu utworzyć `.paul/phases/06-admin-base/06-01-SUMMARY.md` z: - Lista skopiowanych plików (z liczbą linii) - Output smoke testu (literalnie) - Wszelkie deferred issues (np. coś co warto zrefaktoryzować w FormValidator/FormField w przyszłości) - Setup dla Plan 06-02 (jakie założenia po 06-01: Admin\ namespace działa, Form VMs dostępne)