如何在Symfony2中“动态”禁用一个转换器验证错误


How to disable one transformer validation error "dynamically" in Symfony2

>我有一个包含许多字段和验证组的表单,这些字段也包含一些视图数据转换器。

我需要部分禁止验证表单(基于提交数据的组):

use AppBundle'Entity'Client;
use Symfony'Component'Form'FormInterface;
use Symfony'Component'OptionsResolver'OptionsResolver;
// ...
public function configureOptions(OptionsResolver $resolver)
{
    $resolver->setDefaults(array(
        'validation_groups' => function (FormInterface $form) {
            $data = $form->getData();
            if (Client::TYPE_PERSON == $data->getType()) {
                return array('person');
            }
            return array('company');
        },
    ));
}

执行此操作时,窗体将执行基本完整性检查(禁用验证)和来自转换器的验证错误仍被抛出(创建转换器)。

使用 POST_SUBMIT 事件并阻止调用 ValidationListener(禁止表单验证):

use Symfony'Component'Form'FormBuilderInterface;
use Symfony'Component'Form'FormEvents;
use Symfony'Component'Form'FormEvent;
public function buildForm(FormBuilderInterface $builder, array $options)
{
    $builder->addEventListener(FormEvents::POST_SUBMIT, function (FormEvent $event) {
        $event->stopPropagation();
    }, 900); // Always set a higher priority than ValidationListener
    // ...
}

这对我来说不是一个解决方案,因为它意外地禁用了不仅仅是表单验证的东西。

问题是:如何"动态"禁用一个变压器验证错误?

例:

我有一个表单字段RepeatedType属于person验证组,并包含一个视图转换器(RepeatedType),当数组中的值不同时,此转换器会引发异常(ValueToDuplicatesTransformer)。

因此,即使company验证组,表单也显示错误属于来自变压器RepeatedType字段。

这里的问题是:person验证组时如何禁用ValueToDuplicatesTransformer错误?

因为buildForm错过了与添加我假设的字段相关的代码:

  1. 您不直接通过data_class将表单与实体相关联,而是在控制器中设置值
  2. repeated类型具有required => true选项,可用于验证密码
  3. 传递给表单生成器的$data包含repeated字段的值。

问题基本上是触发了验证。如果有任何数据,则该类型将始终执行其基本验证(重复字段应具有相同的值两次)。

要解决此问题,您应该做的是首先不要将值传递给$data,并确保重复字段required => false。如您所解释的,您的表单将仅在该之后进行组验证。

也许最强大的解决方案甚至不同,最好做两个FormTypes而不是使用groups。这将消除您在问题中描述的大部分复杂性。

您不能真正停用来自 DataTransformer 的错误,这些错误是由 FormValidator 添加的,并且此行为不可自定义。这是非常合乎逻辑的,因为转换错误会导致模型数据处于损坏状态。

在这种情况下,我要做的是使用 2 个字段而不是重复字段,第二个字段带有 mapped => false 和一个在需要时手动添加错误的事件侦听器。

也许我错了,但验证组根本不是解决问题的正确工具。要解决的验证规则的依赖关系基于数据,而验证组不是关于数据的,而是关于相同的数据根据上下文进行不同的验证。

如果您只想对个人应用一些规则(或者相反,仅适用于公司),我宁愿在客户端实体中实现自定义检查

namespace AppBundle'Entity;
class Client {
....
/**
* @Assert'IsTrue(message="Person should have a valid Title")
*/
public function isPersonTitleValid()
{
  return $this->type != Client::TYPE_PERSON || $this->isTitleValid();
}
public function isTitleValid()
{
  // Here implement your validation applicable only for person;
}