removeElement() and clear() doesn't work in doctrine 2 with array collection property

前端 未结 2 2066
小鲜肉
小鲜肉 2021-02-03 11:37

I\'m trying to get some simple CRUD done with doctrine 2 but when it\'s time to update a record with one property set as an array collection I don\'t seem to get removeElement()

相关标签:
2条回答
  • 2021-02-03 11:42

    I do something similar in a project with Events which have participants not unlike your User/Country relationship. I will just lay out the process and you can see if there's anything you are doing differently.

    On the Participant entity

    /**
     * @ManyToOne(targetEntity="Event", inversedBy="participants", fetch="LAZY")
     * @JoinColumn(name="event_id", referencedColumnName="id", nullable="TRUE")
     * @var Event
     */
    protected $event;
    

    On the Event entity:

    /**
     * @OneToMany(targetEntity="Participant", mappedBy="event")
     * @var \Doctrine\Common\Collections\ArrayCollection
     */
    protected $participants;
    

    Also in Event#__constructor I initialize like this:

    $this->participants = new \Doctrine\Common\Collections\ArrayCollection();
    

    Here is how I update an event:

    public function update(Event $event, Event $changes)
    {
        // Remove participants
        $removed = array();
        foreach($event->participants as $participant)
        {
            if(!$changes->isAttending($participant->person))
            {
                $removed[] = $participant;
            }
        }
    
        foreach($removed as $participant)
        {
            $event->removeParticipant($participant);
            $this->em->remove($participant);
        }
    
        // Add new participants
        foreach($changes->participants as $participant)
        {
            if(!$event->isAttending($participant->person))
            {
                $event->addParticipant($participant);
                $this->em->perist($participant);
            }
        }
    
        $event->copyFrom($changes);
        $event->setUpdated();
        $this->em->flush();
    }
    

    The methods on the Event entity are:

    public function removeParticipant(Participant $participant)
    {
        $this->participants->removeElement($participant);
        $participant->unsetEvent();
    }
    
    public function addParticipant(Participant $participant)
    {
        $participant->setEvent($this);
        $this->participants[] = $participant;
    }
    

    The methods on the Participant entity are:

    public function setEvent(Event $event)
    {
        $this->event = $event;
    }
    
    public function unsetEvent()
    {
        $this->event = null;
    }
    

    UPDATE: isAttending method

    /**
     * Checks if the given person is a 
     * participant of the event
     * 
     * @param Person $person
     * @return boolean 
     */
    public function isAttending(Person $person)
    {
        foreach($this->participants as $participant)
        {
            if($participant->person->id == $person->id)
                return true;
        }
    
        return false;
    }
    
    0 讨论(0)
  • 2021-02-03 11:44

    New answer

    In your countries entity, should you not have:

    @ManyToOne(targetEntity="User", inversedBy="countries") 
    

    instead of inversedBy="id"?

    Initial answer

    You need to set the countries field in your entity as remove cascade. For example, on a bidirectional one to many relationship:

    class Entity
    {
        /**
         * 
         * @OneToMany(targetEntity="Country", mappedBy="entity", cascade={"remove"})
         */
        private $countries;
    }
    

    This way, when saving your entity, doctrine will also save changes in collections attached to your entity (such as countries). Otherwise you have to explicitly remove the countries you want to remove before flushing, e.g.

    $this->em()->remove($aCountry);
    

    This is also valid for persist, merge and detach operations. More information here.

    0 讨论(0)
提交回复
热议问题