Search code examples
phpsymfonydoctrinemany-to-many

Symfony delete ManyToMany related object when one part is empty?


I'm trying to delete unused tags. Although the relationship between Post and Tag has been deleted, the post-linked tag is not deleted.

"orphanRemoval" does not work because it has deleted all. cascade "remove" does not delete.

Post Entity:

class Post implements \JsonSerializable
{
   /**
    * @ORM\ManyToMany(targetEntity="App\Entity\Cms\PostTag", inversedBy="posts", cascade={"persist", "remove"})
    * @ORM\JoinTable(name="post_tag_taxonomy")
    * @Assert\Count(max="5")
    */
    private $tags;
}

Tag Entity:

class PostTag {
    /**
     * @ORM\ManyToMany(targetEntity="App\Entity\Cms\Post", mappedBy="tags")
     */
     private $posts;
}

Here's a similar example, but for Java. How to delete an ManyToMany related object when one part is empty?


Solution

  • I suggest you use preUpdate event from Doctrine life cycle callbacks. On the event of update a Post, you tell doctrine to check if there's a Tag change (in this case it's to NULL), if yes then query the Tag check if any posts still use it.

    In short, you need to :

    Add @ORM\HasLifecycleCallbacks before your class to enable life cycles.

    Add preUpdate function in Post class :

        /**
         * @ORM\PreUpdate
         * @param PreUpdateEventArgs $event
         */
        public function clearChangeSet(PreUpdateEventArgs $event)
        {
            if ($event->hasChangedField('field_you_want_to_check') 
            ) {
                $em = $event->getEntityManager();
                // Now use the entityManager to query the tag and check.
            }
        }
    

    By doing this doctrine will do the check for you, in the logic code you just need to perform the unlinking, no need to care about delete tags there.

    Update : as pointed out, for associations in entity you cannot get the changes by $event->hasChangedField, use the method in Symfony 3 / Doctrine - Get changes to associations in entity change set