Files
cmsPRO/.paul/phases/06-admin-base/06-01-PLAN.md
Jacek Pyziak a3caeb9a9a feat(06-admin-base): Admin\ base infrastructure — Form Edit System + Support layer (Phase 6)
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>
2026-04-30 23:32:26 +02:00

13 KiB
Raw Permalink Blame History

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
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
true 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

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

<success_criteria>

  • 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 </success_criteria>
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)