【问题标题】:Doctrine - update many to many associations inside of event listenerDoctrine - 更新事件监听器内部的多对多关联
【发布时间】:2018-09-20 10:07:11
【问题描述】:

我对如何使用教义事件更新相关集合有点困惑。

一个实体通过ManyToMany 与另一个实体相关联。为了更好地理解你可以看到下面的例子(有工作的用户)。 目标是:当用户的状态要改变时,他的工作也应该从事件监听器改变

我已经尝试过preUpdate事件:

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

还有onFlush事件:

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
        );
    }
}

但如果仅在侦听器之外更改状态 - 用户仍然拥有相同的作业(作业未从侦听器更改):

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

但如果在侦听器之外更改集合 - 它可以工作(从侦听器更改作业):

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

欢迎任何帮助。


这里是实体的代码sn-ps:

用户.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;

    ...
}

【问题讨论】:

  • 为什么不在模型中处理这个?不要使用侦听器,它们旨在用于低级别、建模不相关的操作,例如日志记录。停止使用anemic domain models

标签: php symfony doctrine-orm


【解决方案1】:

我建议在这个任务中完全避免使用 Doctrine 事件监听器。相反,整个行为应该直接在用户实体中建模:setState() 方法也可以保存删除作业的行为。

然后注意removeOrphans=true 学说映射选项:

基本上,它通过从集合中删除 Job 并将其 User 设置为 null 来工作。 Doctrine 会从工作单元中检测到你的孤立作业,并在调用persist($user); flush(); 时自动从数据库中删除它们

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-07-05
    • 2018-06-01
    • 2019-06-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-30
    • 1970-01-01
    • 2013-10-11
    相关资源
    最近更新 更多