Метод UnitOfWork->getOriginalEntityData возвращает новую сущности при связи OneToOne(всегда) и ManyToOne(при изменении связанной сущности)

Предисловие: столкнулся сразу с двумя проблемами связанными с получением данных сущностей/оригинальных данных в жизненном цикле Doctrine, а точнее в событии PreUpdate. Использовать фичи вроде EntityManager->detach и EntityManager->refrsh не могу, т.к. контекст вопроса - написание логгера для уже функционирующего приложения, эти же методы вызовут коллизии в дальнейшем и сложно контролируемое поведение.

Класс уже написан и вне слушателей жизненного цикла Doctrine работает для первой проблемы, вторая сохраняется.

Описание и вводный код:

1. Первая проблема.

Имеется две сущности, можно представить как User и Address, соответственно пользователь ссылается на свой уникальный адрес и имеют следующую связь:

// UserEntity
@ORM\OneToOne(targetEntity=Address::class, mappedBy="user", cascade={"persist", "remove"})

// AddressEntity
@ORM\OneToOne(targetEntity=User::class, inversedBy="address", cascade={"persist", "remove"})

Далее, я отслеживаю изменения с помощью прослушивать события для сущности User.

App\Event\Listeners\User\UserChangedListener:
    tags:
        -
            name: 'doctrine.orm.entity_listener'
            event: 'preUpdate'
            entity: 'App\Entity\User\User'
            method: 'UserChanged'
            lazy: true

Код прослушивателя:

public function userChanged(User $user)
{
    $campaignChanges = $this->getChangesOfEntityService->getEntityChanges($user);
    // далее, код нас не интересует, т.к. проблема в предыдущей строке
}

Код сервиса getChangesOfEntityService:

public function getEntityChanges($entity)
{
    $originalEntityData = $this->em->getUnitOfWork()->getOriginalEntityData($entity);
    // что-то происходит, но это не важно, т.к. интересует предыдущая строка

    var_dump($originalEntityData); // все нижеследующее будет относиться к этому дампу
}

В итоге, получаю следующее поведение:

  1. Вношу изменения в User, изменяю связанную сущность с AddressEntity(ID:1) на AddressEntity(ID:2).
  2. В дампе var_dump($originalEntityData); имеется ключ address и ожидается, что в нем будет сущность AddressEntity(ID:1), т.к. в комментариях к методу getOriginalEntityData сказано, что этот метод получает данные как на момент извлечения их из хранилища.
  3. В действительности же, в дампе var_dump($originalEntityData); уже лежит новая сущность, т.е. нет возможности получить оригинальную и сравнить, была ли она изменена.

2. Вторая проблема.

Имеется аналогично две сущности, однако связь уже ManyToOne от User к Location например.

// UserEntity
@ORM\ManyToOne(targetEntity=Location::class, mappedBy="user", cascade={"persist", "remove"})

// AddressEntity
@ORM\ManyToOne(targetEntity=User::class, inversedBy="location", cascade={"persist", "remove"})

Далее, код аналогичен первой проблеме.

Получаем такое поведение:

  1. Меняем сущность Location через setter для сущности User (user->setLocation(location(ID:2))), ранее была location(ID:1).
  2. В дампе var_dump($originalEntityData);, под ключем location будет все как положено, сущность location(ID:1). в. Однако, если дополнительно изменить саму сущность location, допустим так location->setName('changedLocationName') и повторить все действия, то в дампе var_dump($originalEntityData); будет новая сущность с ID=2, а не как в пункте б с ID=1. Соответственно ситуация похожая первой проблеме, когда через originalEntityData невозможно получить исходное значение свойства.

Собственно вопросы:

  1. С чем связанно данное поведение? (тут разумеется понятно, что с рекалькуляцией изменений самой Doctrin-ой и вызовом этих методов в слушателях ее жизненного цикла, но можно явно самому пересчитать эти изменения и результат будет совершенно иной (правильный, сказано в предисловии)).
  2. Как поправить, если возможно? (интересен конечный результат, но для понимая конечно бы пролить свет на эту загадку).

Ответы (0 шт):