Skip to content

Commit

Permalink
[doctrineGH-8413] Bugfix: Iterating with multiple, mixed results
Browse files Browse the repository at this point in the history
When multiple entity results are part of a row, the result handling
must be different. In addition mixed results with scalars are broken
and now throw an exception as illegal operation.
  • Loading branch information
beberlei committed Feb 8, 2021
1 parent d6b5d70 commit e53aa9c
Show file tree
Hide file tree
Showing 5 changed files with 61 additions and 3 deletions.
6 changes: 6 additions & 0 deletions lib/Doctrine/ORM/AbstractQuery.php
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
use Doctrine\ORM\Internal\Hydration\IterableResult;
use Doctrine\ORM\Mapping\MappingException as ORMMappingException;
use Doctrine\ORM\Query\Parameter;
use Doctrine\ORM\Query\QueryException;
use Doctrine\ORM\Query\ResultSetMapping;
use Doctrine\Persistence\Mapping\MappingException;
use Traversable;
Expand Down Expand Up @@ -999,6 +1000,11 @@ public function toIterable(iterable $parameters = [], $hydrationMode = null): it
}

$rsm = $this->getResultSetMapping();

if ($rsm->isMixed && count($rsm->scalarMappings) > 0) {
throw QueryException::iterateWithMixedResultNotAllowed();
}

$stmt = $this->_doExecute();

return $this->_em->newHydrator($this->_hydrationMode)->toIterable($stmt, $rsm, $this->_hints);
Expand Down
6 changes: 5 additions & 1 deletion lib/Doctrine/ORM/Internal/Hydration/AbstractHydrator.php
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,11 @@ public function toIterable(Statement $stmt, ResultSetMapping $resultSetMapping,

$this->cleanupAfterRowIteration();

yield end($result);
if (count($result) === 1) {
yield end($result);
} else {
yield $result;
}
}
}

Expand Down
5 changes: 5 additions & 0 deletions lib/Doctrine/ORM/Query/QueryException.php
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,11 @@ public static function iterateWithFetchJoinNotAllowed($assoc)
);
}

public static function iterateWithMixedResultNotAllowed(): QueryException
{
return new self('Iterating a query with mixed results (using scalars) is not supported.');
}

/**
* @return QueryException
*/
Expand Down
2 changes: 0 additions & 2 deletions tests/Doctrine/Tests/ORM/Functional/AdvancedDqlQueryTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -171,8 +171,6 @@ public function testSelectSubselect(): void
$this->assertEquals('Caramba', $result[0]['brandName']);

$this->_em->clear();

IterableTester::assertResultsAreTheSame($query);
}

public function testInSubselect(): void
Expand Down
45 changes: 45 additions & 0 deletions tests/Doctrine/Tests/ORM/Functional/QueryTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -301,6 +301,51 @@ public function testIterateResult_IterativelyBuildUpUnitOfWork(): void
self::assertSame(2, $iteratedCount);
}

public function testToIterableWithMultipleSelectElements(): void
{
$author = new CmsUser();
$author->name = 'Ben';
$author->username = 'beberlei';

$article1 = new CmsArticle();
$article1->topic = 'Doctrine 2';
$article1->text = 'This is an introduction to Doctrine 2.';
$article1->setAuthor($author);

$article2 = new CmsArticle();
$article2->topic = 'Symfony 2';
$article2->text = 'This is an introduction to Symfony 2.';
$article2->setAuthor($author);

$this->_em->persist($article1);
$this->_em->persist($article2);
$this->_em->persist($author);

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

$query = $this->_em->createQuery('select a, u from ' . CmsArticle::class . ' a JOIN ' . CmsUser::class . ' u WITH a.user = u');

$result = iterator_to_array($query->toIterable());

$this->assertCount(2, $result);

foreach ($result as $row) {
$this->assertCount(2, $row);
$this->assertInstanceOf(CmsArticle::class, $row[0]);
$this->assertInstanceOf(CmsUser::class, $row[1]);
}
}

public function testToIterableWithMixedResultIsNotAllowed(): void
{
$this->expectException(QueryException::class);
$this->expectExceptionMessage('Iterating a query with mixed results (using scalars) is not supported.');

$query = $this->_em->createQuery('select a, a.topic from ' . CmsArticle::class . ' a');
$query->toIterable();
}

public function testIterateResultClearEveryCycle(): void
{
$article1 = new CmsArticle();
Expand Down

0 comments on commit e53aa9c

Please sign in to comment.