Chainer les décorateurs

Rendu individuel des décorateurs

Dans la section précédente, nous avons vu comment combiner les décorateurs afin de créer un rendu complexe. Ceci est très fléxible mais rajoute tout de même un part de compléxité à l'ensemble. Dans ce chapitre, nous allons inspecter le rendu individuel des décorateurs afin de créer du contenu visuel pour des formulaires ou des éléments.

Une fois des décorateurs enregistrés, vous pouvez les récupérer via leur nom depuis l'élément. Revoyons l'exemple précédent:

  1. $element = new Zend_Form_Element('foo', array(
  2.     'label'      => 'Foo',
  3.     'belongsTo'  => 'bar',
  4.     'value'      => 'test',
  5.     'prefixPath' => array('decorator' => array(
  6.         'My_Decorator' => 'path/to/decorators/',
  7.     )),
  8.     'decorators' => array(
  9.         'SimpleInput'
  10.         array('SimpleLabel', array('placement' => 'append')),
  11.     ),
  12. ));

Si nous voulons récupérer le décorateur SimpleInput, nous passons par la méthode getDecorator():

  1. $decorator = $element->getDecorator('SimpleInput');
  2. echo $decorator->render('');

C'est simple et ça peut l'être encore plus; ré-écrivons le tout sur une seule ligne:

  1. echo $element->getDecorator('SimpleInput')->render('');

Pas mauvais, mais toujours un peu compliqué. Pour simplifier, une notation raccourcie a été introduite dans Zend_Form en 1.7: vous pouvez rendre n'importe quel décorateur enregistré en appelant une méthode de la forme renderDecoratorName(). Ceci effectue le rendu et fait en sorte que $content soit optionnel ce qui simplifie l'utilisation:

  1. echo $element->renderSimpleInput();

C'est une simplification astucieuse, mais comment et pourquoi l'utiliser?

Beaucoup de développeurs ont des besoins très précis en affichage des formulaires. Ils préfèrent avoir un contrôle complet sur tout l'affichage plutôt que d'utiliser une solution automatisée qui peut s'écarter de leur but initial. Dans d'autres cas, les formulaires peuvent demander un affichage extrêmement spécifique, en groupant des éléments alors que d'autres doivent pouvoir être invisibles avant que l'on n'effectue telle action sur la page, etc.

Utilisons la possibilité de rendre un seul décorateur pour créer un affichage précis.

D'abord, définissons un formulaire. Celui-ci récupèrera des détails démographiques sur l'utilisateur. Le rendu sera hautement personnalisé et dans certains cas il utilisera les aides de vue directement plutôt que les éléments. Voici une définition simple du formulaire:

  1. class My_Form_UserDemographics extends Zend_Form
  2. {
  3.     public function init()
  4.     {
  5.         // Ajoute un chemin pour les décorateurs personnalisés
  6.         $this->addElementPrefixPaths(array(
  7.             'decorator' => array('My_Decorator' => 'My/Decorator'),
  8.         ));
  9.  
  10.         $this->addElement('text', 'firstName', array(
  11.             'label' => 'First name: ',
  12.         ));
  13.         $this->addElement('text', 'lastName', array(
  14.             'label' => 'Last name: ',
  15.         ));
  16.         $this->addElement('text', 'title', array(
  17.             'label' => 'Title: ',
  18.         ));
  19.         $this->addElement('text', 'dateOfBirth', array(
  20.             'label' => 'Date of Birth (DD/MM/YYYY): ',
  21.         ));
  22.         $this->addElement('text', 'email', array(
  23.             'label' => 'Your email address: ',
  24.         ));
  25.         $this->addElement('password', 'password', array(
  26.             'label' => 'Password: ',
  27.         ));
  28.         $this->addElement('password', 'passwordConfirmation', array(
  29.             'label' => 'Confirm Password: ',
  30.         ));
  31.     }
  32. }

Note: Nous n'utilisons pas de validateurs ou de filtres ici, car ils n'ont rien à voir avec le rendu visuel qui nous interesse. En réalité, il y en aurait.

Maintenant réfléchissons au rendu visuel du formulaire. Une communalité concernant les nom et prénom est qu'on les affiche l'un à coté de l'autre, à coté de leur titre, si présent. Les dates, si elles n'utilisent pas Javascript, affichent souvent des champs séparés pour chaque segment de la date.

