Persisting other entities inside preUpdate of Doctrine Entity Listener

后端 未结 4 1961
忘掉有多难
忘掉有多难 2020-12-09 16:44

For clarity I continue here the discussion started here.

Inside a Doctrine Entity Listener, in the preUpdate method (where I have access to both the old and new val

4条回答
  •  小蘑菇
    小蘑菇 (楼主)
    2020-12-09 16:50

    Using an Lifecycle Listener instead of an EntityListener might be better suited in this case (I find that the symfony docs provide a better overview over the different options). This is due to onFlush, a very powerful event, not being available for EntityListeners. This event is invoked after all changesets are computed and before the database actions are executed.

    In this answer I explore the options using an Entity Listener.

    Using preUpdate: This event provides a PreUpdateEventArgs which makes it easy to find all values that are going to be changed. However this event is triggered within UnitOfWork#commit, after the inserts have been processed. Hence there is now no possibility to add a new entity to be persisted within current transaction.

    Using preFlush: This event occurs at the beginning of a flush operation. Changesets might not yet be available, but we can compare the original values with the current ones. This approach might not be suitable when there are many changes that are needed. Here is an example implementation:

        public function preFlush(Order $order, PreFlushEventArgs $eventArgs)
        {
            // Create a log entry when the state was changed
            $entityManager = $eventArgs->getEntityManager();
            $unitOfWork = $entityManager->getUnitOfWork();
            $originalEntityData = $unitOfWork->getOriginalEntityData($order);
            $newState = $order->getState();
            if (empty($originalEntityData)) {
                // We're dealing with a new order
                $oldState = "";
            } else {
                $stateProperty = 'state';
                $oldState = $originalEntityData[$stateProperty];
                // Same behavior as in \Doctrine\ORM\UnitOfWork:720: Existing
                // changeset is ignored when the property was changed
                $entityChangeSet = $unitOfWork->getEntityChangeSet($order);
                $stateChanges = $entityChangeSet[$stateProperty] ?? [];
                if ($oldState == $newState && $stateChanges) {
                    $oldState = $stateChanges[0] ?? "";
                    $newState = $stateChanges[1] ?? "";
                }
            }
            if ($oldState != $newState) {
                $statusLog = $this->createOrderStatusLog($order, $oldState, $newState);
                $unitOfWork->scheduleForInsert($statusLog);
                $unitOfWork->computeChangeSet($entityManager->getClassMetadata('App\Entity\OrderStatusLog'), $statusLog);
            }
        }
    

    Using postFlush/postUpdate: Using these events would lead to a second database transaction, which is undesirable.

提交回复
热议问题