Dans ce billet nous allons voir comment utiliser Ajax pour valider champ par champ un formulaire constuit avec sfForm de Symfony 1.1.
Je prend pour acquis que vous ayez lu / que vous connaissez la validatation de formulaire « classique » offert par sfForm. Tout est expliqué là et surtout là.
En fait le souci avec les validateurs symfony 1.1 est qu’ils ne possèdent pas la méthode isValid() contraitement aux validateurs symfony 1.0. Du coup, quand on fait de l’ajax, nous sommes obligés de passer d’un type de validateur à un autre.
Cette exemple illuste le fait avec le validateur sfValidatorEmail (sf 1.1) et sfEmailValidator (sf 1.0). L’idée est de définir les paramêtres du validateur (les messages d’erreurs dans notre cas) qu’à un seul endroid afin de respecter le concept Dry (Don’t Repeat Yourself).
Voilà les étapes nécessaires pour mettre en place une validation de formulaire classique et « Ajaxé » :
- Vous créez vos widgets dans lib/form/MaClasseForm.class.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
class MaClasseForm extends BaseMaClassForm { public function configure() { $this->setWidgets(array( 'id' => new sfWidgetFormInputHidden(), 'FirstName' => new sfWidgetFormInput(), 'LastName' => new sfWidgetFormInput(), 'Email' => new sfWidgetFormInput(), 'password_repeat' => new sfWidgetFormInput(), 'password' => new sfWidgetFormInput() )); // On peut modifier les labels si besoin est ... $this->widgetSchema->setLabels(array( 'FirstName' => 'Prenom', 'Email' => 'addresse Email ', 'LastName' => 'Nom', )); } }
- Vous définissez vos validateurs dans lib/form/MaClasseForm.class.php à la suite de la méthode configure()
1 2 3 4 5 6 7 8 9 10 11 12 13
$this->setValidators(array( 'id' => new sfValidatorPropelChoice(array('model' => 'Utilisateurs', 'column' => 'id', 'required' => false)), 'FirstName' => new sfValidatorString(array('max_length' => 20, 'required' => false)), 'LastName' => new sfValidatorString(array('max_length' => 20, 'required' => false)), 'password' => new sfValidatorString(array('max_length' => 40, 'required' => false)), 'password_repeat' => new sfValidatorString(array('max_length' => 40, 'required' => false)), 'Email' => new sfValidatorEmail(array('required' => true)), 'Birthday' => new sfValidatorDate(array('required' => false)), )); // J'en profite pour definir un nom formater des champs pour avoir $_POST['utilisateurs['email']] etc $this->widgetSchema->setNameFormat('utilisateurs[%s]');
- Normallement à ce stade vous pouvez utiliser la classe de formulaire dans votre fichier apps/MonApp/MonModule/actions/actions.class.php
1 2 3 4 5 6 7 8 9 10 11 12 13
public function executeMonAction() { $this->formInscription = new MaClasseForm(); if ($this->request->isMethod('post')) { // récupère les champs du formulaire sous forme de tableau. $array_champ = $this->getRequest()->getParameter("utilisateurs"); $this->formInscription->bind($array_champ); if ($this->formInscription->isValid()) { // Formulaire valide. } }
- Voilà la validation « classique » et faite. Et l’ajax dans tout ça ? On y vient ^^ Alors au lieu d’afficher le formulaire de manière classique (via le template adéquate apps/MonApp/MonModule/templates/MonActionSuccess.php)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
// Au lieu de echo $form; // On va rendre le template comme on le souhaite // Par souci de flemme je ne fait que le champ Email <table> <tr> <td><?php echo $form['Email ']->renderLabel() ?>:</td> <td><?php echo $form['Email '] ?></td> <td><span id="error_for_email "> <?php if ($form['Email ']->hasError()): ?> <ul class="error_list"> <?php foreach ($form['Email ']-<getError() as $error): ?> <li class="error_for"><?php echo $error ?></li> <?php endforeach; ?> </ul> <?php endif; ?> </span></td> </tr> </table>
- Et maintenant on va jouer avec l’ajax pour vérifier ce champ email lors de la saisie.
1 2 3 4 5 6 7 8 9 10
/************** Ajax Time :) *****************/ // Dans le template on met : <?php // Crée l'observateur pour le champ utilisateurs_email du formulaire. echo observe_field("utilisateurs_email",array( 'update' => "error_for_email", 'url' => "MonModule/VerifierEmail", 'with' => "'email='+ value", )); ?>
- On rajoute l’action VerifierEmail() dans le fichier d’actions.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
public function executeVerifierEmail() { // Initialisation des variables internes $chaine_a_verifier = $this->getRequestParameter("email"); $array_erreur = array(); // Récupère le validateur d'email définit dans lib/form/MaClasseForm.class.php $form = new MaClasseForm(); $validateur_form = $form->getValidatorSchema(); $all_validateurs_field = $validateur_form->getFields(); $email = $all_validateurs_field["email"]; // Récupere le bon code d'erreur if($chaine_a_verifier == "") { $array_erreur = array('email_error' => $email->getMessage("required")); } else { $array_erreur = array('email_error' => $email->getMessage("invalid")); } // Crée un validateur d'email hérité de Symfony 1.0 $validateur_email = new sfEmailValidator($this->getContext()); // Un peu de Dry (Don't Repeat Yourself) afin d'éviter d'avoir des messages d'erreurs définit à deux endroits différents. $validateur_email->initialize($this->getContext(), $array_erreur ); // Dispatcheur vers le bon templates if($validateur_email->execute($chaine_a_verifier,$message_retour)) { $message_a_afficher = $this->getPartial("ajax_error",array("message"=>$message_retour,"reussi"=>true)); } else { $message_a_afficher = $this->getPartial("ajax_error",array("message"=>$message_retour,"reussi"=>false)); } return $this->renderText($message_a_afficher); }
- Donc en fait on met à jour le « span » error_for_email avec le résultat de l’appel de la méthode VerifierEmail(). J’ai utilisé un template partial car le but est de le réutiliser pour tous les appels en Ajax. Celui ci n’est pas bien compliqué
1 2 3 4
<ul> <li class="<?php if($reussi) echo "accept_for"; else echo "error_for"; ?>">&nbsp;<?php echo $message; ?> </li> </ul>
- Et voilà, le formulaire fonctionne classiquement et dispose de vérifications en Ajax aussi.
Nous venons de voir le validateur d’Email, mais tous fonctionnent sur le même principe. Voici la méthode pour utiliser le validateur de Sting qui diffère un peu.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | public function executeVerifierPseudo() { // Initialisation des variables internes $chaine_a_verifier = trim($this->getRequestParameter("pseudo")); // Récupère le validateur de pseudo $form = new MaClasseForm(); $validateur_form = $form->getValidatorSchema(); $all_validateurs_field = $validateur_form->getFields(); $validateurs = $all_validateurs_field["FirstName"]; $pseudo = $validateurs->getValidators(); $pseudo = $pseudo[0]; // Crée un validateur de String sf1.0 $validateur_pseudo = new sfStringValidator($this->getContext()); $validateur_pseudo->initialize($this->getContext(), array( 'min' => $pseudo->getOption("min_length"), 'min_error' => $pseudo->getMessage("min_length"), 'max' =>$pseudo->getOption("max_length"), 'max_error' => $pseudo->getMessage("max_length"), 'required' => $pseudo->getMessage("required"), )); // Dispatcheur vers le bon templates if($validateur_pseudo->execute($chaine_a_verifier,$message_retour) && $chaine_a_verifier != "") { $message_a_afficher = $this->getPartial("ajax_error",array("message"=>$message_retour,"reussi"=>$bool)); } else { if($chaine_a_verifier == "") $test = $pseudo->getMessage("required"); // Remplace les jokers des messages d'erreurs. $min = $pseudo->getOption("min_length"); $max = $pseudo->getOption("max_length"); $message_retour= preg_replace("#%value%#",$chaine_a_verifier,$message_retour); $message_retour= preg_replace("#%min_length%#",$min,$message_retour); $message_retour= preg_replace("#%max_length%#",$max,$message_retour); $message_a_afficher = $this->getPartial("ajax_error",array("message"=>$message_retour,"reussi"=>false)); } return $this->renderText($message_a_afficher); } |
Et voilà c’est fini :)
Tags : ajax, php, formulaire, framework, Symfony