Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
701 views
in Technique[技术] by (71.8m points)

validation - Symfony validate form with mapped false form fields

I've got a form with extra fields added with the option mapped to false. But when I try to validate my form, it won't pass indicating "this value is not valid" above these specific form fields. Isn't this option supposed to bypass validation?

These form fields are only useful for populate other fields and I don't need to save or even check them.

The only solution I found is to remove all extra fields with js on a submit button click.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

This post is not up to date with Symfony 2.3

read comments bellow

A new version is comming !

Validating non mapped fields in Form (Symfony 2.1.2)

This is a global response for some stackoverflow questions about current way to validate unbounded or non mapped field in forms.

The rich Symfony 2 ecosystem makes our framework of choice a fast evolving tool.
Symfony 2.1 version brings a lot of deprecations. This means that what is working with Symfony 2.0 to 2.1.2 will no longer work in Symfony 2.3. For more information about this, read UPGRADE FROM Symfony 2.0 to 2.1 and read @deprecated comments in Symfony code.

Unbound fields

When building a form, you usually use Entities, and your validation can be made in the Entity itself tanks to Validation annotations.

namespace DjTestBundleEntity;

use DoctrineORMMapping as ORM;
use SymfonyComponentValidatorConstraints as Assert;

/**    
 * DjTestBundleEntityPost
 *
 * @ORMTable()
 * @ORMEntity(repositoryClass="DjTestBundleEntityPostRepository")
 */
class Post
{
    // ... some code

    /**
    * @var string $title
    * @ORMColumn(name="title", type="string", length=200, nullable=false)
    * @AssertNotBlank()
    */
    private $title;

    // .. getters and setters
}

But sometimes (often) you need to insert some fields in your form that are not mapped to the model.

Our model example is like this :

namespace DjTestBundleEntity;

use DoctrineORMMapping as ORM;
use SymfonyComponentValidatorConstraints as Assert;

/**
 * DjTestBundleEntityPost
 *
 * @ORMTable()
 * @ORMEntity(repositoryClass="DjTestBundleEntityPostRepository")
 */
class Post
{
    /**
     * @var integer $id
     *
     * @ORMColumn(name="id", type="integer")
     * @ORMId
     * @ORMGeneratedValue(strategy="AUTO")
     */
    private $id;

    /**ghjkl
     * @var string $title
     * @ORMColumn(name="title", type="string", length=200, nullable=false)
     * @AssertNotBlank()
     */
    private $title;

    // ... getters and setters
}

If we want to add an extra field called myExtraField to our Form we do :

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
}

Note :

  • mapped replaces property_path that will be deprecated in Symfony 2.3
  • you can add a default selected value to myExtraField by adding a 'data' => 1 entry in your options array.

Example 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
));

If you want to validate myExtraField field you can't do it in the Post Entity annotations, you have to do it in your form.

Validation non mapped field - the Symfony 2.0 way

The 2.0 way was to add a validator to the form builder ($builder->addValidator(..)), but this method is deprecated !

namespace DjTestBundleForm;

use SymfonyComponentFormAbstractType;
use SymfonyComponentFormFormBuilderInterface;
use SymfonyComponentOptionsResolverOptionsResolverInterface;

// needed namespaces for 2.0 validation
use SymfonyComponentFormCallbackValidator;
use SymfonyComponentFormFormInterface;
use SymfonyComponentFormFormError;

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

        // VALIDATING NON MAPPED FIELD Symfony 2.0 way
        /** @var SymfonyComponentFormCallbackValidator $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
}

This is currently validating the myExtraField field, BUT $builder->addValidator will die in Symfony 2.3 !

The Forward Compatible code

As stated in UPGRADE FROM Symfony 2.0 to 2.1, as the FormValidatorInterface is deprecated, we now have to pass our validation closure function to an event listener bound to FormEvents::POST_BIND event.

This is the code.

namespace DjTestBundleForm;

use SymfonyComponentFormAbstractType;
use SymfonyComponentFormFormBuilderInterface;
use SymfonyComponentOptionsResolverOptionsResolverInterface;

// needed namespaces for 2.1 validation
use SymfonyComponentFormFormInterface;
use SymfonyComponentFormFormEvents;
use SymfonyComponentFormFormEvent;
use SymfonyComponentFormFormError;

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
}

This can certainly be improved with some Sf gurus help, but for now it's validates unbound form field in a forward compatible way.

Hope that helps unstuck some of us.

David


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...