Symfony Formulaires.

Slides:



Advertisements
Présentations similaires
PHP5 its a kind of magic. Chargement automatique function __autoload( $nom_classe ) { require_once('obj/'.$nom_classe.'.class.php'); } si on exécute le.
Advertisements

Logique approchée Michel de Rougemont Université Paris II VERA: CORRECT:
LE PRESENT ER VERBS JE TU IL/ELLE ON NOUS VOUS ILS/ELLES
Les Phrases avec Si Français 1442 Leçon Do you remember how to make le Conditionnel? Step One? (pick your verb) Step Two? (Leave it as IS unless.
QCA Unit 16 – Scène de Plage (part 3a – extended sentences) Jo Rhys-Jones - Kingswear Primary School 2008.
Mercredi – le 13 décembre 1A) À quelle heure est-ce que tu prends... (prõh) 1) le petit déjeuner? (puh tee day jzhuh nay) 2) le déjeuner ? (day jzhuh nay)
Jeudi, dix-huit novembre Le rechauffement de la terre.
OTB Analog module: Input configuration with TSX PREMIUM (TSXCPP110)
THE SUBJUNCTIVE How do you use it???. How do we form the subjunctive? add a que find the subject find the ils form of the verb add in the endings: e ions.
La formation des questions Reflect a bit… Reflect a bit… Pourquoi est-il important de poser les questions? Pourquoi est-il important de poser les questions?
Les objets de la classe.
Le Superlatif des Adjectifs
Personal Home Page / Hypertext Processor (PHP)
Symfony generators. contexte Répétition de limplémentation des méthodes CRUD pour ls objets métier Commande symfony permettant dinitialiser un module.
Symfony en action I M V Controleur.
Symfony Un projet français 1 ère version octobre 2005 Fabien Potencier PDG de sensio Lab développeur François Zanonitto écrit.
PHP5 its a kind of magic. Chargement automatique function __autoload( $nom_classe ) { require_once('obj/'.$nom_classe.'.class.php'); } si on exécute le.
11:37:32 Programmation Web PHP5 objet "avancé" Jérôme CUTRONA
Procédure dappel Appeal process 1(c) RISS / IJHS, 2012.
Injection de dépendances
Javascript les spécificités du langage - Partie 7 -
Cours n°3 Les formulaires
Spring MVC Cedric Dumoulin.
BlueJ_XI 1 Java, les objets : tout de suite ! Gestion des erreurs : les exceptions Notes de cours associées au chapitre 11 tutorial BlueJ
10 Copyright © Oracle Corporation, Tous droits réservés. Autres concepts relatifs aux déclencheurs.
La Famille An introduction to family vocabulary in French, using a family that I think you’ll be familiar with…
Le langage PHP 5.
How to solve biological problems with math Mars 2012.
Laurent Capelli Solution anti SPAM : Codage adresse mail Comment se protéger des robots chercheurs d'adresse mail éviter les chaînes du type «
Objets Javascript Mécanismes internes Le concept et la construction dobjets
Le PHP – la base Les commentaires */ ?>. Le PHP – le terminateur dinstruction Le point virgule Le point virgule est utilisé pour terminer une"; echo instruction.
Magnets fiche projet / project sheet IAFACTORY THE MAGNETIC FACTORY magnets. IAFACTORY | conseil en architecture de linformation | |
TortoiseSVN N°. Subversion : pour quoi faire ? Avoir un espace de stockage commun – Tous les étudiants du SIGLIS ont un espace svn commun Partager vos.
Master 1 SIGLIS java Lecteur Stéphane Tallard Chapitre 4 – Structures de contrôle.
Quelques notes sur CORBA F. Boyer, Oct Principes Programmation distribuée Multi-plateformes Notion de client et de serveur Notion de stub et de.
IAFACTORY | conseil en architecture de linformation | | |
Le langage Javascript pour le web
JUnit Présentation complète de JUnit et « guide d’utilisation » en 13 transparents.
Le verbe FAIRE au présent
Le verbe PRENDRE au présent to take. When the verb PRENDRE is conjugated, it looks like this: Je prends – I take, I am taking Tu prends – you take, you.
1 PHP 1.Langage PHP 1.1. Types de base, variables et constantes 1.2. Opérateurs et expressions 1.3. Instructions 1.4. Fonctions 2.Accès aux bases de données:
AJAX.
CSI1502 Principes fondamentaux en conception des logiciels Chapter 8: Gestion des exceptions.
BlueJ_VI 1 Java, les objets : tout de suite ! Test, assertions, « vérification statique » Notes de cours associées au chapitre 6 Avec des assertions, utilisation.
Le verbe “Être” “être” ou “ne pas être” ça c’est la question.
Jeudi 14 octobre Les objectifs: 1.Be confident in looking nouns up in a dictionary 2.The / a.
Michel Coletta - Journées PATTERNS Avril Grenoble1 STRUTS Introduction Technologies Java Architecture Développement Enseigner quoi ?
1111 Gestion des exceptions Objectifs À la fin de ce cours, vous serez capables de : • Expliquer les concepts de base de la gestion des exceptions.
LE PASSÉ COMPOSÉ Bonjour!.
1 PtiLoo Compléments de Cours pour réaliser les Extensions version 20/08/ :51 Ajout à faire pour version 20/08/ :51 n "animation" pour.
Utilisation avancée.
Le passé composé …avec avoir et être
Objectifs À la fin de ce cours, vous serez capables de :
© 1 Taglibs Applications Struts Taglibs. © 2 Applications Struts Les Tags Libraries Struts Bean : Accès aux JavaBean, aux ressources Html : Gestion des.
Packages et Types De la Spécification Formelle A l'implémentation Ada.
PHP5 objet "avancé" Jérôme CUTRONA 09:56:48 Programmation Web
Quel est l’objectif selon toi ?. On the train ticket I gave you highlight: 1. the name of the French train company 2. the number of people who can travel.
AJAX Jérôme CUTRONA 06:28:58 Programmation Web
Pthread Ordonnancement. #define _MULTI_THREADED #include #ifndef _CHECK_H #define _CHECK_H /* headers used by a majority of the example program */ #include.
Conception de Site Webs Interactifs Cours 7 Patrick Reuter
Google voice assignment major assessment Qu’est-ce que je fais tous les jours?
CPI/BTS 2 Programmation Web Fonctions & Includes Prog Web CPI/BTS2 – M. Dravet – 02/11/2003 Dernière modification: 02/11/2003.
Bases de données Singleton pour la connexion
Nicolas Ribot Introduction aux triggers Nicolas Ribot - Licence GNU FDL - Version 1.1.
Présentation du nouveau Site Hercules. Plan Nouvelle ergonomie Nouvelle base de données Nouvelle procédure d’inscription Nouveaux outils d’administration.
1 Après 4 séances ● Ipn1 ipn2 ipn3 ipn4 ipn5 ipn6 ipn7 ipn8 ipn9 ● Hello OK- X OK- OK OK- X OK- OK ● Image OK X X OK-- X OK X X ● Shapes ● TpQt ● DrawQT.
5.
5.
votre événement New Year,
Vide.
Transcription de la présentation:

