Skip to content

Commit

Permalink
fix: always cleanup in AbstractHydrator::toIterable() (#11101)
Browse files Browse the repository at this point in the history
Previously it didn't cleanup anything as long as the iteration hasn't reached the final row.

Co-authored-by: Oleg Andreyev <oleg.andreyev@lampa.lv>
  • Loading branch information
simPod and oleg-andreyev committed Apr 25, 2024
1 parent 306963f commit cbec236
Show file tree
Hide file tree
Showing 2 changed files with 48 additions and 16 deletions.
34 changes: 18 additions & 16 deletions src/Internal/Hydration/AbstractHydrator.php
Expand Up @@ -182,29 +182,31 @@ public function toIterable($stmt, ResultSetMapping $resultSetMapping, array $hin

$this->prepare();

while (true) {
$row = $this->statement()->fetchAssociative();

if ($row === false) {
$this->cleanup();
try {
while (true) {
$row = $this->statement()->fetchAssociative();

break;
}
if ($row === false) {
break;
}

$result = [];
$result = [];

$this->hydrateRowData($row, $result);
$this->hydrateRowData($row, $result);

$this->cleanupAfterRowIteration();
if (count($result) === 1) {
if (count($resultSetMapping->indexByMap) === 0) {
yield end($result);
$this->cleanupAfterRowIteration();
if (count($result) === 1) {
if (count($resultSetMapping->indexByMap) === 0) {
yield end($result);
} else {
yield from $result;
}
} else {
yield from $result;
yield $result;
}
} else {
yield $result;
}
} finally {
$this->cleanup();
}
}

Expand Down
30 changes: 30 additions & 0 deletions tests/Tests/ORM/Hydration/AbstractHydratorTest.php
Expand Up @@ -12,6 +12,7 @@
use Doctrine\ORM\Internal\Hydration\AbstractHydrator;
use Doctrine\ORM\ORMException;
use Doctrine\ORM\Query\ResultSetMapping;
use Doctrine\Tests\Models\Hydration\SimpleEntity;
use Doctrine\Tests\OrmFunctionalTestCase;
use PHPUnit\Framework\MockObject\MockObject;

Expand Down Expand Up @@ -154,4 +155,33 @@ public function testHydrateAllClearsAllAttachedListenersEvenOnError(): void
$this->expectException(ORMException::class);
$this->hydrator->hydrateAll($this->mockResult, $this->mockResultMapping);
}

public function testToIterableIfYieldAndBreakBeforeFinishAlwaysCleansUp(): void
{
$this->setUpEntitySchema([SimpleEntity::class]);

$entity1 = new SimpleEntity();
$this->_em->persist($entity1);
$entity2 = new SimpleEntity();
$this->_em->persist($entity2);

$this->_em->flush();
$this->_em->clear();

$evm = $this->_em->getEventManager();

$q = $this->_em->createQuery('SELECT e.id FROM ' . SimpleEntity::class . ' e');

// select two entities, but do no iterate
$q->toIterable();
self::assertCount(0, $evm->getListeners(Events::onClear));

// select two entities, but abort after first record
foreach ($q->toIterable() as $result) {
self::assertCount(1, $evm->getListeners(Events::onClear));
break;
}

self::assertCount(0, $evm->getListeners(Events::onClear));
}
}

0 comments on commit cbec236

Please sign in to comment.