Skip to content

[Form] by_reference when embedding a single object #6965

@pvanliefland

Description

@pvanliefland

When setting data on an embedded form that has the option 'by_reference' set to false, the provided model data is cloned before being converted to norm data / view data.

I understand that it is the desirable behavior when dealing with collections, as only the Collection instance is cloned, and not its items.

When embedding a single object, the behavior seems problematic : if the form's underlying object is a Doctrine entity previously inserted in the database, cloning it will prevent Doctrine from being able to update it - it will be considered as a new entity.

Of course, I could set 'by_reference' to true but I need the actual setter to be called on the "parent" object.

A simple example : a user entity, with an optional extended profile entity. My user form type embeds the extended profile form type. I need setExtendedProfile() to be called on the user entity, so 'by_reference' needs to be set to false. However, if I use the form to update an existing user entity, the cloning operation on the extendedProfile entity will trick Doctrine into thinking that this extendedProfile entity is a new entity.

Not sure whether it is an actual bug or if I am missing something. My first idea would be to change the Form class so that it only clones \Traversable instances, and not every single object. @bschussek, if it is indeed a reasonable solution I can provide a patch along with adapted unit tests.

class User
{
    /**
     * @var ExtendedProfile
     * @ORM\OneToOne(targetEntity="ExtendedProfile", mappedBy="user", cascade={"all"}, orphanRemoval=true)
     */
    private $extendedProfile;

    public function getExtendedProfile()
    {
        return $this->extendedProfile;
    }

    public function setExtendedProfile($extendedProfile)
    {
        // Do important stuff here
        $this->extendedProfile = $extendedProfile;
    }
    ...
}

class ExtendedProfile
{
     /**
     * @var User
     * @ORM\OneToOne(targetEntity="User", inversedBy="extendedProfile")
     * @ORM\JoinColumn(name="user_id", referencedColumnName="id", nullable=false)
     */
    private $user;
    ...
}

class UserType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('extendedProfile', 'extended_profile', array('by_reference' => false))
            ...
    }
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions