Custom validator sous symfony 1.2
By eNk` on Thursday, May 7 2009, 09:25 - Symfony - Permalink
Dans ce billet nous allons voir comment créer un sfValidator custom utilisable avec le framework de formulaire.
Dans cet exemple nous allons créer un validateur permettant de vérifier si un pseudo est déjà existant dans la base de données. Ce validateur pourra par exemple être utilisé sur un formulaire d'inscription afin de forcer les utilisateurs à choisir un pseudo qui n'existe pas encore.
Commençons par créer une classe PseudoValidator qui hérite de sfValidatorBase, dans laquelle nous allons redéfinir les méthodes configure() et doClean(). La méthode configure() va permettre de définir les options et les messages de notre validateur. La méthode doClean() va quand à elle être utilisée pour valider la valeur du champ.Vous pouvez par exemple créer cette classe dans le répertoire _my_project_/lib/validator.
class PseudoValidator extends sfValidatorBase
{
public function configure($options = array(), $messages = array())
{
// @todo ajout d'options et de messages
}
public function doClean($value)
{
// @todo validation de la valeur du champs $value
}
}
Ajoutons maintenant le code nécessaire dans nos deux méthodes afin de valider le champ et de définir le message qui sera affiché en cas d'échec de la validation.
Dans un premier temps nous allons définir un message "invalid" dans la méthode configure(). Ensuite dans la méthode doClean() nous allons utiliser une méthode permettant de vérifier si le pseudo existe ou non en base. Dans le cas où le pseudo existe, la valeur du champ n'est donc pas valide, et nous allons lancer une exception de type sfValidatorError avec le message "invalid". Si le pseudo n'existe pas en base il n'y a rien de spécial faire, la méthode doClean() retourne la valeur.
class PseudoValidator extends sfValidatorBase
{
public function configure($options = array(), $messages = array())
{
$this->setMessage('invalid', 'Le pseudo "%pseudo%" est déjà utilisé.');
}
public function doClean($value)
{
// Dans une classe de votre modèle, créez une méthode permettant de savoir si le pseudo $value existe en base.
// Pour l'exemple je suppose que checkPseudo() retourne un booléen.
$exist = YourClass::checkPseudo($value);
if($exist)
{
throw new sfValidatorError($this, 'invalid', array('pseudo' => $value));
}
return $value;
}
}
Pour aller un peu plus loin dans l'exemple nous allons ajouter deux options à notre validateur, "trim" et "min_length", cette dernière sera une option obligatoire.
class PseudoValidator extends sfValidatorBase
{
public function configure($options = array(), $messages = array())
{
$this->addOption('trim');
$this->addRequiredOption('min_length');
$this->addMessage('min_length_msg', 'Au moins %min% caractères.'); // message par défaut
$this->setMessage('invalid', 'Le pseudo "%pseudo%" est déjà utilisé.');
}
public function doClean($value)
{
if($this->hasOption('trim') && $this->getOption('trim'))
{
$value = trim($value);
}
if($this->hasOption('min_length') && $this->getOption('min_length') > strlen($value))
{
throw new sfValidatorError($this, 'min_length_msg', array('min' => $this->getOption('min_length')));
}
$exist = YourClass::checkPseudo($value);
if($exist)
{
throw new sfValidatorError($this, 'invalid', array('pseudo' => $value));
}
return $value;
}
}
Pour utiliser notre validateur, rien de plus simple, un petit symfony cc pour réinitialiser l'autoloading et il suffit d'associer le validateur au champ.
$myFormObject->setValidator('my_field', new PseudoValidator(array('min_length' => 4, 'trim' => true), array('min_length_msg' => "Le pseudo doit contenir au moins %min% caractères.")));
Comments
On comprendra que pour l'exemple tu définisses toutes les étapes, mais il convient de rappeler qu'en pratique on préfèrera faire hériter le validateur de la classe "sfValidatorInput", permettant d'avoir toutes les options de validation d'un input text standard ;)
Tu as tout à fait raison je part la classe sfValidatorBase pour l'exemple, simplement pour montrer comment se construit un validateur à partir de la classe qui est la base de tous les validateurs.
Dans ce cas il est vrai qu'il serait bien vu de partir de la classe sfValidatorString étant donné que l'élément à valider est un champ de texte classique.
Bonjour,
Je débute sous symfony et je cherche par ci par la des infos et je suis tombé sur votre site.
L'astuce est très utile mais je voulais savor si il est pas plus simple d'utiliser :
... new sfValidatorPropelUnique(array('model' => 'user', 'column' => 'username'), array('invalid' => 'Ce pseudo est déja utilisé. Veuillez en choisir un auutre.'))
pour vérifier l'unicité du pseudo dans la table?
En effet l'utilisation d'un sfValidatorPropelUnique dans ce cas est plus simple que la construction d'un nouveau validateur. Mais comme je l'ai indiqué dans mon commentaire précédent mon idée ici est de montrer comment se construit un validateur.
Bonjour,
Partant de votre exemple, j'essaie de faire mon formulaire de login, mais j'ai du mal sur la fionction YourClass::checkEmail.
Dans UserPeer, j'ai la fonction:
public static function checkEmail($email)
{
$c = new Criteria();
$c->add(self::EMAIL, $email);
return self::doSelectOne($c);
}
et dans la fonction doClean:
if ($user = UserPeer::checkEmail($values['email']))
{
$userPassword = $user->getPassword();
if (MD5($values['password']) = $userPassword())
....
Mais ca ne fonctionne pas.
Tu pourrai snous eclairer sur le contenu à mettre dans la fonction checkPseudo, s'il te plait?
Merci
Bonjour, et désolé pour cette réponse un peu tardive =).
Je ne pense pas que le problème vienne de ta méthode checkEmail(), mais plutôt de la méthode doClean() du validateur.
En effet dans le cas où checkEmail() retourne bien un utilisateur tu contrôle le password, ça ok, mais que fais tu dans le cas où checkEmail() ne retourne pas d'utilisateur ou si le test sur le password est faux ?
La méthode doClean() d'un validateur est utiliser pour contrôler la validité de la valeur d'un champ, dans le cas où cette valeur n'est pas correcte il faut lever une exception de type sfValidatorError. Donc dans ton cas je pense qu'il faudrait que tu ai quelque chose comme ça:
if ($user = UserPeer::checkEmail($values['email']))
{
$userPassword = $user->getPassword();
if (MD5($values['password']) != $userPassword()) { throw new sfValidatorError(...); }
}
else
{
throw new sfValidatorError(...);
}
Tu peut aussi regarder cette page de la doc qui je pense correspond bien à ce que tu souhaite faire:
http://www.symfony-project.org/cook...
<A href="http://www.toptoys2trade.com/zhu-zh... ">zhu zhu pets</A>
<a href="http://www.toptoys2trade.com/a-sill... "> silly bandz</a>
<A href="http://www.toptoys2trade.com/power-... "> power balance</A>
<A href="http://www.toptoys2trade.com/animal... ">animal rubber bands</A>
<A href="http://www.toptoys2trade.com/baby-c... ">Baby Carriers</A>
<A href="http://www.toptoys2trade.com/pillow... ">Pillow Pets</A>
<A href="http://www.toptoys2trade.com/plush-... ">Plush Pencil Case</A>
<A href="http://www.golf-equipment2u.com ">golf equipments</A>