Doctrine:多对多在事件侦听器中删除关联对象
Doctrine: many-to-many get removed associated object inside an event listener
我有很多这样的关联
Entity Car
{
/**
* @var \Doctrine\Common\Collections\Collection
*
* @ORM\ManyToMany(targetEntity="User", inversedBy="cars", fetch="EXTRA_LAZY")
* @ORM\JoinTable(
* name="cars_users",
* joinColumns={
* @ORM\JoinColumn(name="car_id", referencedColumnName="id")
* },
* inverseJoinColumns={
* @ORM\JoinColumn(name="user_id", referencedColumnName="id")
* }
* )
*/
protected $users;
/**
* @param $user
*/
public function removeUser(User $user)
{
if (!$this->users->contains($user)) {
return;
}
$this->users->removeElement($user);
$user->removeCar($this);
return $this;
}
}
Entity User
{
/**
* @var \Doctrine\Common\Collections\Collection
*
* @ORM\ManyToMany(targetEntity="Car", mappedBy="users")
*/
protected $cars;
}
在我的控制器中我有
$carA = getRandomCar();
$userB = getAUserThatBelongToCarA();
//remove association between Car A and User B
$carA->removesUser($userB);
doctrineUpdateCar($carA);
我有一个 Doctrine Listener CarListener
我正在尝试找出 User
是否已在该侦听器中删除,并告诉它是哪个 User
。
我尝试了 preUpdate
postUpdate
postFlush
但无法找到在 CarListener
中获取 $userB
对象的方法
您的 preUpdate
侦听器将收到一个 PreUpdateEventArgs
对象,您可以使用该对象获取大量有关要通过 hasChangedField()
等方法持久化的更改的信息。更多信息在这里:
http://doctrine-orm.readthedocs.org/projects/doctrine-orm/en/latest/reference/events.html#preupdate
Doctrine 确实表现得很奇怪...在更复杂的环境中遇到了同样的问题。所以我决定从你的例子中复制汽车和用户 class。使用完全相同的实体,除了汽车实体中的 removeUser 函数。认为这会更短:
class Car
{
public function removeUser(User $user)
{
$this->users->removeElement($user);
}
}
在控制器中我得到了这个:
$em = $this->getDoctrine()->getManager();
$cars = $this->getDoctrine()->getRepository('AppBundle:Car');
$users = $this->getDoctrine()->getRepository('AppBundle:User');
$car = $cars->findOneById(2);
$removeUser = $users->findOneById(3);
$car->removeUser($removeUser);
// $em->flush();
ID 为#3 的用户总是从#2 汽车中移除。无论 car_user table 中的条目是否存在,都会执行 DELETE 语句。
如果我在 EntityManager
($em) 的 flush 方法中发表评论,则会调用 onFlush
事件。 UnitsOfWork 对象上的函数 getScheduledEntityInsertions()
、getScheduledEntityUpdates()
、getScheduledEntityDeletions()
、getScheduledCollectionDeletions()
和 getScheduledCollectionUpdates()
仅返回空数组...
我认为最简单的方法是通知自己有关更改的信息。找到了一种通过交出注释来跟踪它们的简单方法。以下是链接:
事件
我建议您使用 onflush 事件让 listener/subscriber 监听,因为它是在计算更改之后但在对数据库执行任何操作之前调度的。这使得它非常理想,因为您可以访问所有即将进行的更改,但实际上还没有将它们写入数据库(因此您可以选择中止)。
listener/subscriber 被传递给 OnFlushEventArgs
object,您可以从中访问 UnitOfWork。工作单元有 5 种方法来收集即将进行的更改:
getScheduledEntityInsertions()
getScheduledEntityUpdates()
getScheduledEntityDeletions()
getScheduledCollectionUpdates()
getScheduledCollectionDeletions()
Collections
您正在做的是从 collection Car::$users
中删除 User
并从 collection User::cars
中删除 Car
。
因此实际上没有删除任何实体,也没有更改任何字段。相反,您正在更改 collections。换句话说,您要查看的是 getScheduledCollectionUpdates()
。
getScheduledCollectionUpdates()
返回的 collection(s) 是 PersistentCollection 的一个实例,它有这些方法告诉你发生了什么变化:
getInsertDiff()
getDeleteDiff()
在您的情况下,您可以使用 getDeleteDiff()
找出哪个实体已从 collection 中删除。
我有很多这样的关联
Entity Car
{
/**
* @var \Doctrine\Common\Collections\Collection
*
* @ORM\ManyToMany(targetEntity="User", inversedBy="cars", fetch="EXTRA_LAZY")
* @ORM\JoinTable(
* name="cars_users",
* joinColumns={
* @ORM\JoinColumn(name="car_id", referencedColumnName="id")
* },
* inverseJoinColumns={
* @ORM\JoinColumn(name="user_id", referencedColumnName="id")
* }
* )
*/
protected $users;
/**
* @param $user
*/
public function removeUser(User $user)
{
if (!$this->users->contains($user)) {
return;
}
$this->users->removeElement($user);
$user->removeCar($this);
return $this;
}
}
Entity User
{
/**
* @var \Doctrine\Common\Collections\Collection
*
* @ORM\ManyToMany(targetEntity="Car", mappedBy="users")
*/
protected $cars;
}
在我的控制器中我有
$carA = getRandomCar();
$userB = getAUserThatBelongToCarA();
//remove association between Car A and User B
$carA->removesUser($userB);
doctrineUpdateCar($carA);
我有一个 Doctrine Listener CarListener
我正在尝试找出 User
是否已在该侦听器中删除,并告诉它是哪个 User
。
我尝试了 preUpdate
postUpdate
postFlush
但无法找到在 CarListener
$userB
对象的方法
您的 preUpdate
侦听器将收到一个 PreUpdateEventArgs
对象,您可以使用该对象获取大量有关要通过 hasChangedField()
等方法持久化的更改的信息。更多信息在这里:
http://doctrine-orm.readthedocs.org/projects/doctrine-orm/en/latest/reference/events.html#preupdate
Doctrine 确实表现得很奇怪...在更复杂的环境中遇到了同样的问题。所以我决定从你的例子中复制汽车和用户 class。使用完全相同的实体,除了汽车实体中的 removeUser 函数。认为这会更短:
class Car
{
public function removeUser(User $user)
{
$this->users->removeElement($user);
}
}
在控制器中我得到了这个:
$em = $this->getDoctrine()->getManager();
$cars = $this->getDoctrine()->getRepository('AppBundle:Car');
$users = $this->getDoctrine()->getRepository('AppBundle:User');
$car = $cars->findOneById(2);
$removeUser = $users->findOneById(3);
$car->removeUser($removeUser);
// $em->flush();
ID 为#3 的用户总是从#2 汽车中移除。无论 car_user table 中的条目是否存在,都会执行 DELETE 语句。
如果我在 EntityManager
($em) 的 flush 方法中发表评论,则会调用 onFlush
事件。 UnitsOfWork 对象上的函数 getScheduledEntityInsertions()
、getScheduledEntityUpdates()
、getScheduledEntityDeletions()
、getScheduledCollectionDeletions()
和 getScheduledCollectionUpdates()
仅返回空数组...
我认为最简单的方法是通知自己有关更改的信息。找到了一种通过交出注释来跟踪它们的简单方法。以下是链接:
事件
我建议您使用 onflush 事件让 listener/subscriber 监听,因为它是在计算更改之后但在对数据库执行任何操作之前调度的。这使得它非常理想,因为您可以访问所有即将进行的更改,但实际上还没有将它们写入数据库(因此您可以选择中止)。
listener/subscriber 被传递给 OnFlushEventArgs
object,您可以从中访问 UnitOfWork。工作单元有 5 种方法来收集即将进行的更改:
getScheduledEntityInsertions()
getScheduledEntityUpdates()
getScheduledEntityDeletions()
getScheduledCollectionUpdates()
getScheduledCollectionDeletions()
Collections
您正在做的是从 collection Car::$users
中删除 User
并从 collection User::cars
中删除 Car
。
因此实际上没有删除任何实体,也没有更改任何字段。相反,您正在更改 collections。换句话说,您要查看的是 getScheduledCollectionUpdates()
。
getScheduledCollectionUpdates()
返回的 collection(s) 是 PersistentCollection 的一个实例,它有这些方法告诉你发生了什么变化:
getInsertDiff()
getDeleteDiff()
在您的情况下,您可以使用 getDeleteDiff()
找出哪个实体已从 collection 中删除。