Я немного запутался в том, как обновить связанную коллекцию с помощью событий доктрины.
Один объект связан с другим через 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;
...
}






Я бы рекомендовал вообще избегать прослушивателей событий Doctrine для этой задачи. Вместо этого все поведение должно быть смоделировано непосредственно в пользовательской сущности: метод setState () также может удерживать поведение для удаления задания (заданий).
Тогда обратите внимание на опцию сопоставления доктрины removeOrphans=true:
В основном это работает путем удаления Job из коллекции И установки его User на ноль. Doctrine обнаружит ваши потерянные задания из единицы работы и автоматически удалит их из базы данных при вызове persist($user); flush();.
Почему вы не справитесь с этим внутри модели? Не используйте слушателей, они предназначены для низкоуровневых моделей несвязанных действий, таких как, например, ведение журнала. Прекратите использовать модели анемичных доменов.