Doctrine manyToMany return PersistentCollection instead of ArrayCollection

20,055

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.

Share:
20,055

Related videos on Youtube

Thomas Piard
Author by

Thomas Piard

Symfony2 developer

Updated on November 18, 2020

Comments

  • Thomas Piard
    Thomas Piard over 3 years

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

    • galeaspablo
      galeaspablo almost 8 years
      Could you update with your symfony form and the exact error message?
  • Thomas Piard
    Thomas Piard almost 8 years
    Thanks, i get the idea.