Utilisons la possibilité de rendre des décorateurs un par un pour accomplir notre tâche. D'abord, notez qu'aucun décorateur spécifique n'a été renseigné dans les éléments. Rappelons donc les décorateurs par défaut de la plupart des éléments:

  • ViewHelper: utilise une aide de vue pour rendre l'élément balise de formulaire à proprement parlé.

  • Errors: utilise l'aide de vue FormErrors pour afficher les erreurs de validation éventuelles.

  • Description: utilise l'aide de vue FormNote afin de rendre la description éventuelle de l'élément.

  • HtmlTag: encapsule les trois objets ci-dessus dans un tag <dd>.

  • Label: rend l'intitulé de l'élément en utilisant l'aide de vue FormLabel (et en encapsulant le tout dans un tag <dt>).

Nous vous rappelons aussi que vous pouvez accéder à tout élément individuellement en tant qu'attribut du formulaire représentant son nom.

Notre script de vue ressemblerait à cela:

  1. <?php
  2. $form = $this->form;
  3. // Enlève le <dt> depuis l'intitulé
  4. foreach ($form->getElements() as $element) {
  5.     $element->getDecorator('label')->setOption('tag', null);
  6. }
  7. ?>
  8. <form method="<?php echo $form->getMethod() ?>" action="<?php echo
  9.     $form->getAction()?>">
  10.     <div class="element">
  11.         <?php echo $form->title->renderLabel()
  12.               . $form->title->renderViewHelper() ?>
  13.         <?php echo $form->firstName->renderLabel()
  14.               . $form->firstName->renderViewHelper() ?>
  15.         <?php echo $form->lastName->renderLabel()
  16.               . $form->lastName->renderViewHelper() ?>
  17.     </div>
  18.     <div class="element">
  19.         <?php echo $form->dateOfBirth->renderLabel() ?>
  20.         <?php echo $this->formText('dateOfBirth[day]', '', array(
  21.             'size' => 2, 'maxlength' => 2)) ?>
  22.         /
  23.         <?php echo $this->formText('dateOfBirth[month]', '', array(
  24.             'size' => 2, 'maxlength' => 2)) ?>
  25.         /
  26.         <?php echo $this->formText('dateOfBirth[year]', '', array(
  27.             'size' => 4, 'maxlength' => 4)) ?>
  28.     </div>
  29.     <div class="element">
  30.         <?php echo $form->password->renderLabel()
  31.               . $form->password->renderViewHelper() ?>
  32.     </div>
  33.     <div class="element">
  34.         <?php echo $form->passwordConfirmation->renderLabel()
  35.               . $form->passwordConfirmation->renderViewHelper() ?>
  36.     </div>
  37.     <?php echo $this->formSubmit('submit', 'Save') ?>
  38. </form>

Si vous utilisez le script ci-dessus, vous verrez un code HTML ressemblant à ceci:

  1. <form method="post" action="">
  2.     <div class="element">
  3.         <label for="title" tag="" class="optional">Title:</label>
  4.         <input type="text" name="title" id="title" value=""/>
  5.  
  6.         <label for="firstName" tag="" class="optional">First name:</label>
  7.         <input type="text" name="firstName" id="firstName" value=""/>
  8.  
  9.         <label for="lastName" tag="" class="optional">Last name:</label>
  10.         <input type="text" name="lastName" id="lastName" value=""/>
  11.     </div>
  12.  
  13.     <div class="element">
  14.         <label for="dateOfBirth" tag="" class="optional">Date of Birth
  15.             (DD/MM/YYYY):</label>
  16.         <input type="text" name="dateOfBirth[day]" id="dateOfBirth-day"
  17.             value="" size="2" maxlength="2"/>
  18.         /
  19.         <input type="text" name="dateOfBirth[month]" id="dateOfBirth-month"
  20.             value="" size="2" maxlength="2"/>
  21.         /
  22.         <input type="text" name="dateOfBirth[year]" id="dateOfBirth-year"
  23.             value="" size="4" maxlength="4"/>
  24.     </div>
  25.  
  26.     <div class="element">
  27.         <label for="password" tag="" class="optional">Password:</label>
  28.         <input type="password" name="password" id="password" value=""/>
  29.     </div>
  30.  
  31.     <div class="element">
  32.         <label for="passwordConfirmation" tag="" class="" id="submit"
  33.             value="Save"/>
  34. </form>

Ca peut ne pas ressembler à quelque chose de terminé, mais avec un peu de CSS, cela peut ressembler exactement à ce que vous cherchez. Le point important ici, c'est que le formulaire a été généré en utilisant de la décoration manuelle personnalisée (ainsi que l'utilisation d'échappement avec htmlentities).

Grâce à cette partie du tutoriel, vous devriez être à l'aise avec les possibilité de rendu de Zend_Form. Dans la section suivante, nous verrons comment monter un élément de date grâce à des éléments et des décorateur uniques assemblés main.


Chainer les décorateurs