symfony Formulaires

Helper formulaire Fermé par </form> Éviter les <?php echo dans les balises input, etc … <?php echo form_tag('test/save') ?>  <form method="post" action="/path/to/save"> <?php echo form_tag('test/save', array( 'method’ => ‘get’, ‘multipart’ => ‘true’, ‘class’ => ‘simpleForm‘ ) ?>  <form method="get" enctype="multipart/form-data" class="simpleForm"action="/path/to/save"> Fermé par </form>

Helper champs de formulaire texte tout les champs et contrôles ont un attribut id déduit de l'attribut name <?php echo input_tag('nom', default') ?>  <input type="text" name="nom" id="nom" value="default" /> <?php echo textarea_tag('nom', 'default', array( 'size’ => ’10x20‘ ) ) ?>  <textarea name="nom" id="nom" cols="10" rows="20"> default </textarea>

Helper champs de formulaire choix <?php echo checkbox_tag('celibataire', 1, true) ?> <?php echo checkbox_tag('permisdeconduire', 'B', false) ?> <input type="checkbox" name="celibataire" id="celibataire" value="1"checked="checked" /> <input type="checkbox" name="permisdeconduire" id="permisdeconduire"value="B" /> <?php echo radiobutton_tag('status[]', 'value1', true) ?> <?php echo radiobutton_tag('status[]', 'value2', false) ?> <input type="radio" name="status[]" id="status_value1" value="value1"checked="checked" /> <input type="radio" name="status[]" id="status_value2" value="value2" />

Helper champs de formulaire sélection – syntaxe la plus élégante <?php echo select_tag('payment', options_for_select( array( 'Visa' => 'Visa', 'Eurocard' => 'Eurocard', 'Mastercard' => 'Mastercard‘ ), array('Visa', 'Mastercard') ), array('multiple' => true) ) ?>  <select name="payment" id="payment" multiple="multiple"> <option value="Visa" selected="selected">Visa</option> <option value="Eurocard">Eurocard</option> <option value="Mastercard">Mastercard</option> </select>

Helper champs de formulaire autres <?php echo input_file_tag('nom') ?>  <input type="file" name="nom" id="nom" value="" /> <?php echo input_password_tag('nom', 'valeur') ?>  <input type="password" name="nom" id="nom" value="valeur" /> <?php echo input_hidden_tag('nom', 'valeur') ?>  <input type="hidden" name="nom" id="nom" value="valeur" />

Helper champs de formulaire soumission <?php echo submit_tag('Sauvegarder') ?>  <input type="submit" name="submit" value="Sauvegarder" /> <?php echo submit_image_tag('submit_img') ?>  <input type="image" name="submit" src="/images/submit_img.png" /> helper submit_image_tag() même syntaxe helper image_tag().

Gestion de la soumission mymodule/templates/editAuthorSuccess.php Bonne pratique : utiliser la même action pour afficher et gérer le formulaire. <?php echo form_tag('mymodule/editAuthor') ?> </form> mymodule/actions/actions.class.php public function executeEditAuthor() { if ($this->getRequest()->getMethod() != sfRequest::POST) { // Affichage du Formulaire return sfView::SUCCESS; } else { // Management de la soumission du formulaire $name = $this->getRequestParameter('name'); ... $this->redirect('mymodule/anotheraction'); }

Gadget date poor   <?php echo input_date_tag('datedenaissance', '2005-05-01‘)?> <?php echo select_day_tag('day', 1, array('include_custom’ => ‘Choose a day‘)) ?> <select name="day" id="day"> <option value="">Choose a day</option> <option value="1" selected="selected">01</option> <option value="2">02</option> ... <option value="31">31</option> </select> <?php echo select_month_tag('month', 1, 'include_custom=Choose a month use_short_month=true') ?> <?php echo select_year_tag('year', 2007, 'include_custom=Choose a year year_end=2010') ?>

Gadget date rich  <?php echo input_date_tag('datedenaissance', '2005-05-03', array('rich’ => ’true') ?>

Gadget date valeur par défaut dates reconnues par la fonction PHP strtotime() <?php echo input_date_tag('test', '2006-04-01', 'rich=true') ?> <?php echo input_date_tag('test', 1143884373, 'rich=true') ?> <?php echo input_date_tag('test', 'now', 'rich=true') ?> <?php echo input_date_tag('test', '23 October 2005', 'rich=true') ?> <?php echo input_date_tag('test', 'next tuesday', 'rich=true') ?> <?php echo input_date_tag('test', '1 week 2 days 4 hours 2 seconds', 'rich=true') ?> Aucune valeur par défaut <?php echo input_date_tag('test', ‘ ', 'rich=true') ?> Les Formats de date autre qu’anglais ne fonctionnent pas (14/12/2008)

Rich text TinyMce http://tinymce.moxiecode.com/ tinymce/jscripts/tiny_mce/ => web/js/ settings.yml all: .settings: rich_text_js_dir: js/tiny_mce <?php echo textarea_tag('name', 'default content', Array( 'rich’ => true, ‘size’ => ‘10x20’, ‘tinymce_options’ => ‘language:"fr",theme_advanced_buttons2:"separator"‘ ) ) ?>

Rich text Fck http://fckeditor.com/ fkceditor/ => web/js/ Myproject/apps/myapp/config/settings.yml all: .settings: rich_text_fck_js_dir: js/fckeditor <?php echo textarea_tag('name', 'default content', Array( 'rich’ => ‘fck, ‘size’ => ‘10x20’, ) ) ?>

Sélecteur de Pays et de Langage <?php echo select_country_tag('pays', 'AL') ?>  <select name="pays" id="pays"> <option value="AF">Afghanistan</option> <option value="AL" selected="selected">Albania</option> <option value="DZ">Algeria</option> <option value="AS">American Samoa</option> … <?php echo select_language_tag('langue', 'en') ?>  <select name="langue" id="langue"> <option value="elx">Elamite</option> <option value="en" selected="selected">English</option> <option value="enm">English, Middle (1100-1500)</option> <option value="ang">English, Old (ca.450-1100)</option> <option value="myv">Erzya</option> <option value="eo">Esperanto</option>

Helper formulaire pour objet <?php echo input_tag('telephone', $customer->getTelephone()) ?> <?php echo object_input_tag($client, 'getTelephone') ?> <input type="text" name="telephone" id="telephone" value="0123456789" />

Helper formulaire pour objet object_input_tag($object, $method, $options) object_input_date_tag($object, $method, $options) object_input_hidden_tag($object, $method, $options) object_textarea_tag($object, $method, $options) object_checkbox_tag($object, $method, $options) object_select_tag($object, $method, $options) object_select_country_tag($object, $method, $options) object_select_language_tag($object, $method, $options) object_password_tag() n’existe pas car ce n’est pas une bonne idée d’initialiser un mot de passe avec quelque chose de saisi par l’utilisateur

Peupler une liste déroulante avec des objets <?php echo options_for_select(array( '1' => 'Steve', '2' => 'Bob', '3' => 'Albert', '4' => 'Ian', '5' => 'Buck' ), 4) ?>  <option value="1">Steve</option> <option value="2">Bob</option> <option value="3">Albert</option> <option value="4" selected="selected">Ian</option> <option value="5">Buck</option>

Code contrôleur typique Dans l’action $options = array(); foreach ($authors as $author) { $options[$author->getId()] = $author->getName(); } $this->options = $options;   Dans le template <?php echo options_for_select($options, 4) ?> MIEUX! <?php echo objects_for_select($authors, 'getId', 'getName', 4) ?>

Peupler une liste déroulante à base d’une clé étrangère <?php echo select_tag('author_id', objects_for_select( AuthorPeer::doSelect(new Criteria()), 'getId', '__toString', $article->getAuthorId() )) ?> MIEUX! <?php echo object_select_tag($article, 'getAuthorId') ?> Le helper devine à partir de la méthode passée en paramètre le nom de la classe peer associée AuthorPeer le nom de la méthode peer à utiliser doSelect(new Criteria) La méthode à utiliser sur chaque objet de la liste __toString() si elle existe ou la clé primaire sinon

Peupler une liste déroulante à base d’une clé étrangère – version explicite Spécifier la classe peer utilisée pour retrouver les valeurs <?php echo object_select_tag($article, 'getAuthorId', 'related_class=Foobar')?> Spécifier la méthode peer utilisée pour retrouver les valeurs <?php echo object_select_tag($article, 'getAuthorId','peer_method=getMostFamousAuthors') ?> Ajouter un item blanc en début de liste <?php echo object_select_tag($article, 'getAuthorId', 'include_blank=true') ?> Ajouter un item personnalisé en début de liste <?php echo object_select_tag($article, 'getAuthorId', 'include_custom=Choose an author') ?> Les options de ce helper sont combinables en utilisant un tableau d’options

Validation de formulaire Formulaire typique <?php echo form_tag('contact/send') ?> Name: <?php echo input_tag('name') ?><br /> Email: <?php echo input_tag('email') ?><br /> Age: <?php echo input_tag('age') ?><br /> Message: <?php echo textarea_tag('message') ?><br /> <?php echo submit_tag() ?> </form> name est obligatoire et est un texte entre 2 et 100 caractères. email est obligatoire et est un texte entre 2 et 100 caractères, et doit être valide age est obligatoire et doit être un entier entre 0 et 120 message est obligatoire

Les validateurs Symfony met à disposition des validateurs usuels Un validateur possède une méthode execute() Prend une valeur de champ en paramètre Retourne vrai si la valeur est valide, false sinon Emploi de sfStringValidator pour les deux premiers champs Il vérifie que la taille d’un string est compris dans l’intervalle défini lors de l’appel de la méthode initialize()

modules/contact/action/actions.class.php public function validateSend() { $name = $this->getRequestParameter('name');   if (!$name) { $this->getRequest()->setError('name', 'The name field cannot be left blank');   return false; } characters $myValidator = new sfStringValidator(); $myValidator->initialize($this->getContext(), array( 'min' => 2, 'min_error' => 'This name is too short (2 characters minimum)', 'max' => 100, 'max_error' => 'This name is too long. (100 characters maximum)', )); if (!$myValidator->execute($name, $error)) }   return true;

Processus de validation Si l’utilisateur rentre une valeur incorrecte la méthode execute de sfStringValidator retournera false L’action validateSend échouera La méthode handleErrorSend sera appelée au lieu de la méthode executeSend() La classe sfRequest met à disposition une méthode setError(), et une méthode hasError() pour afficher des messages d’erreurs précis C’est le rôle que jouent les paramètres min_error max_error

Fichier de validation modules/contact/validate/send.yml fields name: required: msg: The name field cannot be left blank sfStringValidator: min: 2 min_error: This name is too short (2 characters minimum) max: 100 max_error: This name is too long. (100 characters maximum) Toutes les validations sont effectuées Tous les messages d’erreur seront affichés La validation globale échoue si au moins une validation de champs échoue La méthode validateXXX() sera ensuite exécutée si elle existe Les fichiers de validations sont stockés dans le répertoire validate/ du module et sont nommés nomAction.yml

Réafficher le formulaire En cas déchec handleErrorSend() est exécutée si elle existe Sinon le template sendError.php est affiché Habituellement si la validation echoue on souhaite réafficher le formulaire Redéfinir handleErrorSend() en la redirigeant vers l’affichage du formulaire

modules/contact/actions/actions.class.php class ContactActions extends sfActions { public function handleErrorSend() $this->forward('contact', ‘displayForm'); }   public function executeSend() // traitement du formulaire } Si c’est la même action qui affiche le formulaire et qui le traite handleErrorSend() n’a qu’à renvoyer sfView::SUCCESS pour réafficher sendSuccess.php

Code typique de gestion d’un formulaire avec symfony class ContactActions extends sfActions { public function executeSend() if ($this->getRequest()->getMethod() != sfRequest::POST) // Prepare data for the template, should be shared return sfView::SUCCESS; } else // traite le formulaire $this->redirect('mymodule/anotheraction'); public function handleErrorSend()

Afficher les message d’erreurs dans les formulaires <?php if ($sf_request->hasErrors()): ?> <p>valeurs incorrectes:</p> <ul> <?php foreach($sf_request->getErrors() as $name => $error): ?> <li><?php echo $name ?>: <?php echo $error ?></li> <?php endforeach; ?> </ul> <?php endif; ?>

Afficher les message d’erreurs au niveau des champs <?php echo form_tag('contact/send') ?> <?php if ($sf_request->hasError('name')): ?> <?php echo $sf_request->getError('name') ?> <br /> <?php endif; ?> Name: <?php echo input_tag('name') ?><br /> <?php echo submit_tag() ?> </form> Ou via les helpers Validation <?php use_helper('Validation') ?> <?php echo form_tag('contact/send') ?> <?php echo form_error('name') ?><br /> Name: <?php echo input_tag('name') ?><br /> <?php echo submit_tag() ?> </form>

Repeupler le formulaire Peut se faire via $sf_params Simple forward donc la requête est toujours accessible <?php echo input_tag('name', $sf_params->get('name')) ?> Sinon laisser faire symfony validate/send.yml fillin: enabled: true param: name: test # nom du forumlaire s’il y en a plusieurs skip_fields: [email] # champs exclus exclude_types: [hidden, password] # types de champs exclus check_types: [text, checkbox, radio, select, hidden] # champs à repeupler content_type: html # html, xml ou xhtml

Transformation des données repeuplées Pour transformer les données réaffichées Entities, escaping etc … validate/send.yml fillin: enabled: true param: name: test converters: # Converters to apply htmlentities: [first_name, comments] htmlspecialchars: [comments]

Les validateurs symfony sfStringValidator applique des contraintes sur les chaînes de carctères sfStringValidator: values: [foo, bar] values_error: The only accepted values are foo and bar insensitive: false # If true, comparison with values is case insensitive min: 2 min_error: Please enter at least 2 characters max: 100 max_error: Please enter less than 100 characters sfEmailValidator vérifie la validité d’un adresse email sfEmailValidator: strict: true # name@domaine.ext est valide, sinon RFC822 email_error: This email address is invalid

Les validateurs symfony II sfNumberValidator vérifie qu’une entrée est bien un nombre et lui applique des contraintes de taille sfNumberValidator: nan_error: Please enter an integer min: 0 min_error: The value must be at least zero max: 100 max_error: The value must be less than or equal to 100 sfUrlValidator vérifie la validité d’une url sfUrlValidator: url_error: This URL is invalid

Les validateurs symfony III sfRegexValidator vérifie qu’une entrée est conforme ou non à un masque d’expression régulière compatible perl sfRegexValidator: match: No # spécifie que l’entrée doit vérifier le masque (ne doit pas sinon) match_error: Posts containing more than one URL are considered as spam pattern: /http.*http/si sfCompareValidator vérifie que deux entrées sont égales fields: password1: required: msg: Please enter a password password2: msg: Please retype the password sfCompareValidator: check: password1 compare_error: The two passwords do not match

Les validateurs symfony IV sfPropelUniqueValidator vérifie qu’une entrée n’existe pas déjà en bas de données (pratique pour le identifiant unique) fields: nickname: sfPropelUniqueValidator: class: User column: login unique_error: This login already exists. Please choose another one. sfCallbackValidator vérifie que deux entrées sont égales fields: account_number: sfCallbackValidator: callback: is_numeric invalid_error: Please enter a number. credit_card_number: callback: [myTools, validateCreditCard] # doit renvoyer true ou false invalid_error: Please enter a valid credit card number.

Les validateurs symfony V sfFileValidator vérifie qu’un fichier uploadé a le bon type mime et la bonne taille fields: image: file: True required: msg: Please upload an image file sfFileValidator: mime_types: - 'image/jpeg' - 'image/png' - 'image/x-png' - 'image/pjpeg' mime_types_error: Only PNG and JPEG images are allowed max_size: 512000 max_size_error: Max size is 512Kb .

DRY – les validateurs nommés validators: myStringValidator: class: sfStringValidator param: min: 2 min_error: This field is too short (2 characters minimum) max: 100 max_error: This field is too long (100 characters maximum) fields: name: required: msg: The name field cannot be left blank email: msg: The email field cannot be left blank sfEmailValidator: email_error: This email address is invalid

Restriction de validation à la méthode POST ou GET La validation est appelé par défaut pour la méthode POST redéfinissable globalement ou champs par champs methods: [post] fields: email: methods: [post, get] # redéfinit la conf globale required: msg: The email field cannot be left blank sfEmailValidator: email_error: This email address is invalid

Validateur personnalisé Tout validateur hérite de sfValidator Stocké dans un des répertoires lib/ La méthode execute() prend la valeur à valider et le message d’erreur en paramètre La méthode initalize() recoit le singletion context, et les paramètres du fichier YAML en paramètre Elle doit commencer par appeler la méthode initalize de la classe dont elle dérive (sfValidator) Elle définit les paramètres si le ichier YAML n’existe pas Tout validateur peut accéder aux paramètres via $this->getParameterHolder()

Validateur personnalisé code class sfSpamValidator extends sfValidator { public function execute (&$value, &$error) $re = '/'.implode('.*', array_fill(0, $this->getParameter('max_url') + 1, 'http')).'/is';   if (preg_match($re, $value)) $error = $this->getParameter('spam_error'); return false; }   return true; public function initialize ($context, $parameters = null) parent::initialize($context);   $this->setParameter('max_url', 2); $this->setParameter('spam_error', 'This is spam'); $this->getParameterHolder()->add($parameters);   }

Validateur personnalisé utilisation validate/send.yml message: required: msg: The message field cannot be left blank sfSpamValidator: max_url: 3 spam_error: Leave this site immediately, you filthy spammer!

Utilisation de la syntaxe tableau dans les formulaires PHP permet d’utiliser la syntaxe tableau dans les formulaires <label for="story_title">Title:</label> <input type="text" name="story[title]" id="story_title" value="default" /> Incidence sur le fichier de validation fields: story{title}: required: Yes

Exécution d’un validateur sur un champs vide Exemple du changement de mot de passe fields: password1: password2: sfCompareValidator: check: password1 compare_error: passwords mismatch Valide un mot de passe blanc!! fields: password1: group: group_password password2: sfCompareValidator: check: password1 compare_error: passwords mismatch Les tests agissant sur un groupe ne s’applique que si un des champs membre n’est pas vide