Chainer les décorateursSi vous avez bien suivi la section précédente, vous avez pu remarquer que la méthode render() prend un argument, $content. Il est de type chaine de caractères. render() va utiliser cette chaine et décider de la remplacer, de rajouter ou de faire précéder du contenu à celle-ci. Ceci permet de chaine les décorateurs -- ce qui ouvre des possibilités de créer ses propres décorateurs qui vont rendre une petite partie des données d'un élément chacun -- c'est la chaine complet de décorateurs qui déterminera le rendu final réel de l'élément. Voyons voir en pratique comment ça fonctionne. Pour la plupart des éléments, les décorateurs suiovants sont chargés par défaut:
Notez bien que chaque décorateur na qu'une petite tâche particulière et opère sur une partie spécifique des données de l'élément auquel il est rattaché, le décorateur Errors récupère les messages de validation de l'élément et les rend, le décorateur Label rend simplement le libéllé. Ceci fait que chaque décorateur est très petit, réutilisable, et surtout testable. Cet argument $content vient de là aussi : chaque décorateur travaille avec sa méthode render() sur un contenu (générallement généré par le décorateur immédiatement précédent dans la pile globale) et embellit ce contenu en lui rajoutant ou en lui faisant précéder des informations. Il peut aussi remplacer totallement son contenu. Ainsi, pensez au mécanisme des décorateurs comme la conception d'un oignon de l'intérieur vers l'exterieur. Voyons voir un exemple, le même que celuide la section précédente:
Supprimons la fonctionnalité libéllé (label) et créons un décorateur spécifique pour lui.
Ok, ca semble bon mais il y a un problème : le dernier décorateur va l'emporter. Vous allez vous retrouver avec comme seul rendu, celui du dernier décorateur. Pour faire fonctionner le tout comme il se doit, concaténez simplement le contenu précédent $content avec le contenu généré:
Le problème avec cette approche est que vous ne pouvez pas choisir où se place le contenu du décorateur en question. Heureusement, un mécanisme standard existe; Zend_Form_Decorator_Abstract possède le concept de place et définit des constantes pour le régler. Aussi, il permet de préciser un séparateur à placer entre les 2. Voyons celà:
Notez que dans l'exemple ci-dessus, nous intervertissons les comportements par défaut avec append et prepend. Créons dès lors un élément de formulaire qui va utiliser tout celà: Comment ça fonctionne? et bien nous appelons render(), l'élément va alors commencer une itération sur tous ses décorateurs, en appelant render() sur chacun. Il va passer une chaine vide comme contenu pour le premier décorateur, et le rendu de chaque décorateur va servir de contenu pour le suivant, ainsi de suite:
Mais attendez une minute! Et si nous voulions que le libéllé soit rendu après le tag de formulaire pour une raison quelconque? Vous souvenez-vous de l'option "placement"? Vous pouvez la préciser comme option de décorateur, et le plus simple est alors de la passer à la création de l'élément: Notez que passer des options vous oblige à préciser le nom du décorateur dans un tableau en tant que premier élément, le deuxième élément est un tableau d'options. Le code ci-dessus propose un rendu : <input id="bar-foo" name="bar[foo]" type="text" value="test"/>\n<label for="bar-foo">. Grâce à cette technique, vous pouvez avoir plusieurs décorateurs dont chacun s'occupe de rendre une petite partie d'un élément; et c'est en utilisant plusieurs décorateurs et en les chainant correctement que vous obtiendrez un rendu complet : l'oignon final. Avantages et inconvénients d'une telle technique, commençons par les inconvénients:
Les avantages sont:
Les exemples ci-dessus montrent l'utilisation de décorateurs au sein même d'un objet Zend_Form et nous avons vu comment les décorateurs jouent les uns avec les autres pour arriver au rendu final. Afin de pouvoir les utiliser de manière indépendante, la version 1.7 a ajouté des méthodes fléxibles rendant les formulaires ressemblant au style Rail. Nous allons nous pencher sur ce fait dans la section suivante.
|