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