web-dev-qa-db-fra.com

Symfony valide le formulaire avec de faux champs de formulaire mappés

J'ai un formulaire avec des champs supplémentaires ajoutés avec l'option mapped à false. Mais lorsque j'essaie de valider mon formulaire, il ne passe pas et indique "cette valeur n'est pas valide" au-dessus de ces champs de formulaire spécifiques. Cette option n'est-elle pas censée contourner la validation? 

Ces champs de formulaire ne sont utiles que pour renseigner d'autres champs et je n'ai pas besoin de les enregistrer ni même de les vérifier. 

La seule solution que j'ai trouvée consiste à supprimer tous les champs supplémentaires avec js lors d'un clic sur le bouton d'envoi. 

31
kzrdt

Ce message n'est pas à jour avec Symfony 2.3

lire les commentaires ci-dessous

Une nouvelle version arrive!

Validation de champs non mappés dans Form (Symfony 2.1.2)

Il s'agit d'une réponse globale à certaines questions de stackoverflow sur la manière actuelle de valider un champ non lié ou non mappé dans les formulaires.

Le riche écosystème Symfony 2 fait de notre cadre de choix un outil en évolution rapide.
La version Symfony 2.1 apporte de nombreuses déprécations. Cela signifie que ce qui fonctionne avec Symfony 2.0 à 2.1.2 ne fonctionnera plus dans Symfony 2.3 . Pour plus d'informations à ce sujet, lisez UPGRADE DE Symfony 2.0 à 2.1 et lisez les commentaires @deprecated du code Symfony.

Champs non liés

Lors de la création d'un formulaire, vous utilisez généralement des entités et votre validation peut être effectuée dans les réservoirs d'entité eux-mêmes pour les annotations de validation.

namespace Dj\TestBundle\Entity;

use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;

/**    
 * Dj\TestBundle\Entity\Post
 *
 * @ORM\Table()
 * @ORM\Entity(repositoryClass="Dj\TestBundle\Entity\PostRepository")
 */
class Post
{
    // ... some code

    /**
    * @var string $title
    * @ORM\Column(name="title", type="string", length=200, nullable=false)
    * @Assert\NotBlank()
    */
    private $title;

    // .. getters and setters
}

Mais parfois (souvent), vous devez insérer dans votre formulaire des champs qui ne sont pas mappés au modèle.

Notre exemple de modèle est comme ceci:

namespace Dj\TestBundle\Entity;

use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;

/**
 * Dj\TestBundle\Entity\Post
 *
 * @ORM\Table()
 * @ORM\Entity(repositoryClass="Dj\TestBundle\Entity\PostRepository")
 */
class Post
{
    /**
     * @var integer $id
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

    /**ghjkl
     * @var string $title
     * @ORM\Column(name="title", type="string", length=200, nullable=false)
     * @Assert\NotBlank()
     */
    private $title;

    // ... getters and setters
}

Si nous voulons ajouter un champ supplémentaire appelé myExtraField à notre formulaire, nous faisons:

class PostType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder->add('title')
                ->add('myExtraField', 'choice', array(
                        'label' => 'myExtraField option :',
                        'choices' => array(
                            1 => 'Option One',
                            2 => 'Option Wat !'
                        ),
                        'expanded' => true,
                        'mapped' => false
                   ));
    }
    // other methods
}

Remarque :

  • mapped remplace property_path qui sera obsolète dans Symfony 2.3
  • vous pouvez ajouter une valeur sélectionnée par défaut à myExtraField en ajoutant une entrée 'data' => 1 dans votre tableau d'options.

Exemple de code: 

$builder->add('title')
    ->add('myExtraField', 'choice', array(
        'label' => 'myExtraField option :',
        'choices' => array(
            1 => 'Option One',
            2 => 'Option Wat !'
        ),
        'data' => 1, // default selected option
        'expanded' => true,
        'mapped' => false
));

Si vous souhaitez valider le champ myExtraField, vous ne pouvez pas le faire dans les annotations de post-entité, vous devez le faire dans votre formulaire.

Champ de validation non mappé - la méthode Symfony 2.0

