允许OneToOne关系在Symfony2中是可选的

时间:2015-03-29 18:44:55

标签: symfony relationship one-to-one optional

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

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

想要的行为是将user->地址关系设置为null(并删除DB上先前设置的地址)。

有一个cascade_validation,表单中的addess字段(嵌套表单)设置为不需要,用户实体允许该地址为null。

更新

相关实体和表格:

用户实体(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中并且与用户非空关系)并且用户想要取消设置(所有地址字段都为空)的情况下导致验证错误。 似乎如果相关地址没有实际的实例,它仍然是可选的。但是,如果地址的实例存在并且与用户链接,则它不再是可选的。

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

1 个答案:

答案 0 :(得分:0)

尝试在您的关系中设置orphanRemoval

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

修改

我现在看到,你放错了听众。首先它应该是POST_SUBMIT,PRE_SUBMIT是处理请求数据和修改表单。在POST SUBMIT上,您可以修改对象。