Allow a OneToOne relationship to be optional in Symfony2

喜你入骨 提交于 2019-12-12 05:37:24

问题


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.

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

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.

UPDATE

Relevant entities and forms :

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.

User form

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

The address nested form is classical

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.

UPDATE 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:


Try setting orphanRemoval on your relation

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

EDIT

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.



来源:https://stackoverflow.com/questions/29333311/allow-a-onetoone-relationship-to-be-optional-in-symfony2

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!