duaj39673 2018-09-20 10:07
浏览 63

Doctrine - 更新事件侦听器内的多对多关联

I`m a little bit confused with how to update related collection using doctrine events.

One entity is related with another through ManyToMany. For better understanding u can see examples below (User with Jobs). The goal is: when User`s status is going to be changed then his jobs should also be changed from event listener.

I have already tried preUpdate event:

public function preUpdate(PreUpdateEventArgs $args)
{
    $entity = $args->getObject();
    foreach ($entity->getJobs() as $job) {
        $entity->getJobs()->removeElement($job);
    }
}

And also onFlush event:

public function onFlush(OnFlushEventArgs $eventArgs)
{
    $em = $eventArgs->getEntityManager();
    $uow = $em->getUnitOfWork();

    foreach ($uow->getScheduledEntityUpdates() as $entity) {
        foreach ($entity->getJobs() as $job) {
            $entity->getJobs()->removeElement($job);
        }

        $em->persist($entity);
        $uow->recomputeSingleEntityChangeSet(
            $em->getClassMetadata(Job::class),
            $entity
        );
    }
}

But in case when only status was changed outside the listener - user still have the same jobs(jobs were not changed from listener):

$user->setStatus('some-other-status');

But in case when collection was changed outside the listener - it works(jobs were changed from listener):

$collection = ... // some new collection of jobs
$user->setJobs(collection);

Any help is welcome.


Here are code snippets of entities:

User.php

use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;

/**
 * @ORM\Entity()
 * @ORM\Table()
 */
class User
{
    /**
     * @ORM\Column(type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue
     */
    protected $id;

    /**
     * @ORM\Column(type="string")
     */
    protected $status;

    /**
     * @ORM\ManyToMany(targetEntity="Job")
     * @ORM\JoinTable(name="_user_x_job",
     *     joinColumns={@ORM\JoinColumn(name="user", referencedColumnName="id", onDelete="CASCADE")},
     *     inverseJoinColumns={@ORM\JoinColumn(name="job", referencedColumnName="id", onDelete="CASCADE")}
     * )
     */
    protected $jobs;

    public function __construct()
    {
        $this->jobs = new ArrayCollection();
    }

    ...
}

Job.php:

use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;

/**
 * @ORM\Entity()
 * @ORM\Table()
 */
class Job
{
    /**
     * @ORM\Column(type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue
     */
    protected $id;

    /**
     * @ORM\Column(type="string")
     */
    protected $name;

    ...
}
  • 写回答

1条回答 默认 最新

  • dozabg1616 2018-09-20 10:42
    关注

    I would recommend to avoid Doctrine Event Listeners at all for this task. Instead the whole behavior should be modeled directly in the User Entity: The setState() method can also hold the behavior to remove the job(s).

    Then look out for removeOrphans=true doctrine mapping option:

    Basically it works by removing the Job from the collection AND set its User to null. Doctrine will detect your orphaned jobs from the unit of work and automatically deletes them from the database when calling persist($user); flush();

    评论

报告相同问题?

悬赏问题

  • ¥15 c语言怎么用printf(“\b \b”)与getch()实现黑框里写入与删除?
  • ¥20 怎么用dlib库的算法识别小麦病虫害
  • ¥15 华为ensp模拟器中S5700交换机在配置过程中老是反复重启
  • ¥15 java写代码遇到问题,求帮助
  • ¥15 uniapp uview http 如何实现统一的请求异常信息提示?
  • ¥15 有了解d3和topogram.js库的吗?有偿请教
  • ¥100 任意维数的K均值聚类
  • ¥15 stamps做sbas-insar,时序沉降图怎么画
  • ¥15 买了个传感器,根据商家发的代码和步骤使用但是代码报错了不会改,有没有人可以看看
  • ¥15 关于#Java#的问题,如何解决?