# Admin Form Fields Usage Guide

Dokumentation für das neue composition-basierte Admin Form Field System.

## Übersicht

Das Admin Form Field System wurde vollständig refactored zu einem composition-basierten Design ohne Vererbung. Alle Fields implementieren das `FormField` Interface und nutzen Value Objects für gemeinsame Funktionalität.

## Architektur

```
FormField (Interface)
├── FieldMetadata (Value Object) - name, label, help
├── FieldAttributes (Value Object) - HTML attributes
├── FieldWrapper (Component) - wrapping logic
└── Field Implementations (ohne extends!)
    ├── TextField
    ├── EmailField
    ├── NumberField
    ├── TextareaField
    ├── SelectField
    ├── DateTimeField
    ├── CheckboxField
    └── HiddenField
```

## Verfügbare Field Types

### TextField
Einfaches Text Input Field.

```php
use App\Framework\Admin\FormFields\Fields\TextField;

$field = TextField::create(
    name: 'username',
    label: 'Username',
    value: 'john_doe',
    required: true,
    placeholder: 'Enter your username',
    help: 'Choose a unique username'
);

$form = $field->render($formBuilder);
```

### EmailField
Email Input mit Browser-Validierung.

```php
use App\Framework\Admin\FormFields\Fields\EmailField;

$field = EmailField::create(
    name: 'email',
    label: 'Email Address',
    value: 'user@example.com',
    required: true,
    placeholder: 'you@example.com',
    help: 'We will never share your email'
);

$form = $field->render($formBuilder);
```

### NumberField
Number Input mit min/max/step Constraints.

```php
use App\Framework\Admin\FormFields\Fields\NumberField;

$field = NumberField::create(
    name: 'age',
    label: 'Age',
    value: 25,
    required: true,
    min: 18,
    max: 120,
    step: 1,
    help: 'Must be 18 or older'
);

$form = $field->render($formBuilder);
```

### TextareaField
Multi-line Text Input.

```php
use App\Framework\Admin\FormFields\Fields\TextareaField;

$field = TextareaField::create(
    name: 'description',
    label: 'Description',
    value: 'Long text content...',
    required: false,
    placeholder: 'Enter description',
    help: 'Provide a detailed description',
    rows: 10
);

$form = $field->render($formBuilder);
```

### SelectField
Dropdown Select mit Options.

```php
use App\Framework\Admin\FormFields\Fields\SelectField;

$field = SelectField::create(
    name: 'status',
    label: 'Status',
    options: [
        'draft' => 'Draft',
        'published' => 'Published',
        'archived' => 'Archived'
    ],
    value: 'draft',
    required: true,
    help: 'Select campaign status',
    placeholder: 'Choose status...'
);

$form = $field->render($formBuilder);
```

### DateTimeField
DateTime Input mit verschiedenen Typen.

```php
use App\Framework\Admin\FormFields\Fields\DateTimeField;

// DateTime Local
$field = DateTimeField::create(
    name: 'release_date',
    label: 'Release Date',
    value: new \DateTime('2024-06-15 14:30:00'),
    required: true,
    help: 'When to release the track',
    type: 'datetime-local'
);

// Date Only
$field = DateTimeField::create(
    name: 'birth_date',
    label: 'Birth Date',
    value: '1990-05-20',
    type: 'date'
);

// Time Only
$field = DateTimeField::create(
    name: 'appointment_time',
    label: 'Time',
    value: '14:30',
    type: 'time'
);

$form = $field->render($formBuilder);
```

### CheckboxField
Checkbox mit custom checked value.

```php
use App\Framework\Admin\FormFields\Fields\CheckboxField;

$field = CheckboxField::create(
    name: 'accept_terms',
    label: 'I accept the terms and conditions',
    value: true,
    required: true,
    help: 'You must accept to continue',
    checkedValue: '1'
);

$form = $field->render($formBuilder);
```

### HiddenField
Hidden Input (kein Label/Wrapper).

