Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/php/298.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Php 为Symfony 3中集合的每个元素应用特定的验证组_Php_Forms_Symfony_Validation_Symfony 3.4 - Fatal编程技术网

Php 为Symfony 3中集合的每个元素应用特定的验证组

Php 为Symfony 3中集合的每个元素应用特定的验证组,php,forms,symfony,validation,symfony-3.4,Php,Forms,Symfony,Validation,Symfony 3.4,我不得不将我的一个项目从symfony 2.8升级到symfony 3.4,我注意到验证过程中发生了巨大的变化 为了简化,假设我有一个用户实体,有许多地址实体。 当我创建/更新我的用户时,我希望能够添加/删除/更新任意数量的地址。所以在symfony2.8中,我遇到了这种情况 用户 我使用注释验证器 src/AppBundle/Entity/User.php //... class User { //... /** * @Assert\Count(min=1, ma

我不得不将我的一个项目从symfony 2.8升级到symfony 3.4,我注意到验证过程中发生了巨大的变化

为了简化,假设我有一个用户实体,有许多地址实体。 当我创建/更新我的用户时,我希望能够添加/删除/更新任意数量的地址。所以在symfony2.8中,我遇到了这种情况

用户

我使用注释验证器

src/AppBundle/Entity/User.php

//...
class User
{
    //...
    /** 
     * @Assert\Count(min=1, max=10)
     * @ORM\OneToMany(targetEntity="AppBundle\Entity\Address", mappedBy="user", cascade={"persist", "remove"})
     */
    protected $addresses;
    //...
}
UserForm

src/AppBundle/Form/UserForm.php

public function buildForm(FormBuilderInterface $builder, array $options)
{
    $builder
        // ...
        ->add('addresses', CollectionType::class, [
            'type' => AddressType::class,
            'cascade_validation' => true,
            'allow_add' => true,
            'allow_delete' => true,
            'by_reference' => false,
        ])
    ;
}

public function setDefaultOptions(OptionsResolverInterface $resolver)
{
    $resolver->setDefaults([
        'data_class' => User::class,
        'cascade_validation' => true,
        'validation_groups' => // User's logic
    ]);
}
src/AppBundle/Form/AddressForm.php

public function buildForm(FormBuilderInterface $builder, array $options)
{
    $builder
        // ...
        ->add('zipCode', TextType::class)
    ;
}

public function setDefaultOptions(OptionsResolverInterface $resolver)
{
    $resolver->setDefaults([
        'data_class' => Address::class,
        'cascade_validation' => true,
        'validation_groups' => function(FormInterface $form) {
            /** @var Address $data */
            $data = $form->getData();
            $validation_groups = [];

            // Simplified here, it's a service call with heavy logic
            if ($data->doesRequireZip()) {
                $validation_groups[] = 'zipRequired';
            }

            return $validation_groups;
        },
    ]);
}
地址

src/AppBundle/Entity/Address.php

//...
class Address
{
    //...
    /**
     * @ORM\ManyToOne(targetEntity="AppBundle\Entity\User", inversedBy="user")
     */
    protected $user;

    /**
     * @Assert\NotBlank(groups={"zipRequired"})
     * @ORM\Column(type="text", nullable="true")
     */
    protected $zipCode;
    //...
}
地址格式

src/AppBundle/Form/UserForm.php

public function buildForm(FormBuilderInterface $builder, array $options)
{
    $builder
        // ...
        ->add('addresses', CollectionType::class, [
            'type' => AddressType::class,
            'cascade_validation' => true,
            'allow_add' => true,
            'allow_delete' => true,
            'by_reference' => false,
        ])
    ;
}

public function setDefaultOptions(OptionsResolverInterface $resolver)
{
    $resolver->setDefaults([
        'data_class' => User::class,
        'cascade_validation' => true,
        'validation_groups' => // User's logic
    ]);
}
src/AppBundle/Form/AddressForm.php

public function buildForm(FormBuilderInterface $builder, array $options)
{
    $builder
        // ...
        ->add('zipCode', TextType::class)
    ;
}

public function setDefaultOptions(OptionsResolverInterface $resolver)
{
    $resolver->setDefaults([
        'data_class' => Address::class,
        'cascade_validation' => true,
        'validation_groups' => function(FormInterface $form) {
            /** @var Address $data */
            $data = $form->getData();
            $validation_groups = [];

            // Simplified here, it's a service call with heavy logic
            if ($data->doesRequireZip()) {
                $validation_groups[] = 'zipRequired';
            }

            return $validation_groups;
        },
    ]);
}
在symfony 2.8中

在添加的3个地址中,两个必须使zipRequired组有效,一个无效。我工作

在symfony 3.4中

我向User:$zipCode声明添加了
@Assert\Valid()
,并删除了
'cascade\u validation'=>true
(不在方法配置选项中,但似乎未使用),因为它已被弃用

但现在添加了3个地址,其中两个地址必须使zipRequired组有效,另一个不有效:只使用用户的类验证程序组,这样我就可以用不一致的数据使表单有效

我使用xdebug进行了检查,调用了
AddressForm
中的
validator\u组
回调,但没有调用验证程序

我测试了这里描述的解决方案:但它不能再工作了,因为在symfony 3.4
cascade\u验证中,属性抛出错误

在我的情况下,所涉及的逻辑太重,无法使用此处描述的解决方案,因为在单个方法中重写整个
验证组
回调是非常不够的,它会将组应用于所有子实体


Assert\Valid
cascade\u validation
的行为不同,是否有办法处理symfony 3.4中的嵌入表单单个实体验证组,或者该功能肯定已消失?

因为这是一种预期行为(整个表单应通过根验证组进行验证,正如您可以在此处看到的解释:)解决此问题的唯一方法是在集合项(实体)内使用回调验证:

有关symfony回调断言的更多信息:

此解决方案是在symfony 5.1中提出的,但它可能在2.8中起作用+

更新 只是为了添加我的最终解决方案,我通过验证器添加了验证,强制每个属性对应一个特定的组(如果表单已经执行了验证,也不需要强制默认)


null
传递给
$validator->validate()上的第二个参数
将强制
Assert\Valid
运行对象
$this
,因此,
$groups
中的所有约束和回调都将运行

您是否已修复它?我在sf 5.1中遇到了完全相同的问题刚刚发现它们将尊重根表单上添加的任何验证组,可能是在e子窗体运行并返回正确的组列表,它们在某种程度上被根窗体的验证组覆盖。遗憾的是,他们称之为功能:我能找到的唯一方法是添加回调。我很久以前就不必使用此特定解决方案了。但您的解决方案看起来很棒。无论如何,他们更改了此行为还是太糟糕了R