symfony et sfForms : ajouter une étoile pour les champs obligatoires
Par Noël GUILBERT le dimanche, mars 22 2009, 21:49 - Lien permanent
Il est très courant sur le web d'avoir les champs obligatoires d'un formulaire marqués d'une étoile. Pourtant, avec symfony et les sfForm, ajouter ce caractère n'est pas si évident qu'il en à l'air.
La difficulté s'explique par le découplage total entre les principaux éléments d'un formulaire, à savoir les widgets et les validateurs. Ainsi, un widget n'as pas connaissance des validateurs qui lui sont attachés, et vice-versa. Pourtant, il est indispensable de savoir si un validateur à l'option "required". Pour pouvoir ajouter cette fameuse étoile, il va donc falloir trouver une solution pour que les deux éléments puissent interagir.
La semaine dernière, je suis tombé sur cet article, qui proposait une solution pour répondre à ce problème. Cette dernière me gène un peu car elle redéfinie directement le label en lui ajoutant des informations. Or, l'idéal serait d'ajouter ce caractère uniquement au moment du rendu : en effet, ce n'est que de l'affichage, donc du coté Vue du MVC.
Avec les sfForm, la Vue est caractérisée par la classe sfWidgetFormSchemaFormatter. Or cette classe a uniquement connaissance des widgets, il va donc falloir détourner légèrement son fonctionnement pour lui permettre d'avoir accès aux validateurs. Enfin, il va falloir surcharger la méthode generateLabelName(), dont le fonctionnement parle de lui même.
Sans plus attendre, voici donc notre nouveau formatter :
<?php
class sfWidgetFormSchemaFormatterRequiredFields extends sfWidgetFormSchemaFormatter
{
protected
validatorSchema ;
/**
* This constructor allow us to pass a sfValidatorSchema object to our formatter
*
*/
public function __construct(sfWidgetFormSchema $widgetSchema, sfValidatorSchema $validatorSchema)
{
parent::__construct($widgetSchema);
$this->validatorSchema = $validatorSchema;
}
public function generateLabelName($name)
{
$label = parent::generateLabelName($name);
// Is the field required ? If so we add a star to the label name
$label .= $this->validatorSchema[$name]->getOption('required') ? ' <span class="required">*</span>' : '';
return $label;
}
}
Ensuite, il suffit de d'utiliser ce formatter à la place de celui par défaut. Pour cela, il suffit d'ajouter ces deux lignes dans la méthode configure() de votre formulaire:
$this->widgetSchema->addFormFormatter('RequiredFields', new sfWidgetFormSchemaFormatterRequiredFields($this->widgetSchema, $this->validatorSchema));
$this->widgetSchema->setFormFormatterName('RequiredFields');
Vous pouvez aussi surcharger la méthode setup() de la class BaseForm(Propel|Doctrine) pour ajouter ce comportement à tous vos formulaires.
Conclusion
Le découplage important des différents composants des sfForm rends ce genre de tache à priori simple plutôt compliquée, et cette solution nécessite une assez bonne connaissance du fonctionnement interne de ce framework. Mais en contrepartie, ça nous permet de gérer des choses plus complexes assez facilement.


Commentaires
Tu vas te faire gronder par Fabien, il a toujours refusé de passer les validateurs dans le constructeur (pour info c'est moi qui ait commité le passage des widgets, j'en ai entendu parler longtemps ^^)
@NiKo: je sais bien :) Mais en même temps, il n'y a pas à ma connaissance de solution "officielle" à ce genre de cas
Très bon billet !
Juste une question : Comment surcharger dans le setup() de BaseForm tous les formulaires (la syntaxe si possible)
D'avance merci :-)
Comme ça :
public function setup()
{
$this->widgetSchema->addFormFormatter('RequiredFields', new sfWidgetFormSchemaFormatterRequiredFields($this->widgetSchema, $this->validatorSchema));
$this->widgetSchema->setFormFormatterName('RequiredFields');
}
C'est vrai que c'est sympa d'ajouter automatiquement les '*' aux champs obligatoires, mais je pense pas que la vraie solution soit là !
Ce qu'il faut faire selon moi, c'est justement afficher un à un les champs du formulaire dans la vue.
Les labels ne devraient pas être gérés par le modèle ou le contrôleur.
Ningbo Yinzhou Nuoya Cement Block Machine Factory, a professional manufacturer and exporter of all kinds of Single and Multi Spring brick machine,concrete brick machine,block machine,We are a member of Building Block Association with excellent and advanced technology.
http://www.nbnyzj.com