---
title: "Formulare"
description: "Bauen Sie Formulare flüssig mit der statischen Fabrik von Nibiru."
---

Formulare in Nibiru werden **flüssig** durch Aufruf statischer Methoden auf `\Nibiru\Factory\Form` erstellt. Jeder Aufruf fügt einen HTML-Teil einem internen statischen Puffer hinzu; ein abschließender `Form::addForm()` verpackt den Puffer in ein `<form>`-Element und gibt die gerenderte HTML-Zeichenfolge zurück.

## Importieren Sie die Fabrik
```php
use Nibiru\Factory\Form;
```
Das ist der einzige `use`, den Sie benötigen. Jeder Eingabetyp ist eine statische Methode dieser Klasse.

## Der vollständige Methodenkatalog

Es gibt drei Arten der Methode, nach historischem Benennung.

### `addInputType*` — für tatsächliche `<input>`-Elemente
```
addInputTypeText        addInputTypePassword    addInputTypeEmail
addInputTypeDate        addInputTypeDatetime    addInputTypeColor
addInputTypeRadio       addInputTypeCheckbox    addInputTypeSwitch
addInputTypeSubmit      addInputTypeTextarea
```
### `addType*` — für nicht-`<input>` Formularelemente
```
addTypeFileUpload       addTypeHidden           addTypeImageSubmit
addTypeNumber           addTypeRange            addTypeReset
addTypeSearch           addTypeTelefon          addTypeUrl
addTypeButton           addTypeLabel
```
### `addSelect` / `addSelectOption` — für `<select>` + `<option>`
```
addSelect               addSelectOption
```
### Layout-Hilfsprogramme
```
addOpenDiv     addCloseDiv     addOpenAny     addCloseAny
addOpenSpan    addCloseSpan
```
### Lebenszyklus
```
create     // reset the static buffer; call before building a new form
addForm    // wrap the buffer in <form>...</form> and return as a string
```
:::caution[Die Namensinconsistenz ist absichtlich, zumindest teilweise]
`addInputTypePassword` vs `addTypePassword`, `addInputTypeFileupload` vs `addTypeFileUpload` — das Präfix entspricht, ob das Element ein `<input type="…">` (Input-Prefix) oder ein anderer Tag (Type-Prefix) ist. Es ist unangenehm, aber stabil; die CLI-`./nibiru -c`-Scaffolds verwenden dasselbe Muster, sodass die Muskelspeicherung funktioniert.
:::

## Ein Formular erstellen
```php
use Nibiru\Factory\Form;

Form::create();   // reset the static buffer

Form::addOpenDiv(['class' => 'form-group']);
Form::addTypeLabel(['for' => 'login', 'value' => 'Username']);
Form::addInputTypeText([
    'name'        => 'login',
    'id'          => 'login',
    'class'       => 'form-control',
    'required'    => 'required',
    'placeholder' => 'Type your name…',
]);
Form::addCloseDiv();

Form::addOpenDiv(['class' => 'form-group']);
Form::addTypeLabel(['for' => 'password', 'value' => 'Password']);
Form::addInputTypePassword([
    'name'     => 'password',
    'id'       => 'password',
    'class'    => 'form-control',
    'required' => 'required',
]);
Form::addCloseDiv();

Form::addInputTypeSubmit(['value' => 'Sign in', 'class' => 'btn btn-primary']);

$html = Form::addForm([
    'method' => 'POST',
    'action' => '/login',
    'name'   => 'loginForm',
]);
```
Übergeben Sie `$html` an Ihre Ansicht:
```php
View::assign(['loginForm' => $html]);
``````smarty
<div class="card-body">
  {$loginForm nofilter}
</div>
```
(`nofilter`, da `Form::addForm()` bereits gerenderte HTML zurückgibt – Smarty würde andernfalls entwerten.)

## Rezepte

### Auswahl mit Optionen
```php
Form::addSelect(['name' => 'country', 'class' => 'form-control', 'id' => 'country']);
Form::addSelectOption(['value' => 'at', 'label' => 'Austria']);
Form::addSelectOption(['value' => 'lu', 'label' => 'Luxembourg']);
Form::addSelectOption(['value' => 'us', 'label' => 'United States']);
```
`addSelect` öffnet den `<select>` und fügt den Zustand der Optionensammlung zur Warteschlange hinzu; jede `addSelectOption` hängt an diese an; das umgebende `</select>` wird automatisch ausgegeben, wenn der nächste nicht-Optionen-Aufruf stattfindet.

### Radiogruppe
```php
foreach (['standard', 'admin', 'editor'] as $r) {
    Form::addInputTypeRadio([
        'name' => 'role', 'value' => $r, 'id' => "role-$r",
    ]);
    Form::addTypeLabel(['for' => "role-$r", 'value' => ucfirst($r)]);
}
```
### Dateiupload
```php
Form::addTypeFileUpload([
    'name'   => 'avatar',
    'accept' => 'image/png,image/jpeg',
]);
```
Achten Sie nicht auf `enctype` im Formular zu vergessen:
```php
Form::addForm([
    'method'  => 'POST',
    'action'  => '/profile/upload',
    'enctype' => 'multipart/form-data',
]);
```
### Verborgener CSRF-Token
```php
Form::addTypeHidden([
    'name'  => 'csrf',
    'value' => bin2hex(random_bytes(16)),
]);
```
(Speichern Sie den Wert in `$_SESSION['csrf']` und überprüfen Sie ihn bei POST.)

