# Form Edit System - Dokumentacja użycia ## Architektura ``` ┌─────────────────────────────────────────────────────────────┐ │ Controller │ │ ┌─────────────────┐ ┌─────────────────┐ │ │ │ edit() │ │ save() │ │ │ │ - buduje VM │ │ - walidacja │ │ │ │ - renderuje │ │ - zapis │ │ │ └────────┬────────┘ └─────────────────┘ │ └───────────┼─────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────┐ │ FormEditViewModel │ │ - title, formId, data, fields, tabs, actions │ │ - validationErrors, persist, languages │ └───────────┬─────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────┐ │ components/form-edit.php (szablon) │ │ ┌─────────────────────────────────────────────────────┐ │ │ │ FormFieldRenderer - renderuje każde pole │ │ │ │ ├─ input, select, textarea, switch │ │ │ │ ├─ date, datetime, editor, image │ │ │ │ └─ lang_section (zagnieżdżone pola) │ │ │ └─────────────────────────────────────────────────────┘ │ └─────────────────────────────────────────────────────────────┘ ``` ## Pliki systemu | Plik | Opis | |------|------| | `autoload/admin/ViewModels/Forms/FormFieldType.php` | Stale typow pol | | `autoload/admin/ViewModels/Forms/FormField.php` | Factory methods per typ | | `autoload/admin/ViewModels/Forms/FormTab.php` | Zakladki | | `autoload/admin/ViewModels/Forms/FormAction.php` | Akcje (zapisz, anuluj) | | `autoload/admin/ViewModels/Forms/FormEditViewModel.php` | ViewModel formularza | | `autoload/admin/Support/Forms/FormValidator.php` | Walidacja pol | | `autoload/admin/Support/Forms/FormRequestHandler.php` | Obsluga POST + persist | | `autoload/admin/Support/Forms/FormFieldRenderer.php` | Renderowanie HTML | | `admin/templates/components/form-edit.php` | Uniwersalny szablon | ## Przykład użycia w kontrolerze ```php use admin\ViewModels\Forms\FormEditViewModel; use admin\ViewModels\Forms\FormField; use admin\ViewModels\Forms\FormTab; use admin\ViewModels\Forms\FormAction; use admin\Support\Forms\FormRequestHandler; class BannerController { public function edit(): string { $banner = $this->repository->find($id); $languages = \admin\factory\Languages::languages_list(); $viewModel = new FormEditViewModel( formId: 'banner-edit', title: 'Edycja banera', data: $banner, tabs: [ new FormTab('settings', 'Ustawienia', 'fa-wrench'), new FormTab('content', 'Zawartość', 'fa-file'), ], fields: [ // Zakładka Ustawienia FormField::text('name', [ 'label' => 'Nazwa', 'tab' => 'settings', 'required' => true, ]), FormField::switch('status', [ 'label' => 'Aktywny', 'tab' => 'settings', ]), FormField::date('date_start', [ 'label' => 'Data rozpoczęcia', 'tab' => 'settings', ]), // Sekcja językowa w zakładce Zawartość FormField::langSection('translations', 'content', [ FormField::image('src', ['label' => 'Obraz']), FormField::text('url', ['label' => 'Url']), FormField::editor('text', ['label' => 'Treść']), ]), ], actions: [ FormAction::save('/admin/banners/save', '/admin/banners'), FormAction::cancel('/admin/banners'), ], languages: $languages, persist: true, ); return \Tpl::view('components/form-edit', ['form' => $viewModel]); } public function save(): void { $formHandler = new FormRequestHandler(); $viewModel = $this->buildFormViewModel(); // jak w edit() $result = $formHandler->handleSubmit($viewModel, $_POST); if (!$result['success']) { // Błędy walidacji - zapisane automatycznie do sesji echo json_encode(['success' => false, 'errors' => $result['errors']]); exit; } // Sukces - persist wyczyszczony automatycznie $this->repository->save($result['data']); echo json_encode(['success' => true]); exit; } } ``` ## Dostępne typy pól | Typ | Metoda | Opcje | |-----|--------|-------| | `text` | `FormField::text(name, ['label' => '...', 'required' => true])` | placeholder, help | | `number` | `FormField::number(name, [...])` | - | | `email` | `FormField::email(name, [...])` | walidacja formatu | | `password` | `FormField::password(name, [...])` | - | | `date` | `FormField::date(name, [...])` | datetimepicker | | `datetime` | `FormField::datetime(name, [...])` | datetimepicker z czasem | | `switch` | `FormField::switch(name, [...])` | checked (bool) | | `select` | `FormField::select(name, ['options' => [...]])` | options: [key => label] | | `textarea` | `FormField::textarea(name, ['rows' => 4])` | rows | | `editor` | `FormField::editor(name, ['toolbar' => 'MyTool'])` | CKEditor | | `image` | `FormField::image(name, ['filemanager' => true])` | filemanager URL | | `file` | `FormField::file(name, [...])` | filemanager | | `hidden` | `FormField::hidden(name, value)` | - | | `color` | `FormField::color(name, ['label' => '...'])` | HTML5 color picker + text input | | `lang_section` | `FormField::langSection(name, 'tab', [fields])` | pola per język | ## Walidacja Walidacja jest automatyczna na podstawie właściwości pól: - `required` - pole wymagane - `type` = `email` - walidacja formatu e-mail - `type` = `number` - walidacja liczby - `type` = `date` - walidacja formatu YYYY-MM-DD Dla sekcji językowych walidacja jest powtarzana dla każdego aktywnego języka. ## Persist (zapamiętywanie danych) Gdy `persist = true`: 1. Przy błędzie walidacji dane są zapisywane w `$_SESSION['form_persist'][$formId]` 2. Formularz automatycznie przywraca dane z sesji przy ponownym wyświetleniu 3. Po udanym zapisie sesja jest czyszczona automatycznie przez `FormRequestHandler` ## Przerabianie istniejących formularzy 1. **Kontroler** - zamień `view\Xxx::edit()` na `FormEditViewModel` 2. **Repository** - dostosuj `save()` do formatu z `FormRequestHandler` (lub dodaj wsparcie dla obu formatów) 3. **Szablon** - usuń stary szablon lub zostaw jako fallback 4. **Testy** - zaktualizuj testy jeśli zmienił się format danych ## Aktualizacja 2026-02-15 (ver. 0.275) - Modul `ShopCategory` zostal zmigrowany do warstwy Domain + DI, ale formularz kategorii nadal korzysta z legacy `gridEdit`. - W ramach migracji wydzielono skrypty UI do osobnych partiali `*-custom-script.php` (lista, browse, edycja, produkty), co upraszcza dalsze przepiecie formularza na `components/form-edit`. - Po migracji `ShopCategory` kolejnym kandydatem do pelnej migracji formularza na Form Edit System pozostaje modul `Order` (zgodnie z `REFACTORING_PLAN.md`). --- *Dokument aktualizowany: 2026-02-15*