Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Doctrine manyToMany return PersistentCollection instead of ArrayCollection

I'm working with Symfony 3.1 and Doctrine 2.5.

I setup a manyToMany relationship as I always do :

manyToMany:
        placeServices:
            targetEntity: Acme\MyBundle\Entity\PlaceService
            joinTable:
                name: place_place_service
                joinColumns:
                    place_id:
                        referencedColumnName: id
                inverseJoinColumns:
                    place_service_id:
                        referencedColumnName: id

And add methods to my Entity

    protected $placeServices;

    ...

    public function __construct()
    {
        $this->placeServices = new ArrayCollection();
    }

    ...

    /**
     * @return ArrayCollection
     */
    public function getPlaceServices(): ArrayCollection
    {
        return $this->placeServices;
    }

    /**
     * @param PlaceServiceInterface $placeService
     * @return PlaceInterface
     */
    public function addPlaceService(PlaceServiceInterface $placeService): PlaceInterface
    {
        if(!$this->placeServices->contains($placeService)) {
            $this->placeServices->add($placeService);
        }

        return $this;
    }

    /**
     * @param PlaceServiceInterface $placeService
     * @return PlaceInterface
     */
    public function removePlaceService(PlaceServiceInterface $placeService): PlaceInterface
    {
        if($this->placeServices->contains($placeService)) {
            $this->placeServices->removeElement($placeService);
        }

        return $this;
    }

The thing is, when I load my entity, doctrine put a PersistentCollection in the $this->placeServices property. This does not sound like a big problem, except that when I build a form to connect those two entities (a simple multiple checkboxes with symfony form type), when $form->handleRequest() is triggered, Doctrine try to inject the new data in my entity, and throw an error if get/add/remove method are not using ArrayCollection.

I can force my getter/add/remove methods to transforme the PersistentCollection to ArrayCollection (using unwrap method) but then the relations made are not persisted.

I've found a workaround, if I set fetch="EAGER" on the relation the property is initialized with ArrayCollection, and the relation are persisted. But i'm not sure it's a good solution.

Thanks :)

like image 821
Thomas Piard Avatar asked Jul 16 '16 11:07

Thomas Piard


1 Answers

Just use Doctrine\Common\Collections\Collection interface instead of ArrayCollection. ArrayCollection and PersistentCollection implement this interface.

Doctrine uses PersistentCollection for lazy loading entities. You are right, using EAGER is not always a good solution - it can cause perfomance issues.

like image 57
Arthur Avatar answered Oct 17 '22 06:10

Arthur