In docs: http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/events.html
There are defined events. Among them:
preRemove - The preRemove event occurs for a given entity before the respective EntityManager remove operation for that entity is executed. It is not called for a DQL DELETE statement.
postRemove - The postRemove event occurs for an entity after the entity has been deleted. It will be invoked after the database delete operations. It is not called for a DQL DELETE statement.
But these events are not called on DQL DELETE statement.
I remove elements from many to many table. When In collection there are two elements and I remove one, then event postUpdate
is called, but when i remove last element from collection postUpdate
is not called. postRemove
and preRemove
are not called never.
I saw in _profiler
that this query calls postUpdate
:
DELETE FROM instance_user WHERE instance_id = ? AND user_id = ?
but this not:
DELETE FROM instance_user WHERE instance_id = ?
How can I call action on deletion and addition in of many to many table? I can trigger any addition and these deletions that are not deletions all of elements in collection. To fully working code I need trigger deletions without all parameters specified.
I found some related questions:
As doctrine 2.18, Events::preUpdate
can be used.
BUT:
Changes to associations of the updated entity are never allowed in this event, since Doctrine cannot guarantee to correctly handle referential integrity at this point of the flush operation.
That means, if you want to update $tag
values, you CAN'T from there.
I recommand to use Events::preFlush
instead.
Getting tags
from this event, will return a PersistentCollection, e.g $post->getTags()
.
BE CAREFUL, when new Post
entity, and your collection is empty, getTags()
will return a Doctrine\Common\Collections\ArrayCollection
instead (which is empty).
Finally, you can use getDeleteDiff()
or getInsertDiff()
to get your informations.
<?php
namespace App\EventListener;
use App\Entity\Post;
use App\Entity\Tag;
use Doctrine\Bundle\DoctrineBundle\Attribute\AsEntityListener;
use Doctrine\ORM\Event\PreFlushEventArgs;
use Doctrine\ORM\Events;
use Doctrine\ORM\PersistentCollection;
#[AsEntityListener(event: Events::preFlush, entity: Post::class)]
class PostListener
{
public function preFlush(Post $post, PreFlushEventArgs $event): void
{
/** @var ArrayCollection|PersistentCollection<int, Tag> $tags */
$tags = $post->getTags();
if ($tags instanceof PersistentCollection) {
dump($tags->getDeleteDiff());
dd($tags->getInsertDiff());
}
}
}
namespace App\Entity;
use App\Repository\PostRepository;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\DBAL\Types\Types;
use Doctrine\ORM\Mapping as ORM;
#[ORM\Entity(repositoryClass: PostRepository::class)]
class Post
{
#[ORM\Id]
#[ORM\GeneratedValue]
#[ORM\Column(type: Types::INTEGER)]
private ?int $id = null;
/**
* @var Collection<int, Tag>
*/
#[ORM\ManyToMany(targetEntity: Tag::class, cascade: ['persist'])]
#[ORM\OrderBy(['name' => 'ASC'])]
private Collection $tags;
public function __construct()
{
$this->tags = new ArrayCollection();
}
public function getId(): ?int
{
return $this->id;
}
public function addTag(Tag ...$tags): void
{
foreach ($tags as $tag) {
if (!$this->tags->contains($tag)) {
$this->tags->add($tag);
}
}
}
public function removeTag(Tag $tag): void
{
$this->tags->removeElement($tag);
}
/**
* @return Collection<int, Tag>
*/
public function getTags(): Collection
{
return $this->tags;
}
}