---
title: "Formulaires"
description: "Construisez des formulaires fluidement avec le fabrique statique de Nibiru."
---

Les formulaires dans Nibiru sont construits **naturellement** en appelant des méthodes statiques sur `\Nibiru\Factory\Form`. Chaque appel ajoute un fragment HTML à un tampon statique interne ; un `Form::addForm()` final encapsule le tampon dans un élément `<form>` et retourne la chaîne HTML rendue.

## Importer la fabrique
```php
use Nibiru\Factory\Form;
```
C'est la seule `use` dont vous avez besoin. Chaque type d'entrée est une méthode statique de cette classe.

## Le catalogue complet des méthodes

Il existe trois types de méthode, selon l'appellation historique.

### `addInputType*` — pour les éléments réels `<input>`
```
addInputTypeText        addInputTypePassword    addInputTypeEmail
addInputTypeDate        addInputTypeDatetime    addInputTypeColor
addInputTypeRadio       addInputTypeCheckbox    addInputTypeSwitch
addInputTypeSubmit      addInputTypeTextarea
```
### `addType*` — pour les éléments de formulaire autres que `<input>`
```
addTypeFileUpload       addTypeHidden           addTypeImageSubmit
addTypeNumber           addTypeRange            addTypeReset
addTypeSearch           addTypeTelefon          addTypeUrl
addTypeButton           addTypeLabel
```
### `addSelect` / `addSelectOption` — pour `<select>` + `<option>`
```
addSelect               addSelectOption
```
### Aide à la mise en page
```
addOpenDiv     addCloseDiv     addOpenAny     addCloseAny
addOpenSpan    addCloseSpan
```
### Cycle de vie
```
create     // reset the static buffer; call before building a new form
addForm    // wrap the buffer in <form>...</form> and return as a string
```
:::caution[L'incréance de nommage est intentionnelle, mais pas complètement]
`addInputTypePassword` vs `addTypePassword`, `addInputTypeFileupload` vs `addTypeFileUpload` — le préfixe correspond à ce que l'élément soit un `<input type="…">` (préfixe Input) ou une autre balise (préfixe Type). C'est un peu inconfortable, mais stable ; les modèles de conception utilisés par la CLI `./nibiru -c` suivent le même modèle, donc l'habitude s'impose.
:::

## Création d'un formulaire
```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',
]);
```
Passez `$html` à votre vue :
```php
View::assign(['loginForm' => $html]);
``````smarty
<div class="card-body">
  {$loginForm nofilter}
</div>
```
(`nofilter` car `Form::addForm()` retourne déjà du HTML rendu — Smarty l'échappe sinon.)

## Recettes

### Sélectionner avec des options
```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` ouvre le `<select>` et met en file d'attente l'état de collection d'options ; chaque `addSelectOption` y ajoute une option ; la balise fermante `</select>` est émise automatiquement lorsque le prochain appel non-option se produit.

### Groupe radio
```php
foreach (['standard', 'admin', 'editor'] as $r) {
    Form::addInputTypeRadio([
        'name' => 'role', 'value' => $r, 'id' => "role-$r",
    ]);
    Form::addTypeLabel(['for' => "role-$r", 'value' => ucfirst($r)]);
}
```
### Téléchargement de fichiers
```php
Form::addTypeFileUpload([
    'name'   => 'avatar',
    'accept' => 'image/png,image/jpeg',
]);
```
N'oubliez pas `enctype` sur le formulaire :
```php
Form::addForm([
    'method'  => 'POST',
    'action'  => '/profile/upload',
    'enctype' => 'multipart/form-data',
]);
```
### Jeton CSRF caché
```php
Form::addTypeHidden([
    'name'  => 'csrf',
    'value' => bin2hex(random_bytes(16)),
]);
```
(Mettez la valeur dans `$_SESSION['csrf']` et vérifiez lors de l'envoi par POST.)

## Aide aux dispositions

`addOpenDiv` / `addCloseDiv` et `addOpenAny` / `addCloseAny` vous permettent de composer des mises en page au style Bootstrap dans le même flux fluide :
```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'])` ouvre n'importe quel autre balise ; `addCloseAny([…, 'tag' => 'fieldset'])` la ferme.

## Comment cela fonctionne en arrière-plan

Le rendu des formulaires est **basé sur une chaîne de caractères**, pas basé sur le DOM. Chaque classe de type se trouve à `core/c/type<X>.php` et contient un modèle HTML avec des espaces réservés :
```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";
}
```
Le factory passe votre tableau `$attributes` à travers `FormAttributes::loadAttributeValues()`, qui remplace chaque espace réservé par la valeur correspondante. Les valeurs vides font en sorte que les espaces réservés soient effacés afin que les attributs ne soient pas rendus avec des chaînes vides.

C'est pourquoi **seulement les clés connues fonctionnent** — `'name'`, `'value'`, `'placeholder'`, `'class'`, `'id'`, `'required'`, `'data'` sont reconnus ; les clés arbitraires sont ignorées silencieusement.

## Modèle en production

Le `formsController` sur `thorax.nibiru-framework.com` construit son formulaire de contact dans le constructeur et l'assigne à une propriété :
```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]);
    }
}
```
Cela maintient les actions du contrôleur minuscules — le formulaire est une ligne pour être rendu dans le modèle.

## Traps courants

- **Oublier `Form::create()`.** Le tampon est statique. Sans `create()`, vous concaténerez sur ce qui était là-bas dernièrement (y compris entre les requêtes dans les processus PHP à long terme).
- **Smarty échappant l'HTML.** Ajoutez `nofilter` (ou `|nofilter`) lorsque vous affichez la chaîne rendue.
- **Attributs personnalisés ignorés silencieusement.** Chaque type accepte un ensemble fixe de clés d'espace réservé. Utilisez la clé `data` pour les attributs `data-*` (qui sont étendus), mais les attributs vraiment arbitraires sont supprimés.
- **Pas d'échappement automatique XSS.** La couche du formulaire est basée sur des chaînes de caractères. Si vous affichez une entrée utilisateur comme valeur par défaut, échappez-la vous-même avant de la passer à la fabrique.
- **Confusion entre `addInputType…` et `addType…`.** En cas de doute, regardez le nom de fichier `core/c/type<X>.php` — si l'élément HTML du type est `<input type="X">`, utilisez `addInputType<X>`, sinon utilisez `addType<X>`. `addSelect` est la seule exception (juste `addSelect`, sans préfixe).

## Validation des formulaires

Nibiru ne fournit pas la validation côté serveur. Modèles courants :

- `Respect/Validation` pour les vérifications déclaratives (déjà présentes dans de nombreuses applications Nibiru en production).
- Un module avec un plugin `validate()` par type de formulaire.
- HTML5 `required`, `pattern`, `min`/`max` comme première ligne de défense.
