Search code examples
symfonysymfony-forms

Symfony Forms persist multiple EntityType


I have no problem to persist from ManytoMany(normal) and ManytoOne, however, I don't understand the proper way to persist entity from OnetoMany and ManytoMany(Reversed).

Here is an example :

ExampleEntity :

...
/**
 * @var ArrayCollection $myentities
 *
 * @ORM\OneToMany(targetEntity="AppBundle\Entity\Myentity", mappedBy="exampleentity", cascade={"persist"})
 */
private $myentities;

// getters/setters
/*
public function addMyentity(Myentity $myentitie)
public function removeMyentity(Myentity $myentitie)
public function getMyentities()
public function setMyentities(ArrayCollection $myentities)
*/
...

Form :

...
->add('myentities', 'Symfony\Bridge\Doctrine\Form\Type\EntityType', array(
    'class'         => 'AppBundle\Entity\Myentity',
    'multiple'    => true
))
...

Controller :

...
if ($form->handleRequest($request)->isValid()) {
        $em = $this->getDoctrine()->getManager();
        $em->persist($exampleentity);
        $em->flush();
    }
}
...

So here is the problem, add and remove function are never called, so all "$myentities" are never persist correcly.

I try to update my form with "by_reference => false" but it is not documented for EntityType (and also create other errors).

I try to change my controller but during edit how detect which one have been select (easy) and which ones have been unselected (not easy or not optimised) ?

Doctrine is not supposed to simplify theses kind of tasks ?


Solution

  • Solution in case anyone stumbles upon this same problem:

    You need to have proper setters/getters:

    class MyEntity
    {
        /**
         * @var Groupe[]|ArrayCollection
         *
         * @ORM\OneToMany(targetEntity="Groupe", mappedBy="otherEntity")
         */
        protected $notifyGroupsOnNewMail;
    
        public function addNotifyGroupsOnNewMail(Groupe $notifyGroupsOnNewMail): self
        {
            if (!$this->notifyGroupsOnNewMail->contains($notifyGroupsOnNewMail))
            {
                $this->notifyGroupsOnNewMail[] = $notifyGroupsOnNewMail;
                $notifyGroupsOnNewMail->setMyEntity($this);
            }
    
            return $this;
        }
    
        public function removeNotifyGroupsOnNewMail(Groupe $notifyGroupsOnNewMail): self
        {
            if ($this->notifyGroupsOnNewMail->contains($notifyGroupsOnNewMail))
            {
                $this->notifyGroupsOnNewMail->removeElement($notifyGroupsOnNewMail);
                // set the owning side to null (unless already changed)
                if ($notifyGroupsOnNewMail->getMyEntity() === $this)
                {
                    $notifyGroupsOnNewMail->setMyEntity(null);
                }
            }
    
            return $this;
        }
    }
    

    But also have 'by_reference' => false in your form, otherwise your setters are not called, and therefore trying to persist from the reverse side will not save anything:

                ->add('notifyGroupsOnNewMail', EntityType::class, [
                    'class'    => Groupe::class,
                    'required' => false,
                    'multiple' => true,
                    'by_reference' => false
                ])