I. Prérequis

La version du Zend Framework 2 utilisée pour cet article est la 2.0.0beta4. Son utilisation nécessite au minimum la version 5.3.3 de PHP.

Zend Framework 2.0 RequirementsZend Framework 2.0 Requirements

II. Qu'est-ce qui change ?

Les formulaires de la première version ont souvent fait débat au sein des développeurs. Difficile à appréhender et à mettre en œuvre, par exemple avec l'utilisation des décorateurs, l'équipe de développement du Zend Framework a souhaité revoir complètement l'organisation et la structure du composant.

III. Formulaire, fieldset et élément

Le Zend Framework 2 modifie complètement l'architecture du composant de formulaire. L'élément de base, au centre de tout le composant, est le Zend\Form\Element. L'objet Element possède des attributs et des messages, le nom de l'élément sera lui-même un attribut ayant pour clé « name ».

De cet élément sera héritée la classe Zend\Form\Fieldset qui représente un ensemble d'éléments. La classe Fieldset dispose de toutes les méthodes nécessaires à la gestion de ces éléments, comme avec les méthodes « add », « get », « has » ou encore « remove » afin d'ajouter, récupérer, vérifier la présence d'un élément ou le supprimer. En plus de contenir des objets de type Zend\Form\Element, la classe Fieldset est aussi capable de contenir d'autres instances d'objet Fieldset.

La classe de formulaire hérite de la classe Fieldset. Un formulaire étant capable de contenir de nombreux éléments, il hérite donc naturellement de la classe Element qui lui permettra de définir aussi ses attributs, comme la méthode de passage des paramètres ou encore l'action du formulaire. Notons que la classe de formulaire est séparée en deux classes : Zend\Form\Form et Zend\Form\BaseForm qui contient les actions génériques d'un formulaire.

Récapitulons le rôle de chacune de ces classes :

• Zend\Form\Element : représentation de base, définit des attributs et des messages ;

• Zend\Form\Fieldset : hérite de Zend\Form\Element, ce conteneur représente un ensemble d'objets de type Element et/ou de type Fieldset ;

• Zend\Form\BaseForm : hérite de Zend\Form\Fieldset et gère la validation du formulaire, l'ajout et la récupération des données du formulaire ainsi que les objets d'hydratation ;

• Zend\Form\Form : hérite de Zend\Form\BaseForm et gère la fabrique de formulaires, fieldset et élément. La classe s'occupe de la gestion du composant Zend\InputFilter du formulaire, qui contient filtres et validateurs.

IV. Les fabriques et les hydrateurs

La fabrique utilisée par défaut dans le composant Zend\Form est de type Zend\Form\Factory. La fabrique permet la création d'objets de formulaire, de fieldset et d'élément depuis un tableau de description passé en paramètre :

création d'un élément depuis la fabrique
Sélectionnez
$fabrique = new Zend\Form\Factory();
$element = $fabrique->create(array(
     'type' => 'Zend\Form\Element',
    'name' => 'nom',
    'attributes' => array(
        'type'  => 'text',
        'label' => 'Nom :',
    ),
));

La fabrique est utilisée lorsque nous créons des éléments depuis des tableaux au sein d'un objet de formulaire :

Formulaire utilisant la fabrique
Sélectionnez
class SimpleForm extends Form{
    public function __construct()    {
        parent::__construct();
        $this->setAttribute('method', 'post');
        $this->add(array(
            'name' => 'nom',
            'attributes' => array(
                'type'  => 'text',
                'label' => 'Nom :',
            ),
        ));
    }
}

Une fois notre formulaire construit, avec ou sans la fabrique, il doit être peuplé afin de pouvoir valider les informations injectées. Deux méthodes peuvent être utilisées pour l'injection de données :

• depuis un tableau avec la méthode « setData() » ;

• depuis un objet auquel on affecte un objet de type Zend\Stdlib\Hydrator\HydratorInterface afin de permettre l'extraction et l'injection de données.

La méthode « setData() » est simple à utiliser, il suffit de lui passer un tableau en paramètre, et les données validées seront retournées sous la forme d'un tableau de valeurs :

utilisation de la méthode "setData"
Sélectionnez
$form = new SimpleForm();
$filter = new SimpleFormFilter();
$form->setInputFilter($filter);
$form->setData(
    array(
        'nom' => 'Vincent',
        'sujet' => 'information',
        'message' => 'Ceci est un <strong>message</strong> depuis Zend\Form',
    )
);
$valid = $form->isValid();
$datas = $form->getData() ;