La méthode 2.0 consistait à ajouter un validateur au générateur de formulaire ($ builder-> addValidator (..)), mais cette méthode est obsolète!

namespace Dj\TestBundle\Form;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;

// needed namespaces for 2.0 validation
use Symfony\Component\Form\CallbackValidator;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\Form\FormError;

class PostType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        // ... $builder->add()

        // VALIDATING NON MAPPED FIELD Symfony 2.0 way
        /** @var Symfony\Component\Form\CallbackValidator $myExtraFieldValidator **/
        $myExtraFieldValidator = new CallbackValidator(function(FormInterface $form){
          $myExtraField = $form->get('myExtraField')->getData();
            if (empty($myExtraField)) {
              $form['myExtraField']->addError(new FormError("myExtraField must not be empty"));
            }
        });
        // adding the validator to the FormBuilderInterface
        $builder->addValidator($myExtraFieldValidator);
    }
    // ... other methods
}

Ceci valide actuellement le champ myExtraField, BUT $ builder-> addValidator mourra dans Symfony 2.3!

Le code compatible avant

Comme indiqué dans UPGRADE DE Symfony 2.0 à 2.1 , étant donné que FormValidatorInterface est obsolète, nous devons maintenant transmettre notre fonction de fermeture de validation à un écouteur d'événements lié à l'événement FormEvents :: POST_BIND.

Ceci est le code.

namespace Dj\TestBundle\Form;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;

// needed namespaces for 2.1 validation
use Symfony\Component\Form\FormInterface;
use Symfony\Component\Form\FormEvents;
use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormError;

class PostType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        // ... $builder->add()

        // VALIDATING NON MAPPED FIELD Symfony 2.1.2 way (and forward)
        /** @var \closure $myExtraFieldValidator **/
        $myExtraFieldValidator = function(FormEvent $event){
            $form = $event->getForm();
            $myExtraField = $form->get('myExtraField')->getData();
            if (empty($myExtraField)) {
              $form['myExtraField']->addError(new FormError("myExtraField must not be empty"));
            }
        };

        // adding the validator to the FormBuilderInterface
        $builder->addEventListener(FormEvents::POST_BIND, $myExtraFieldValidator);
    }
    // ... other methods
}

Cela peut certainement être amélioré avec l'aide de Sf gurus, mais pour l'instant, il valide le champ de formulaire non lié d'une manière compatible en aval.

J'espère que cela aidera certains d'entre nous.

David

74
David Jacquel

Comme je l'ai mentionné dans une question sur un sujet similaire , depuis Symfony 2.1, vous devez utiliser l'option 'contraintes' pour ajouter une validation à vos champs non mappés:

use Symfony\Component\Validator\Constraints\MinLength;
use Symfony\Component\Validator\Constraints\NotBlank;

$builder
    ->add('firstName', 'text', array(
        'constraints' => new MinLength(3),
    ))
    ->add('lastName', 'text', array(
        'constraints' => array(
            new NotBlank(),
            new MinLength(3),
        ),
    ))
;

J'espère que cela aidera quelqu'un comme moi qui a perdu du temps à ce sujet ...

30
Żabojad

Si vous utilisez déjà avec une contrainte, procédez comme suit:

$builder
    ->add('new', 'repeated', array(
            'type' => 'password',
            'required'          => true,                    
            'invalid_message' => 'crmpicco.status.password_mismatch',
            'constraints'       => array(
                new NotBlank(),
                new Assert\Length([
                    'min'        => 2,
                    'max'        => 50,
                    'minMessage' => 'Your first name must be at least 2  characters long',
                    'maxMessage' => 'Your first name cannot be longer than 2 characters',
                ])
            )
        ))
    ->add('save', 'submit', array(
            'label' => 'password.form.fields.save',
        ))
    ;
5
crmpicco

Ça marche. Vérifié pour symfony 2.1 . Le code devrait être comme ceci:

$builder->add('password', 'password', ['required' => false, 'mapped' => false]);

Bien sûr, la propriété 'requis' n'est pas requise. Exemple tiré de la documentation.