Symfony2中验证的可选嵌套表单

时间:2015-03-29 13:00:53

标签: forms validation symfony nested-forms optional

Symfony2中是否有一种方法可以在使用级联验证时添加可选的嵌套表单? 换句话说,假设我有一个带有嵌套地址格式的用户表单(->add('adresse', new AddressType(), array('required' => false)))。此地址不是必需的,但必须在用户指定('cascade_validation' => true)时验证。

更新

相关实体和表格:

用户实体(Getters& Setters是经典的,Symfony生成的):

class User
{
    [...]

    /**
     * @var \Address
     *
     * @ORM\OneToOne(targetEntity="Address", cascade="persist")
     * @ORM\JoinColumn(
     *        name="address_id", referencedColumnName="id"
     * )
     */
    private $address;

    [...]
}

地址实体是经典的,没有与用户的双向关系。

用户表单

    class UserType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            [...]
            ->add('address', new AddressType(), array('required' => false))
            [...]
        ;
    }

    public function setDefaultOptions(OptionsResolverInterface $resolver)
    {
        $resolver->setDefaults(array(
            'data_class' => 'Xentia\FuneoBundle\Entity\User',
            'cascade_validation' => true
        ));
    }

    public function getName()
    {
        return 'user';
    }
}

地址嵌套表格是经典的

正如您所看到的,这是一个非常经典和简单的代码。唯一的特殊情况是地址是可选的。仅在地址先前已设置(并且因此存在于DB中并且与用户非空关系)并且用户想要取消设置(所有地址字段都为空)的情况下导致验证错误。 似乎如果相关地址没有实际的实例,它仍然是可选的。但是,如果地址的实例存在并且与用户链接,则它不再是可选的。

那么,它应该做什么:当用户更新他的个人资料时,如果有一个先前设置的地址并且他试图取消设置它,user->address应该设置为NULL并且地址应该删除。 实际发生了什么:表单抛出一个验证错误,指出未设置地址字段。但是,由于地址是可选的,因此不应发生此类验证错误。而且,实际上,如果在用户更新其配置文件之前未设置地址,则不会发生这种情况,只有在先前设置了地址时才会发生。

1 个答案:

答案 0 :(得分:1)

  

当用户更新他的个人资料时,如果有先前设置的地址并且他试图取消设置,则应将user->地址设置为NULL并删除该地址。

是的,你是对的,如果用户试图取消设置它就会被删除。在我们的评论中,您进一步澄清了一点:

  

“删除地址”按钮?在我看来,对用户来说太过分了......我认为没有理由这样做。如果用户未设置地址,则应自动删除该地址。软件必须对用户来说很容易,对开发者来说也很难,而不是相反。对我来说绝对不是一个好的解决方案。

这不是它应该如何运作的。由于用户之前已经创建了地址,因此删除此Address实体是没有意义的,因为它的所有属性都是空的。如果您要删除用户,那么可能想要删除其地址。对于Doctrine,如果没有明确说明(或cascaded ),则无需删除关联。

您尝试实现的目标可能不会直接Constraint Configuration。您应该进行实体验证 内部

Address课程中设置Callbacks。可以是这样的:

    /**
     * @param ExecutionContextInterface $contextInterface
     */
    public function validate(ExecutionContextInterface $contextInterface)
    {
        $country = ($this->country && $this->state);
        $home = ($this->street && $this->zip);

        if ($country || $home) {
            //You can start validating your fields one by one as you wish
            if ($this->country === null) {
                $contextInterface->addViolationAt('country', 'Pick a Country, mercì');
            }

            [...]
        }
        //No property is set so we skip validation (they can be set as empty in the DB)            
        return;
    }

注意

您可以使用实体内部的验证constraints或总custom类来验证您的验证需求。