Le composant de formulaire laisse la possibilité de lui fournir un objet enveloppant les données à valider, ce qui aura l'avantage de pouvoir récupérer les données filtrées et validées depuis ce même objet. Cependant, afin d'indiquer au formulaire comment extraire et peupler cet objet, il est impératif de lui fournir un hydrateur afin qu'il sache quelle stratégie adopter pour le traitement de l'objet.

Trois hydrateurs d'objet sont disponibles dans l'espace de nom Zend\Stdlib\Hydrator :

• ArraySerializable : l'extraction des données se fera depuis la méthode «getArrayCopy» et l'hydratation depuis la méthode «exchangeArray» ou «populate». L'utilisation d'un objet héritant de \ArrayObject permet la prise en charge automatique de ces deux premières méthodes ;

• ObjectProperty : basé sur les propriétés publiques de l'objet, il suffira de définir une propriété publique pour chaque élément que l'on souhaite extraire ou hydrater ;

• ClassMethods : basé sur les méthodes d'altération (appelé aussi getter et setter), cet hydrateur permet d'interagir facilement avec les objets que l'on a créés.

Prenons un exemple avec l'hydrateur ClassMethods, hydrateur que j'ai implémenté dans le framework. Le formulaire de l'exemple contient trois éléments de type « text » : « nom », « prenom » et « email ».

Voici un exemple d'utilisation de ce filtre et du peuplement depuis un objet et un hydrateur :

