Utiliser un Validator dans un Form\Type Symfony2

Vous avez sûrement déjà dû utiliser des fonctions de validation appelées en callback sur vos formulaires (CallbackValidator) pour tester un retour de formulaire et lever une erreur sur un certain champs si la valeur de ce dernier n’est pas valide.

public function buildForm(FormBuilder $builder, array $options)
{
    $builder->add('myfield', 'text');
    $builder->addValidator(new CallbackValidator(function(FormInterface $form) {
    $myfield = $form->get('myfield');
    if ($myfield->getData() != null && !is_string($myfield->getData())) {
        $myfield->addError(new FormError('Invalid format'));
    }
}

Et bien sachez que vous pouvez utiliser dans vos Form/Type des Validator (à l’instar de ceux qu’on peut invoquer en utilisant les Assert dans nos entitées) qui vont pouvoir vous apporter un nombre important d’outils qui vont vous aider à valider vos formulaires.

Tout d’abord, il vous faudra utiliser les namespace de classes suivants :

<?php
namespace Acme\Bundle\AcmeBundle\Form\Type;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilder;
use Symfony\Component\Form\CallbackValidator;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\Form\FormError;
use Symfony\Component\Validator\Constraints\Regex;
use Symfony\Component\Validator\Constraints\RegexValidator;

class FooType extends AbstractType
{
    [...]
}

Les deux derniers sont ceux que nous devons rajouter pour pouvoir utiliser cette contrainte de validation. Ici nous avons choisit la validation de Regex mais vous pouvez utiliser n’importe quel type de contrainte tant qu’elle possède une classe Validator associée. (cf. liste des toutes les contraintes)

Il vous suffira désormais de juste instancier de nouveaux objets dans votre CallbackValidator afin de pouvoir analyser et valider une valeur.

[...]
public function buildForm(FormBuilder $builder, array $options)
{
    $builder->add('myfield', 'text');
    $builder->addValidator(new CallbackValidator(function(FormInterface $form) {
    $myfield = $form->get('myfield');
    if ( ! is_null($myfield->getData()) ) {
        $validator      = new RegexValidator();
        $constraint     = new Regex(array(
            'pattern' => "/^[a-z0-9-]+$/"
        ));
        $isValid = $validator->validate( $myfield->getData(), $constraint );
        if ( ! $isValid ) {
            $myfield->addError( new FormError( "This field is not valid (only alphanumeric characters separated by hyphens)" ) );
        }
    }
}
[...]

Voilà une astuce bien sympathique qui peut vous être utile à valider un champs qui, par exemple, ne figure pas dans les attributs de votre entitée. Exactement comme vous pourriez le faire en utilisant les validations de type Assert.

10 réflexions au sujet de « Utiliser un Validator dans un Form\Type Symfony2 »

  1. Salut,

    Bonne astuce en effet, tu peux aussi l’écrire comme ça pour que ça soit plus lisible:

    public function buildForm(FormBuilder $builder, array $options)
    {
    ….
    $builder->addValidator(new CallbackValidator(array($this, ‘isOk’)));
    }

    public function isOk(FormInterface $form)
    {
    // même chose que ton code
    }

  2. Merci pour ce cas pratique de « post validator » bien utile.
    Il reste malgré tout un détail que je n’arrive pas à résoudre:

    $myfield->addError( new FormError( « This field is not valid (only alphanumeric characters separated by hyphens) » ) );

    Attache l’erreur au formulaire et non au champs myfield.
    Y a t il un moyen d’attacher l’erreur à un champs plutôt qu’au formulaire tout entier?

  3. Ping : A week of symfony #263 (9->15 January 2012) « We are php

  4. J’essaye d’ajouter l’erreur suivante : Please, numbers only au lieux de l’erreur classique des patterns qui est : « Veuillez modifier la valeur pour correspondre au format demandé. »

    Pour ça j’ai fait : ->add(‘size’, ‘text’, array(‘attr’ => array(‘placeholder’ => ‘Living size’,
    ‘pattern’ => ‘\d+’,
    ‘message’ => ‘Please, numbers only’),
    Mais ça ne fonctionne pas.
    Avez vous une idée ?
    Merci :)

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *

*

Vous pouvez utiliser ces balises et attributs HTML : <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>