允许OneToOne关系在Symfony2中是可选的 [英] Allow a OneToOne relationship to be optional in Symfony2

查看:133
本文介绍了允许OneToOne关系在Symfony2中是可选的的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个负责创建和更新用户的表格.用户可以(或不可以)有一个地址(用户的OneToOne单向关系).

I have a form responsible of creating and updating users. A user can (or not) have an address (OneToOne unidirectional relation from user).

当我创建用户时,没问题. 当我更新用户时,通常没有问题. 当我更新已经有一个地址的用户并尝试取消设置所有地址字段时,出现问题.然后会出现验证错误.

When I create a user, no problem. When I update a user, usually no problem. Problems come up when i update a user which already has an address and try to unset all the address fields. There is then a validation error.

所需的行为是将user-> address关系设置为null(并删除数据库上先前设置的地址).

The wanted behavior would be to have the user->address relation set to null (and delete the previously set address on the DB).

有一个cascade_validation,格式(嵌套格式)的addess字段被设置为不需要,并且用户实体允许该地址为空.

There is a cascade_validation, the addess field in form (nested form) is set to not be required and the user entity allow the address to be null.

更新

相关实体和表格:

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

User entity (Getters & Setters are classical, Symfony generated):

class User
{
    [...]

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

    [...]
}

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

The address entity is classical, no bidirectionnal relation to user.

用户表格

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';
    }
}

地址嵌套形式为经典

如您所见,这是一个非常经典而直接的代码.唯一特殊的情况是该地址是可选的.仅在先前设置了地址(并且因此存在于数据库中且与用户不为空的关系)且用户想要取消设置(所有地址字段均保留为空)的情况下,才导致验证错误. 看来,如果相关地址没有实际实例,它仍然可以是可选的.但是,如果该地址的一个实例存在并与用户链接,则它不再是可选的.

As you can see, the is a quite classical and straightforward code. The only particular case is that address is optional. Leading to an validation error only in the case that the address was previously set (and, thus, exist in the DB and as a not null relation with the user) and the user want to unset it (all address fields are left empty). It seems that if the related address has not an actual instance it can still be optional. But, if an instance of the address exist and is linked with the user, it can not be optional anymore.

更新2

namespace Xentia\FuneoBundle\Form\Type;

use Doctrine\Common\Util\Debug;
use Symfony\Component\Config\Definition\Exception\Exception;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormEvents;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;

class AddressType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add("suggestLocality", null, array(
                'mapped' => false,
                'label' => 'Locality'
            ))
            ->add("suggestStreet", null, array(
                'mapped' => false,
                'label' => 'Street'
            ))
            ->add('street')
            ->add('locality')
            ->add('postalCode')
            ->add('country', null, array(
                'label' => false,
            ))
            ->add('latitude', 'hidden')
            ->add('longitude', 'hidden');

        $builder->addEventListener(FormEvents::PRE_SUBMIT,
            function(FormEvent $event) {
                $address = $event->getData();
                if (!empty($address)) {
                    $addressLocality = $address['locality'];
                    if (empty($addressLocality)) {
                        $event->setData(null);
                    }
                }
            }
        );
    }

    public function setDefaultOptions(OptionsResolverInterface $resolver)
    {
        $resolver->setDefaults(array(
            'data_class' => 'Xentia\FuneoBundle\Entity\Address',
            'validation_groups' => array('Default'),
        ));
    }

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

推荐答案

尝试在您的关系中设置orphanRemoval

Try setting orphanRemoval on your relation

/** @OneToOne(targetEntity="...", orphanRemoval=true) */
$address

编辑

我现在知道,您放置了错误的侦听器.首先应该是POST_SUBMIT,PRE_SUBMIT是处理请求数据并修改表单.在"POST提交"中,您可以修改对象.

I see now, you have placed the wrong listener. First of all it should be POST_SUBMIT, PRE_SUBMIT is to process request data and modify form. On POST SUBMIT you can modify the object.

这篇关于允许OneToOne关系在Symfony2中是可选的的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