Для ясности продолжу здесь обсуждение началось здесь.
Внутри Doctrine Entity Listener, в методе preUpdate (где у меня есть доступ как к старому, так и к новому значению любого поля сущности), я пытаюсь сохранить сущность, не связанную с основной.
По сути, у меня есть сущность A, и когда я изменяю значение в одном из полей, которые я хочу записать, в таблице project_notification, поля oldValue, newValue плюс другие.
Если я не сбрасываю содержимое в методе preUpdate, новый объект уведомления не сохраняется в БД. Если я промою это, я войду в бесконечный цикл.
Это метод preUpdate:
public function preUpdate(ProjectTolerances $tolerances, PreUpdateEventArgs $event)
{
if ($event->hasChangedField('riskToleranceFlag')) {
$project = $tolerances->getProject();
$em = $event->getEntityManager();
$notification = new ProjectNotification();
$notification->setValueFrom($event->getOldValue('riskToleranceFlag'));
$notification->setValueTo($event->getNewValue('riskToleranceFlag'));
$notification->setEntity('Entity'); //TODO substitute with the real one
$notification->setField('riskToleranceFlag');
$notification->setProject($project);
$em->persist($notification);
// $em->flush(); // gives infinite loop
}
}
Погуглив немного, я обнаружил, что вы не можете вызвать сброс в слушателях, и здесь он предложил сохранить материал, который будет сохранен в массиве, чтобы сбросить его позже в onFlush. Тем не менее, он не работает (и, вероятно, не должен работать, так как экземпляр класса слушателя уничтожается после вызова preUpdate, поэтому все, что вы храните в качестве защищенного атрибута на уровне класса, теряется при последующем вызове onFlush или я что-то упустил?).
Вот обновленная версия слушателя:
class ProjectTolerancesListener
{
protected $toBePersisted = [];
public function preUpdate(ProjectTolerances $tolerances, PreUpdateEventArgs $event)
{
$uow = $event->getEntityManager()->getUnitOfWork();
// $hasChanged = false;
if ($event->hasChangedField('riskToleranceFlag')) {
$project = $tolerances->getProject();
$notification = new ProjectNotification();
$notification->setValueFrom($event->getOldValue('riskToleranceFlag'));
$notification->setValueTo($event->getNewValue('riskToleranceFlag'));
$notification->setEntity('Entity'); //TODO substitute with the real one
$notification->setField('riskToleranceFlag');
$notification->setProject($project);
if(!empty($this->toBePersisted))
{
array_push($toBePersisted, $notification);
}
else
{
$toBePersisted[0] = $notification;
}
}
}
public function postFlush(LifecycleEventArgs $event)
{
if(!empty($this->toBePersisted)) {
$em = $event->getEntityManager();
foreach ($this->toBePersisted as $element) {
$em->persist($element);
}
$this->toBePersisted = [];
$em->flush();
}
}
}
Возможно, я могу решить эту проблему, запустив событие из слушателя со всей необходимой информацией для выполнения моих операций регистрации после сброса... но:
1) я не знаю, смогу ли я это сделать
2) кажется немного излишним
Спасибо!