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>
267 lines
13 KiB
Markdown
267 lines
13 KiB
Markdown
---
|
||
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
|
||
---
|
||
|
||
<objective>
|
||
## 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`
|
||
</objective>
|
||
|
||
<context>
|
||
<clarifications>
|
||
- **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.
|
||
</clarifications>
|
||
|
||
## 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
|
||
</context>
|
||
|
||
<acceptance_criteria>
|
||
|
||
## 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ą
|
||
```
|
||
|
||
</acceptance_criteria>
|
||
|
||
<tasks>
|
||
|
||
<task type="auto">
|
||
<name>Task 1: Skopiuj 5 Form ViewModeli z shopPRO do Admin\ViewModels\Forms\ z PascalCase namespace</name>
|
||
<files>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</files>
|
||
<action>
|
||
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/`)
|
||
</action>
|
||
<verify>
|
||
`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
|
||
</verify>
|
||
<done>AC-1 częściowo (klasy istnieją), AC-4 częściowo (PascalCase namespace).</done>
|
||
</task>
|
||
|
||
<task type="auto">
|
||
<name>Task 2: Skopiuj FormValidator do Admin\Validation\ z PascalCase namespace i poprawnymi `use`</name>
|
||
<files>autoload/Admin/Validation/FormValidator.php</files>
|
||
<action>
|
||
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)
|
||
</action>
|
||
<verify>
|
||
`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;`
|
||
</verify>
|
||
<done>AC-2 satisfied: FormValidator ładuje się i zna FormField/FormFieldType.</done>
|
||
</task>
|
||
|
||
<task type="auto">
|
||
<name>Task 3: Dodaj `php: >=7.4` do composer.json i zregeneruj autoloader</name>
|
||
<files>composer.json</files>
|
||
<action>
|
||
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+)
|
||
</action>
|
||
<verify>
|
||
`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)`
|
||
</verify>
|
||
<done>AC-1 satisfied (autoload działa dla wszystkich 6 klas), AC-4 satisfied (php>=7.4).</done>
|
||
</task>
|
||
|
||
<task type="auto">
|
||
<name>Task 4: Smoke test — runtime sanity check formularza</name>
|
||
<files>(brak modyfikacji — tylko weryfikacja runtime)</files>
|
||
<action>
|
||
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
|
||
</action>
|
||
<verify>
|
||
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)
|
||
</verify>
|
||
<done>AC-3 satisfied (walidacja działa runtime), AC-5 satisfied (zero regresji — tylko nowe pliki + composer.json).</done>
|
||
</task>
|
||
|
||
</tasks>
|
||
|
||
<boundaries>
|
||
|
||
## 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
|
||
|
||
</boundaries>
|
||
|
||
<verification>
|
||
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
|
||
</verification>
|
||
|
||
<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>
|
||
|
||
<output>
|
||
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)
|
||
</output>
|