32

我有一个带有额外字段的表单,其中添加mappedfalse. 但是当我尝试验证我的表单时,它不会在这些特定表单字段上方指示“此值无效”。这个选项不应该绕过验证吗?

这些表单字段仅对填充其他字段有用,我不需要保存甚至检查它们。

我找到的唯一解决方案是在单击提交按钮时使用 js 删除所有额外字段。

4

5 回答 5

74

这篇文章不是最新的 Symfony 2.3

阅读下面的评论

新版本来了!

验证表单中的非映射字段(Symfony 2.1.2)

这是对有关当前验证表单中无界或非映射字段的方法的一些 stackoverflow 问题的全球响应。

丰富的 Symfony 2 生态系统使我们选择的框架成为快速发展的工具。
Symfony 2.1 版本带来了很多弃用。这意味着在 Symfony 2.0 到 2.1.2 中工作的内容将不再在 Symfony 2.3 中工作。有关这方面的更多信息,请阅读从 Symfony 2.0 升级到 2.1并阅读 Symfony 代码中的@deprecated 注释。

未绑定字段

在构建表单时,您通常会使用 Entities,而您的验证可以在 Entity 本身的容器中进行 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
}

但有时(通常)您需要在表单中插入一些未映射到模型的字段。

我们的模型示例是这样的:

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
}

如果我们想在我们的表单中添加一个名为myExtraField的额外字段,我们这样做:

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
}

笔记 :

  • mapped替换了将在 Symfony 2.3 中弃用的property_path
  • 您可以通过在选项数组中添加'data' => 1条目来向 myExtraField 添加默认选定值。

示例代码:

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

如果要验证myExtraField字段,则不能在 Post Entity 注释中进行,必须在表单中进行。

验证非映射字段 - Symfony 2.0 方式

2.0 的方法是在表单构建器中添加一个验证器($builder->addValidator(..)),但是这个方法已经被弃用了!

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
}

这目前正在验证 myExtraField 字段,但$builder->addValidator将在 Symfony 2.3 中消失!

前向兼容代码

正如从 Symfony 2.0 升级到 2.1中所述,由于FormValidatorInterface已被弃用,我们现在必须将验证闭包函数传递给绑定到 FormEvents::POST_BIND 事件的事件侦听器。

这是代码。

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
}

这当然可以通过一些 Sf 专家的帮助来改进,但现在它以向前兼容的方式验证未绑定的表单字段。

希望这有助于我们中的一些人摆脱困境。

大卫

于 2012-10-26T12:10:24.447 回答
31

正如我在一个关于类似主题的问题中提到的那样从 Symfony 2.1 开始,您应该使用“约束”选项来为您的未映射字段添加验证:

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

希望它能帮助像我这样在这方面浪费时间的人......

于 2013-07-31T06:05:54.060 回答
5

如果您已经在使用约束,那么您可以这样做:

$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',
        ))
    ;
于 2016-05-18T03:39:27.823 回答
0

其作品。检查 symfony 2.1。代码应该是这样的:

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

当然,属性“必需”不是必需的。文档中的示例。

于 2014-02-06T03:50:46.960 回答
0

Symfony 3.4 基于非映射字段的表达式约束:

$resolver->setDefaults([
        'data_class' => MyClass::class,
        'constraints' => [
            new Expression([
                'expression' => 'this["endTime"].getData() >= this["startTime"].getData()',
                'message' => 'L\'heure de fin doit être plus grande ou égale à l\'heure de début'
            ])
        ]
    ]);
于 2019-03-19T09:21:29.450 回答