Доктрина - обновление многих ко многим ассоциациям внутри слушателя событий

Я немного запутался в том, как обновить связанную коллекцию с помощью событий доктрины.

Один объект связан с другим через 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);

Любая помощь приветствуется.


Вот фрагменты кода сущностей:

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;

    ...
}

Почему вы не справитесь с этим внутри модели? Не используйте слушателей, они предназначены для низкоуровневых моделей несвязанных действий, таких как, например, ведение журнала. Прекратите использовать модели анемичных доменов.

emix 20.09.2018 12:52
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Symfony Station Communiqué - 7 июля 2023 г
Symfony Station Communiqué - 7 июля 2023 г
Это коммюнике первоначально появилось на Symfony Station .
Оживление вашего приложения Laravel: Понимание режима обслуживания
Оживление вашего приложения Laravel: Понимание режима обслуживания
Здравствуйте, разработчики! В сегодняшней статье мы рассмотрим важный аспект управления приложениями, который часто упускается из виду в суете...
Установка и настройка Nginx и PHP на Ubuntu-сервере
Установка и настройка Nginx и PHP на Ubuntu-сервере
В этот раз я сделаю руководство по установке и настройке nginx и php на Ubuntu OS.
Коллекции в Laravel более простым способом
Коллекции в Laravel более простым способом
Привет, читатели, сегодня мы узнаем о коллекциях. В Laravel коллекции - это способ манипулировать массивами и играть с массивами данных. Благодаря...
Как установить PHP на Mac
Как установить PHP на Mac
PHP - это популярный язык программирования, который используется для разработки веб-приложений. Если вы используете Mac и хотите разрабатывать...
2
1
623
1

Ответы 1

Я бы рекомендовал вообще избегать прослушивателей событий Doctrine для этой задачи. Вместо этого все поведение должно быть смоделировано непосредственно в пользовательской сущности: метод setState () также может удерживать поведение для удаления задания (заданий).

Тогда обратите внимание на опцию сопоставления доктрины removeOrphans=true:

В основном это работает путем удаления Job из коллекции И установки его User на ноль. Doctrine обнаружит ваши потерянные задания из единицы работы и автоматически удалит их из базы данных при вызове persist($user); flush();.

Другие вопросы по теме