Files
cmsPRO/docs/FORM_EDIT_SYSTEM.md
Jacek Pyziak 9ee4116f50 Refaktoryzacja Faza 0+1: PSR-4 autoloader + Shared/Domain klasy
- Dodano PSR-4 autoloader do wszystkich 6 punktów wejścia
- Shared\: CacheHandler, Helpers, Html, ImageManipulator, Tpl
- Domain\: LanguagesRepository, SettingsRepository, UserRepository
- Stare class.*.php → cienkie wrappery (kompatybilność wsteczna)
- Dodano dokumentację: docs/PROJECT_STRUCTURE.md + pozostałe docs/
- Dodano CLAUDE.md z workflow

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-27 23:43:55 +01:00

8.6 KiB

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

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