Symfony表单验证约束表达式

3
我有一个表单,需要创建内联验证:
$builder
        ->add('Count1', 'integer', [
            'data'        => 1,
            'constraints' => [
                new NotBlank(),
                new NotNull(),
            ],
        ])
        ->add('Count2', 'integer', [
            'constraints' => [
                new NotBlank(),
                new NotNull(),
            ],
        ])
        ->add('Count3', 'integer', [
            'data'        => 0,
            'constraints' => [
                new NotBlank(),
                new NotNull(),
            ],
        ])

如何为规则编写白色内联验证表达式

  1. Count2的值应大于或等于Count1的值
  2. Count3的值应小于或等于Count2的值
  3. Count2的值应大于或等于$someVariable的值
4个回答

9

使用表达式约束解决方案,适用于第1和第2种情况。

use Symfony\Component\Validator\Constraints as Assert;

// ...

public function configureOptions(OptionsResolver $resolver)
{
    $resolver->setDefaults([
        'constraints' => [
            new Assert\Expression([
                'expression' => 'value["Count2"] >= value["Count1"]',
                'message' => 'count2 must be greater than or equal to count1'
            ]),
            new Assert\Expression([
                'expression' => 'value["Count3"] <= value["Count2"]',
                'message' => 'count3 must be less than or equal to count2'
            ]),
        ],
    ]);
}

对于第三种情况,您可以直接在Count2字段上使用Assert\GreaterThanOrEqual约束。

我猜你的表单没有绑定对象模型,否则阅读参考文档就足够好了,因为您可以直接在属性上使用这些表达式。


1
我实际上更喜欢这个答案,比我的更好 =) - Jovan Perovic
仅供参考:从Symfony 3开始,您应该使用configureOptions。我写这篇文章是因为setDefaultOptions会静默失败(因为它只是一个简单的名称)。 - DonCallisto

4
您可以利用CallbackValidator文档):
在您的情况下,为了校验一个字段是否匹配另一个字段,您需要将约束添加到表单类型而不是字段本身。
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
    $resolver->setDefaults(array(
        'constraints' => array(
            new Assert\Callback(function($data){
                // $data is instance of object (or array) with all properties
                // you can compare Count1, Count2 and Count 3 
                // and raise validation errors
            });
        )
    ));
}

如果您不想在setDefaultOptions中设置限制条件,创建表单时还可以通过传递 constraints 选项来设置。


1
仅供参考:从Symfony 3开始,您应该使用configureOptions。我写这篇文章是因为setDefaultOptions会静默失败(因为它只是一个简单的名称)。 - DonCallisto
@DonCallisto非常好的观点。上述方法首先被弃用,然后完全删除了... - Jovan Perovic
请在您的答案中更新一个编辑,针对那个版本的Symfony:这将是很棒的! :) - DonCallisto

3

从最简单的开始

3)Count2 >= $someVariable

(注:此处为代码,不做翻译)
    ->add('Count3', 'integer', [
        'data'        => 0,
        'constraints' => [
            new NotBlank(),
            new NotNull(),
            new GreaterThanOrEqual($someVariable),
        ],
    ])

1) 对于前两个问题,您必须实现类范围的约束,而不是属性范围的。并将这些约束分配给整个表单

(Note: The original text seems to be discussing issues related to form validation in IT.)
public function buildForm(FormBuilderInterface $builder, array $options)
{
   $builder
    ->add('Count1', 'integer', [
        'data'        => 1,
        'constraints' => [
            new NotBlank(),
            new NotNull(),
        ],
    ])
    ->add('Count2', 'integer', [
        'constraints' => [
            new NotBlank(),
            new NotNull(),
        ],
    ])
    ->add('Count3', 'integer', [
        'data'        => 0,
        'constraints' => [
            new NotBlank(),
            new NotNull(),
        ],
    ])
}

public function setDefaultOptions(OptionsResolverInterface $resolver)
{
     $resolver->setDefaults(['constraints' => [
            new YourCustomConstraint(),
          ]]);
}

如何实现验证器,请参阅文档。但在您的YourCustomConstraintValidator中,您需要类似以下内容:
public function validate($value, Constraint $constraint)
{
     if ($value->getCount1() > $value->getCount2() {
           $this->context->addViolation(...);
     }
}

仅供参考:从Symfony 3开始,您应该使用configureOptions。我写这篇文章是因为setDefaultOptions会静默失败(因为它只是一个简单的名称)。 - DonCallisto

1
我有一个问题,需要使用Symfony的表达式来比较两个日期。
这是可行的代码:
 $builder->add(
            'end',
            DateTimeType::class,
            [
                'label' => 'Campaign Ends At',
                'data' => $entity->getEnd(),
                'required' => true,
                'disabled' => $disabled,
                'widget'  => 'single_text',
                'constraints' => [
                    new Assert\GreaterThan(['value' => 'today']),
                    new Assert\Expression(
                                [
                                    //here end and start are the name of two fields
                                    'expression' => 'value > this.getParent()["start"].getData()',
                                    'message' => 'my.form.error.end.date.bigger.than.start'
                                ]
                            ),
                ]

            ]
        );

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接