====== Les formulaires ====== Stato dispose d'un ensemble de classes facilitant la mise en place des formulaires dans vos applications. Elles prennent en charge un bon nombre des tâches courantes comme : * la génération automatique des éléments de formulaires * la validation des données soumises * le réaffichage du formulaire en cas d'erreurs de validation * le filtrage des données soumises et leur conversion dans le type PHP adéquat Les classes utilisées sont de 3 types : * **SInput** : classes qui correspondent à des éléments HTML, et qui gèrent donc la génération HTML * **SField** : classes responsables de la validation et du filtrage des données * **SForm** : classe contenant une collection de champs, donc d'instances de classes de type SField ===== Objets SForm ===== Un objet SForm encapsule un ensemble de champ de formulaires et un ensemble de règles de validation devant être remplies afin que le formulaire soit accepté. L'idée est donc de créer des sous-classes de SForm dans lesquelles vous pourrez définir les champs et leurs propriétés. Par exemple, pour un formulaire de contact, vous pourriez créer la classe suivante : class ContactForm extends SForm { public function __construct(array $data = null, array $files = null) { parent::__construct($data, $files); $this->subject = new SCharField(array('max_length' => 100)); $this->message = new STextField(); $this->sender = new SEmailField(array('required' => true)); $this->cc_me = new SBooleanField(); } } L'affichage du formulaire dans un template peut se faire de façon très simple :

Contact us

form; ?>
Notez bien que le formulaire ne génère que ses propres champs, il ne s'occupe pas de la balise ''form'' ou du(des) bouton(s) de soumission. La classe SForm génère par défaut le HTML du formulaire avec chaque champ et son label dans une balise ''paragraph'' :

Contact us

Remarquez que par défaut, l'ID HTML de chaque élément du formulaire correspond à son attribut ''name''. Vous pouvez modifier ce comportement à l'aide de la méthode ''set_prefix()'' : class ContactForm extends SForm { public function __construct(array $data = null, array $files = null) { parent::__construct($data, $files); $this->set_prefix('contact'); ... } } Le résultat sera que l'ID de chaque élément sera préfixé de ''contact_'' et que les attributs ''name'' seront modifiés de façon à ce que les données soumises soient récupérées par PHP sous la forme d'un tableau (par exemple le champ ''subject'' aura pour attribut ''contact[subject]'') : ...... Vous pouvez alors, dans votre contrôleur, récupérer les données soumises dans ''$this->params['contact']''. Cette fonctionnalité peut par exemple être utilisée pour placer plusieurs formulaires Stato dans un même tag ''
''. Chaque formulaire aura ainsi son propre espace de nommage. ===== Utilisation des formulaires dans les contrôleurs ===== Par convention, les fichiers contenant les classes de formulaires sont placés dans le dossier ''app/forms''. Vous devez par ailleurs ajouter un ''require'' dans le fichier du contrôleur utilisant la classe de formulaire : require 'forms/contact_form.php'; class ContactController extends ApplicationController { ..... La validation des données soumises se fait typiquement de la façon suivante : public function contact() { if (!$this->request->is_post()) { $this->form = new ContactForm(); } else { $this->form = new ContactForm($this->params['contact']); if ($this->form->is_valid()) { // do something with the data $this->redirect_to(array('action' => 'thanks')); return; } } } Si le formulaire n'a pas été soumis, on crée une instance vierge pour affichage. Si il a été soumis, on crée une instance à laquelle on lie les données soumises et vérifie que ces données sont valides. Si c'est bien le cas, on utilise les données et on redirige vers une autre page, sinon le formulaire sera automatiquement réaffiché avec les données qui ont été validées ainsi que les erreurs de validation. Vous pouvez également lier au formulaire les données soumises en les passant en argument de ''is_valid()'' plutôt que du constructeur. Cela vous permet d'écrire votre action d'une façon légèrement différente : public function contact() { $this->form = new ContactForm(); if ($this->request->is_post()) { if ($this->form->is_valid($this->params['contact'])) { // do something with the data $this->redirect_to(array('action' => 'thanks')); return; } } } Une fois que ''is_valid'' retourne ''true'', cela signifie que les données soumises se conforment bien à vos règles de validation. Vous pouvez alors accéder aux données par la propriété ''$cleaned_data'' de votre objet de formulaire. Les données contenues par cette propriété ont en effet été non seulement validées, mais aussi typées (la clé ''cc_me'' correspondra ici à une valeur booléenne par exemple) et filtrées. En reprenant l'exemple précédent, voici comment vous pourriez utiliser les données : public function contact() { $this->form = new ContactForm(); if ($this->request->is_post()) { if ($this->form->is_valid($this->params['contact'])) { // do something with the data $subject = $this->form->cleaned_data['subject']; $message = $this->form->cleaned_data['message']; $sender = $this->form->cleaned_data['sender']; $cc_me = $this->form->cleaned_data['cc_me']; $recipients = array('info@example.com'); if ($cc_me) $recipients[] = $sender; $notifier = new Notifier; $notifier->send_contact_request_notification($subject, $message, $sender, $recipients); $this->redirect_to(array('action' => 'thanks')); return; } } } ===== Affichage des erreurs ===== Si la validation du formulaire échoue, les messages d'erreurs correspondants sont regroupés dans la propriété ''$errors'' du formulaire qui peut être utilisée dans le template du formulaire (par défaut, le HTML généré sera une liste à puces) :

Contact us

form->errors)) : ?>
form->errors; ?>
form; ?>
===== Personnaliser le template de formulaire ===== Si le HTML généré par défaut par le formulaire ne vous convient pas, vous pouvez personnaliser la présentation du formulaire dans votre template :
form->subject; ?>
form->message; ?>
De plus, la classe SForm implémentant l'interface ''Iterator'', vous pouvez boucler sur les champs du formulaire :
form as $field) : ?>
label_tag; ?> error; ?>
Dans cette boucle, ''$field'' est une instance de SBoundField, qui possède les propriétés publiques suivantes : * ''$field->label'' : le label du champ, * ''$field->label_tag'' : le label du champ dans son tag ''