Skip to content

Commit 13060b8

Browse files
authored
Merge pull request #3345 from tvt/8.3
BUGFIX: Fix count for query across OneToMany joins
2 parents 6f3f5da + 42b1c9d commit 13060b8

File tree

2 files changed

+54
-0
lines changed

2 files changed

+54
-0
lines changed

Neos.Flow/Classes/Persistence/Doctrine/CountWalker.php

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
* with this package in the file License-BSD.txt. *
99
* */
1010

11+
use Doctrine\ORM\Mapping\ClassMetadataInfo;
1112
use Doctrine\ORM\Query\AST\AggregateExpression;
1213
use Doctrine\ORM\Query\AST\PathExpression;
1314
use Doctrine\ORM\Query\AST\SelectExpression;
@@ -40,6 +41,10 @@ public function walkSelectStatement(SelectStatement $AST)
4041
}
4142
}
4243

44+
if ($this->isDistinctRequired()) {
45+
$AST->selectClause->isDistinct = true;
46+
}
47+
4348
$pathExpression = new PathExpression(
4449
PathExpression::TYPE_STATE_FIELD | PathExpression::TYPE_SINGLE_VALUED_ASSOCIATION,
4550
$parentName,
@@ -57,4 +62,14 @@ public function walkSelectStatement(SelectStatement $AST)
5762
// ORDER BY is not needed, only increases query execution through unnecessary sorting.
5863
$AST->orderByClause = null;
5964
}
65+
66+
private function isDistinctRequired(): bool
67+
{
68+
foreach ($this->getQueryComponents() as $queryComponent) {
69+
if (isset($queryComponent['relation']['type']) && $queryComponent['relation']['type'] === ClassMetadataInfo::ONE_TO_MANY) {
70+
return true;
71+
}
72+
}
73+
return false;
74+
}
6075
}

Neos.Flow/Tests/Functional/Persistence/Doctrine/QueryTest.php

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -353,6 +353,45 @@ public function comlexQueryWithJoinsCanBeExecutedAfterDeserialization()
353353
self::assertEquals([$testEntity2], $unserializedQuery->execute()->toArray());
354354
}
355355

356+
/**
357+
* @test
358+
*/
359+
public function countReturnsCorrectNumberOfEntities()
360+
{
361+
$testEntityRepository = new \Neos\Flow\Tests\Functional\Persistence\Fixtures\TestEntityRepository();
362+
$testEntityRepository->removeAll();
363+
364+
$testEntity = new \Neos\Flow\Tests\Functional\Persistence\Fixtures\TestEntity;
365+
$testEntity->setName('Flow');
366+
367+
$subEntity1 = new \Neos\Flow\Tests\Functional\Persistence\Fixtures\SubEntity;
368+
$subEntity1->setContent('foo');
369+
$subEntity1->setParentEntity($testEntity);
370+
$testEntity->addSubEntity($subEntity1);
371+
$this->persistenceManager->add($subEntity1);
372+
373+
$subEntity2 = new \Neos\Flow\Tests\Functional\Persistence\Fixtures\SubEntity;
374+
$subEntity2->setContent('foo');
375+
$subEntity2->setParentEntity($testEntity);
376+
$testEntity->addSubEntity($subEntity2);
377+
$this->persistenceManager->add($subEntity2);
378+
379+
$testEntityRepository->add($testEntity);
380+
381+
$this->persistenceManager->persistAll();
382+
383+
$query = new Query(\Neos\Flow\Tests\Functional\Persistence\Fixtures\TestEntity::class);
384+
385+
$constraint = $query->logicalAnd($query->equals('subEntities.content', 'foo'));
386+
$result = $query->matching($constraint)->execute();
387+
388+
$count = $result->count();
389+
$arrayCount = $result->toArray();
390+
391+
self::assertEquals(1, count($arrayCount), 'This correctly returns 1');
392+
self::assertEquals(1, $count, 'this returns 2');
393+
}
394+
356395
protected function assertQueryEquals(Query $expected, Query $actual)
357396
{
358397
self::assertEquals($expected->getConstraint(), $actual->getConstraint());

0 commit comments

Comments
 (0)