Skip to content

Commit

Permalink
Defer dispatching postInsert events until all inserts have been exe…
Browse files Browse the repository at this point in the history
…cuted
  • Loading branch information
mpdude committed Aug 17, 2023
1 parent 1895cf8 commit b66c3b4
Showing 1 changed file with 12 additions and 22 deletions.
34 changes: 12 additions & 22 deletions lib/Doctrine/ORM/UnitOfWork.php
Original file line number Diff line number Diff line change
Expand Up @@ -1165,31 +1165,12 @@ public function recomputeSingleEntityChangeSet(ClassMetadata $class, $entity)
private function executeInserts(): void
{
$entities = $this->computeInsertExecutionOrder();

Check failure on line 1167 in lib/Doctrine/ORM/UnitOfWork.php

View workflow job for this annotation

GitHub Actions / coding-standards / Coding Standards (8.2)

Equals sign not aligned with surrounding assignments; expected 9 spaces but found 1 space
$eventsToDispatch = [];

foreach ($entities as $entity) {
$oid = spl_object_id($entity);

// Mitigation for GH-10869:
// Users may use postPersist and similar listeners to make entity updates and call
// EM::flush() -> UoW::commit() again, while a transaction is currently running.
// This "somehow" worked pre 2.16, although it was never officially endorsed and/or
// is disputed (and there is no guarantee that the UoW will be able to deal with this,
// does not lose updates etc.).
// https://github.com/doctrine/orm/pull/10900 is a discussion about deprecating this
// kind of reentrance and disallowing it in 3.0.
//
// However, to ease the pain somewhat for users in 2.16, this condition covers that
// a reentrant call into UoW::commit() may have processed pending insertions that we
// had in our computed insertion order. So, after the second (inner) commit() returned
// and the outer one continues, deal with the situation that entities are no longer in
// the set of pending insertions.
if (! isset($this->entityInsertions[$oid])) {
continue;
}

$oid = spl_object_id($entity);
$class = $this->em->getClassMetadata(get_class($entity));
$persister = $this->getEntityPersister($class->name);
$invoke = $this->listenersInvoker->getSubscribedSystems($class, Events::postPersist);

$persister->addInsert($entity);

Expand All @@ -1216,10 +1197,19 @@ private function executeInserts(): void
$this->addToEntityIdentifiersAndEntityMap($class, $oid, $entity);
}

$invoke = $this->listenersInvoker->getSubscribedSystems($class, Events::postPersist);

if ($invoke !== ListenersInvoker::INVOKE_NONE) {
$this->listenersInvoker->invoke($class, Events::postPersist, $entity, new PostPersistEventArgs($entity, $this->em), $invoke);
$eventsToDispatch[] = ['class' => $class, 'entity' => $entity, 'invoke' => $invoke];
}
}

// Mitigation for GH-10869:
// Defer dispatching `postPersist` events to until all entities have been inserted and there
// are no pending insertions left.
foreach ($eventsToDispatch as $event) {
$this->listenersInvoker->invoke($event['class'], Events::postPersist, $event['entity'], new PostPersistEventArgs($event['entity'], $this->em), $event['invoke']);
}
}

/**
Expand Down

0 comments on commit b66c3b4

Please sign in to comment.