Symfony, event listener, checker. Как использовать несколько event listener для одного entity
Есть один entity и 2 event listener для него, когда обновляется поле, checker проверяет изменилось ли поле и дальше отрабатывает логика. Проблема в том что listener блокирует второй listener, в итоге в втором listener не работает checker на изменение (говорит что поле не менялось) хотя в базе изменения есть.
public function postUpdate(LifecycleEventArgs $eventArgs): void
{
$entity = $eventArgs->getObject();
if ($entity instance of Group) {
$changedFields = $eventArgs->getEntityManager()->getUnitOfWork()->getEntityChangeSet($entity);
$isChanged = $this->checker->isChanged($changedFields, ['teacher']);
if ($isChanged) {
$this->proceedTeacherChanges($entity);
}
Ответы (1 шт):
При заходе в Listener, Doctrine пересчитывает все изменения, т.е. делает за вас это действие EntityManager->getUnitOfWork->computeChangesSet. Этот момент важен, т.к. под капотом, она перетирает массив с данными originalEntityData, на основе которого в основном и проводит все дальнейшие проверки, вроде isChanged и т.д.
В вашем случае, происходит следующее:
- Doctrine поняла, что вы идете в Listener ее жизненного цикла и делает EntityManager->getUnitOfWork->computeChangesSet, в результате чего перетирает originalEntityData, тем самым фиксируя состояние ваших сущностей.
- Заход в первый Listener.
- Изменения есть, вы можете их проверить.
- Doctrine аналогично понимает, что вы заходите в еще один Listener ее жизненного цикла и точно так же делает перерасчет изменений, но в первом слушателе, вы не внесли никаких изменений и получается, она проверяет зафиксированное, уже рассчитанное состояние с текущими сущностями, естественно diff-а у нее нет и изменений из предыдущего слушателя, она не увидит.
Это происходит как раз из-за оного массива данных originalEntityData, во время перерасчета она его обновляет до состояния сущностей и при повторном перерасчете, не увидит из-за этого изменений.
Зачастую в документации сказано, что не нужно самому перерассчитывать changesSet в Listener-ах, т.к. он считается автоматически, а в вашем случае получается, что вы заставляете Doctrine посчитать его два раза (что именно не рекомендуется) по средствам двойной подписки.