```php
use App\Framework\Admin\FormFields\Fields\HiddenField;

$field = HiddenField::create(
    name: 'campaign_id',
    value: 'abc123'
);

$form = $field->render($formBuilder);
```

## FormFieldFactory Usage

Die `FormFieldFactory` erstellt Fields aus Array-Konfiguration:

```php
use App\Framework\Admin\FormFields\FormFieldFactory;

$factory = new FormFieldFactory();

// Single field from config
$field = $factory->createFromConfig([
    'type' => 'text',
    'name' => 'artist_name',
    'label' => 'Artist Name',
    'value' => 'John Doe',
    'required' => true,
    'placeholder' => 'Enter artist name',
    'help' => 'The name of the performing artist'
]);

// Multiple fields from config array
$fields = $factory->createMultiple([
    [
        'type' => 'text',
        'name' => 'track_title',
        'label' => 'Track Title',
        'required' => true
    ],
    [
        'type' => 'select',
        'name' => 'genre',
        'label' => 'Genre',
        'options' => [
            'pop' => 'Pop',
            'rock' => 'Rock',
            'jazz' => 'Jazz'
        ],
        'required' => true
    ],
    [
        'type' => 'datetime',
        'name' => 'release_date',
        'label' => 'Release Date',
        'datetime_type' => 'datetime-local',
        'required' => true
    ]
]);

// Render all fields to form
foreach ($fields as $field) {
    $formBuilder = $field->render($formBuilder);
}
```

## AdminFormFactory Integration

Die `AdminFormFactory` nutzt automatisch die `FormFieldFactory`:

```php
use App\Framework\Admin\Factories\AdminFormFactory;
use App\Framework\Admin\ValueObjects\AdminFormConfig;
use App\Framework\Http\Method;

$formFactory = $container->get(AdminFormFactory::class);

$formConfig = new AdminFormConfig(
    resource: 'campaigns',
    action: '/admin/campaigns/store',
    method: Method::POST,
    fields: [
        'track_title' => [
            'type' => 'text',
            'label' => 'Track Title',
            'required' => true,
            'placeholder' => 'Enter track title'
        ],
        'artist_name' => [
            'type' => 'text',
            'label' => 'Artist Name',
            'required' => true
        ],
        'release_date' => [
            'type' => 'datetime',
            'label' => 'Release Date',
            'datetime_type' => 'datetime-local',
            'required' => true,
            'help' => 'When to release the track'
        ],
        'genre' => [
            'type' => 'select',
            'label' => 'Genre',
            'options' => [
                'pop' => 'Pop',
                'rock' => 'Rock',
                'electronic' => 'Electronic',
                'jazz' => 'Jazz'
            ],
            'required' => true
        ],
        'description' => [
            'type' => 'textarea',
            'label' => 'Description',
            'rows' => 5,
            'placeholder' => 'Track description...'
        ],
        'is_featured' => [
            'type' => 'checkbox',
            'label' => 'Feature this track',
            'checked_value' => '1'
        ]
    ],
    data: [
        'track_title' => 'Summer Vibes',
        'artist_name' => 'DJ Cool',
        'is_featured' => true
    ]
);

$form = $formFactory->create($formConfig);
```

## Framework Compliance

Das neue System folgt allen Framework-Prinzipien:

### ✅ No Inheritance
- Alle Fields sind `final readonly` classes
- Keine `extends` oder `abstract` classes
- Pure composition über Value Objects und Components

### ✅ Immutability
- Alle classes `readonly`
- Value Objects für gemeinsame Daten
- `withAdditional()` für Attribute-Erweiterung

### ✅ Explicit Dependencies
- Constructor Injection für alle Dependencies
- Keine globalen States oder Service Locators
- Klare Dependency Chain

### ✅ Type Safety
- Strikte Typisierung überall
- Value Objects statt Arrays
- Interface-basiertes Design

## Extension Pattern

Neue Field Types hinzufügen:

```php
namespace App\Framework\Admin\FormFields\Fields;

use App\Framework\Admin\FormFields\FormField;
use App\Framework\Admin\FormFields\ValueObjects\FieldAttributes;
use App\Framework\Admin\FormFields\ValueObjects\FieldMetadata;
use App\Framework\Admin\FormFields\Components\FieldWrapper;
use App\Framework\View\FormBuilder;
use App\Framework\View\ValueObjects\FormElement;

final readonly class ColorPickerField implements FormField
{
    public function __construct(
        private FieldMetadata $metadata,
        private FieldAttributes $attributes,
        private FieldWrapper $wrapper,
        private mixed $value = null
    ) {}

    public static function create(
        string $name,
        string $label,
        mixed $value = null,
        bool $required = false,
        ?string $help = null
    ): self {
        return new self(
            metadata: new FieldMetadata($name, $label, $help),
            attributes: new FieldAttributes(
                name: $name,
                id: $name,
                required: $required
            ),
            wrapper: new FieldWrapper(),
            value: $value
        );
    }

    public function render(FormBuilder $form): FormBuilder
    {
        $attrs = $this->attributes->withAdditional(['type' => 'color']);
        $attrArray = $attrs->toArray();

        if ($this->value !== null) {
            $attrArray['value'] = (string) $this->value;
        }

        $input = FormElement::create('input', $attrArray);
        $wrapped = $this->wrapper->wrap($input, $this->metadata);

        return $form->addElement($wrapped);
    }

    public function getName(): string
    {
        return $this->metadata->name;
    }

    public function getValue(): mixed
    {
        return $this->value;
    }

    public function getLabel(): string
    {
        return $this->metadata->label;
    }
}
```

Dann in `FormFieldFactory` registrieren:

```php
// In createFromConfig() method
return match ($type) {
    // ... existing types
    'color' => ColorPickerField::create(
        name: $name,
        label: $config['label'] ?? ucfirst($name),
        value: $config['value'] ?? null,
        required: $config['required'] ?? false,
        help: $config['help'] ?? null
    ),
    // ...
};
```

## Best Practices

1. **Verwende Factory Methods**: Nutze `::create()` statt direkter Konstruktor-Aufrufe
2. **Type-spezifische Validierung**: Jeder Field Type validiert seine Inputs
3. **Wiederverwendbare Komponenten**: `FieldWrapper` für konsistentes HTML
4. **Value Objects**: `FieldMetadata`, `FieldAttributes`, `FieldOptions` für gemeinsame Daten
5. **Interface-basiert**: Alle Fields implementieren `FormField` Interface
6. **Composition**: Komponiere Funktionalität statt Vererbung zu nutzen

## Migration von alter zu neuer API

### Alt (direkter FormBuilder):
```php
$form->addTextInput('username', $value, 'Username');
$form->addEmailInput('email', $value, 'Email');
```

### Neu (composition-basierte Fields):
```php
$usernameField = TextField::create('username', 'Username', value: $value);
$emailField = EmailField::create('email', 'Email', value: $value);

$form = $usernameField->render($form);
$form = $emailField->render($form);
```

### Oder via Factory:
```php
$fields = $fieldFactory->createMultiple([
    ['type' => 'text', 'name' => 'username', 'label' => 'Username', 'value' => $value],
    ['type' => 'email', 'name' => 'email', 'label' => 'Email', 'value' => $value]
]);

foreach ($fields as $field) {
    $form = $field->render($form);
}
```

## Testing

```php
describe('TextField', function () {
    it('renders text input with value', function () {
        $field = TextField::create(
            name: 'username',
            label: 'Username',
            value: 'john_doe',
            required: true
        );

        $formBuilder = FormBuilder::create('/test', 'POST', $this->formIdGenerator);
        $result = $field->render($formBuilder);

        $html = $result->build();

        expect($html)->toContain('type="text"');
        expect($html)->toContain('name="username"');
        expect($html)->toContain('value="john_doe"');
        expect($html)->toContain('required="required"');
    });
});
```