## Layout-Hilfsprogramme

`addOpenDiv` / `addCloseDiv` und `addOpenAny` / `addCloseAny` ermöglichen es Ihnen, Bootstrap-artige Layouts innerhalb des gleichen flüssigen Streams zu erstellen:
```php
Form::addOpenDiv(['class' => 'row']);
  Form::addOpenDiv(['class' => 'col-md-6']);
    Form::addInputTypeText(['name' => 'first']);
  Form::addCloseDiv();
  Form::addOpenDiv(['class' => 'col-md-6']);
    Form::addInputTypeText(['name' => 'last']);
  Form::addCloseDiv();
Form::addCloseDiv();
```
`addOpenAny([…, 'tag' => 'fieldset'])` öffnet einen beliebigen anderen Tag; `addCloseAny([…, 'tag' => 'fieldset'])` schließt ihn.

## Wie es im Hintergrund funktioniert

Die Formulardarstellung ist **zeichenkettenbasiert**, nicht DOM-basiert. Jede Typklasse befindet sich unter `core/c/type<X>.php` und enthält eine HTML-Vorlage mit Platzhaltern:
```php
// core/c/typetext.php
private function _setElement() {
    $this->_element = '<input type="text" name="NAME" value="VALUE" '
                    . 'placeholder="PLACEHOLDER" maxlength="MAXLENGTH" ID CLASS '
                    . 'REQUIRED DATA>' . "\n";
}
```
Der Fabrikprozess übergibt Ihren `$attributes`-Array an `FormAttributes::loadAttributeValues()`, das jedes Platzhalterzeichen durch den entsprechenden Wert ersetzt. Leere Werte werden gelöscht, sodass die Attribute nicht mit leeren Zeichenfolgen gerendert werden.

Dies ist der Grund, warum **nur bekannte Schlüssel funktionieren** — `'name'`, `'value'`, `'placeholder'`, `'class'`, `'id'`, `'required'`, `'data'` werden erkannt; beliebige Schlüssel werden stumm abgeworfen.

## Muster aus der Produktion

Der `formsController` auf `thorax.nibiru-framework.com` baut sein Kontaktformular im Konstruktor und weist es einer Eigenschaft zu:
```php
namespace Nibiru;
use Nibiru\Adapter\Controller;
use Nibiru\Factory\Form;

class formsController extends Controller {
    private string $form;

    public function __construct() {
        parent::__construct();
        Form::create();
        Form::addTypeLabel(['value' => 'Full Name', 'for' => 'full-name']);
        Form::addInputTypeText([
            'name'     => 'full-name',
            'id'       => 'full-name',
            'required' => 'required',
            'class'    => 'contacts-input form-control',
        ]);
        // ...more fields...
        $this->form = Form::addForm([
            'name'   => 'newregister',
            'method' => 'post',
            'action' => '/forms/submit',
        ]);
    }

    public function pageAction() {
        View::assign(['form' => $this->form]);
    }
}
```
Dies behält die Aktionen des Controllers klein – das Formular ist eine Zeile, um im Template gerendert zu werden.

## Häufige Fallen

- **Versehen mit `Form::create()`.** Der Puffer ist statisch. Ohne `create()` werden Sie anhängen, was zuletzt da war (einschließlich über Anfragen in langlaufenden PHP-Prozessen).
- **Smarty maskiert das HTML.** Fügen Sie `nofilter` (oder `|nofilter`) hinzu, wenn Sie die gerenderte Zeichenfolge ausgeben.
- **Benutzerdefinierte Attribute werden stumm geschwiegen ignoriert.** Jeder Typ akzeptiert eine festgelegte Menge an Platzhalter-Schlüsseln. Verwenden Sie den `data`-Schlüssel für `data-*`-Attribute (die erweitert werden), aber wirklich willkürliche Attribute werden verworfen.
- **Keine automatische XSS-Verschleierung.** Die Form-Ebene ist zeichenkettenbasiert. Wenn Sie Benutzereingaben als Standardwert `value` rendern, verschleiern Sie sie selbst vor dem Übergeben an die Fabrik.
- **Verwirrung zwischen `addInputType…` und `addType…`.** Bei Zweifeln schauen Sie sich den Dateinamen in `core/c/type<X>.php` an — wenn das HTML-Element des Typs `<input type="X">` ist, verwenden Sie `addInputType<X>`, andernfalls `addType<X>`. `addSelect` ist die einzige Ausnahme (nur `addSelect`, ohne Präfix).

## Formularüberprüfung

Nibiru bietet keine serverseitige Validierung. Häufige Muster:

- `Respekt/Validierung` für deklarative Überprüfungen (bereits in vielen Produktionsanwendungen von Nibiru).
- Ein Modul mit einem `validate()`-Plugin pro Formulartyp.
- HTML5-Attribute wie `required`, `pattern`, `min`/`max` als erstes Schutzmaßnahme.