objet utilisé par l'hydrateur
Sélectionnez
class SimpleObject{
    protected $nom;
    protected $prenom;
    protected $email;
    public function __construct($nom, $prenom, $email)    {
        $this->nom = $nom;
        $this->prenom = $prenom;
        $this->email = $email;
    }
    public function getNom()
    {
        return $this->nom;
    }
    public function setNom($nom)
    {
        $this->nom = $nom;
    }
    public function getPrenom()
    {
        return $this->prenom;
    }
    public function setPrenom($prenom)
    {
        $this->prenom = $prenom;
    }
    public function getEmail()
    {
        return $this->email;
    }
    public function setEmail($email)
     {
        $this->email = $email;
    }
}
exemple avec l'hydrateur par méthodes de classes
Sélectionnez
$form = new SimpleForm();
$filter = new SimpleFormFilter();
$form->setInputFilter($filter);
$form->setHydrator(new Zend\Stdlib\Hydrator\ClassMethods());
$object = new SimpleObject('<strong>blanchon</strong>','vincent',&#8216;blanchon.vincent@gmail.com&#146;);
$form->bind($object);
$valid = $form->isValid();
$datas = $form->getData();
$nom = $datas->getNom(); // « blanchon » sera retourné ici.

Le formulaire SimpleForm est un formulaire composé de trois éléments de type « text ». Afin de valider les valeurs passées en paramètres, le formulaire a besoin d'un élément de type Zend\InputFilter\InputFilterInterface contenant filtres et validateurs à utiliser, nous étudierons ce composant dans la prochaine section.
Les données à valider sont ensuite fournies à la méthode « setData() » et sont récupérées depuis la méthode « getData() », une fois ces dernières validées et filtrées.

V. Le composant Zend\InputFilter

Basé sur des chaînes de filtres et chaînes de validateurs, le composant Zend\InputFilter\InputFilter permet le filtrage et la validation de données. Voici un exemple avec l'objet SimpleFilter utilisé dans le formulaire précédent :

Mise en œuvreClaude Leloup2012-05-19T22:06:15« œ » <ALT + 0156> du composant Zend\InputFilter\InputFilter
Sélectionnez
class SimpleFormFilter extends InputFilter{
    public function __construct()    {
        $this->add(array(
            'name'       => 'nom',
            'required'   => true,
            'filters' => array(
                array(
                    'name'    => 'Zend\Filter\StripTags',
                ),
                array(
                    'name'    => 'Zend\Filter\StringTrim',
                ),
            ),
        ));
        $this->add(array(
            'name'       => 'prenom',
            'required'   => true,
            'filters' => array(
                array(
                    'name'    => 'Zend\Filter\StripTags',
                ),
                array(
                    'name'    => 'Zend\Filter\StringTrim',
                ),
            ),
        ));
        $this->add(array(
            'name'       => 'email',
            'required'   => true,
            'filters'    => array(
                array(
                    'name'    => 'Zend\Filter\StripTags',
                ),
            ),
            'validators' => array(
                array(
                    'name'    => 'Zend\Validator\EmailAddress',
                ),
            ),
        ));
    }
}

Il est également possible de ne pas séparer les filtres et validateurs des éléments en implémentant l'interface Zend\InputFilter\InputProviderInterface dans la classe de l'élément, ce qui l'oblige à définir la méthode « getInputSpecification() », descriptif des filtres et validateurs à utiliser. Reprenons l'exemple du formulaire SimpleForm en ajoutant des classes pour chacun des éléments, voici une classe d'élément :

Classe de l'élément Email
Sélectionnez
class Email extends Element implements InputProviderInterface{
    public function getInputSpecification()
    {
        return array(
            'name' => $this->getName(),
            'attributes' => array(
                'type'  => 'text',
                'label' => 'Email :',
            ),
            'required' => true,
            'filters' => array(
                array('name' => 'Zend\Filter\StringTrim'),
                array('name' => 'Zend\Filter\StripTags'),
            ),
            'validators' => array(
                array('name' => 'Zend\Validator\EmailAddress'),
            ),
        );
    }
}

L'implémentation du formulaire se fait légèrement différemment :

Formulaire avec des classes englobant les éléments
Sélectionnez
$form = new SimpleForm();
$form->setInputFilter(new Zend\InputFilter\InputFilter);
$form->add(new Nom('nom'));
$form->add(new Prenom('prenom'));
$form->add(new Email('email'));
$form->setHydrator(new Zend\Stdlib\Hydrator\ClassMethods());
$object = new SimpleObject('blanchon', 'vincent', ' <strong>blanchon<strong>.vincent@gmail.com');
$form->bind($object);$valid = $form->isValid();
$datas = $form->getData();
$email = $datas->getEmail();

Le composant de formulaire offre plusieurs pratiques simples de mise en place de filtres et validateurs pour les éléments, ce qui permet à l'utilisateur de séparer les différentes couches afin de les réutiliser entre les différents formulaires de l'application.

VI. Le rendu de formulaire

Le rendu de formulaire s'effectue depuis les aides de vues créées spécialement pour prendre en charge les éléments construits au sein du formulaire, voici un exemple avec le formulaire précédent :

Rendu de formulaire
Sélectionnez
<?php
$form = $this->form;
$form->prepare();
$form->setAttribute('action', $this->url('my/url'));
$form->setAttribute('method', 'post');
echo $this->form()->openTag($form);
?>
<dl class="zend_form">
<dt>
<?php echo $this->formLabel($form->get('nom')); ?>
</dt>
<dd>
<?php
    echo $this->formInput($form->get('nom'));
    echo $this->formElementErrors($form->get('nom'));
?>
</dd>
<dt>
<?php echo $this->formLabel($form->get('prenom')); ?>
</dt>
<dd>
<?php
    echo $this->formInput($form->get('prenom'));
    echo $this->formElementErrors($form->get('prenom'));
?>
</dd>
<dt>
<?php
echo $this->formLabel($form->get('email'));
?></dt>
<dd>
<?php
    echo $this->formTextarea($form->get('email'));
    echo $this->formElementErrors($form->get('email'));
?></dd>
</dl>
<?php echo $this->form()->closeTag() ?>

VII. Conclusion et ressources

Le composant de formulaire offre des possibilités de création et de gestion beaucoup plus souple pour le développeur, et va pouvoir maintenant réutiliser des briques d'éléments dans différents formulaires.

Cet article est tiré en partie du livre "Au cœur de Zend Framework 2"livre "Au cœur de Zend Framework 2" disponible au début du quatrième trimestre de l'année 2012. Dans ce livre, vous retrouverez en détail tout le fonctionnement du composant Zend\Form afin d'en maîtriser l'utilisation. Ce tutoriel est volontairement simple afin de présenter le formulaire dans ses grandes lignes.

Retrouvez mes modules ou autres fonctionnalités, créés pour le Zend Framework 2, sur mon compte github disponible à l'adresse https://github.com/blanchonvincenthttps://github.com/blanchonvincent.

Retrouvez aussi la liste des tutoriels du Zend Framework 2 sur mon domaine developpez.com : blanchon-vincent.developpez.comblanchon-vincent.developpez.com.