Doctrine:多对多在事件侦听器中删除关联对象

时间:2015-10-27 14:06:17

标签: symfony doctrine-orm doctrine

我有很多很多这样的协会

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但无法找到在$userB

内获取CarListener对象的方法

3 个答案:

答案 0 :(得分:9)

事件

我建议您使用onflush事件让侦听器/订阅者监听,因为它是在计算更改后调度的,但是在执行对数据库的任何操作之前。这使得它非常理想,因为您可以访问即将进行的所有更改,但实际上还没有将它们写入数据库(因此您可以选择中止)。

侦听器/订阅者传递一个OnFlushEventArgs对象,您可以从该对象访问UnitOfWork。工作单元有5种方法来收集即将进行的更改:

  • getScheduledEntityInsertions()
  • getScheduledEntityUpdates()
  • getScheduledEntityDeletions()
  • getScheduledCollectionUpdates()
  • getScheduledCollectionDeletions()

集合

您正在做的是从集合User中删除Car::$users并从集合Car中删除User::cars

因此,实际上没有实体被删除,没有任何字段被更改。而不是你改变收藏。换句话说,它是你想看的getScheduledCollectionUpdates()

getScheduledCollectionUpdates()返回的集合是PersistentCollection的一个实例,它使用这些方法告诉您发生了哪些变化:

  • getInsertDiff()
  • getDeleteDiff()

在您的情况下,您可以使用getDeleteDiff()找出已从集合中删除的实体。

答案 1 :(得分:0)

您的preUpdate侦听器将收到一个PreUpdateEventArgs对象,您可以使用该对象获取有关使用hasChangedField()等方法保留的更改的大量信息。更多信息:

http://doctrine-orm.readthedocs.org/projects/doctrine-orm/en/latest/reference/events.html#preupdate

答案 2 :(得分:0)

教义确实表现得很奇怪......在更复杂的环境中遇到同样的问题。所以我决定从你的例子中复制汽车和用户类。除了car实体中的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表中的条目是否存在,都会执行DELETE语句。 如果我在EntityManager($ em)上的flush方法中发表评论,则会调用onFlush事件。 UnitOfWork对象上的函数getScheduledEntityInsertions()getScheduledEntityUpdates()getScheduledEntityDeletions()getScheduledCollectionDeletions()getScheduledCollectionUpdates()只返回空数组......

我认为最简单的方法是通知自己这些变化。找到一种简单的方法来手动跟踪注释。以下是链接: