From d781eb328a345a680f9790c345337a2cb97b1109 Mon Sep 17 00:00:00 2001 From: Jan Skrasek Date: Sun, 13 Sep 2020 22:37:49 +0200 Subject: [PATCH] relationships: fix counting 1:M table with composite primary key --- .../Dbal/RelationshipMapperOneHasMany.php | 20 ++++++++++++++++--- .../relationships.oneHasMany.phpt | 16 +++++++++++++++ 2 files changed, 33 insertions(+), 3 deletions(-) diff --git a/src/Mapper/Dbal/RelationshipMapperOneHasMany.php b/src/Mapper/Dbal/RelationshipMapperOneHasMany.php index 0418c29f..8a13b2e8 100644 --- a/src/Mapper/Dbal/RelationshipMapperOneHasMany.php +++ b/src/Mapper/Dbal/RelationshipMapperOneHasMany.php @@ -17,6 +17,7 @@ use Nextras\Orm\Entity\IEntityHasPreloadContainer; use Nextras\Orm\Entity\Reflection\PropertyMetadata; use Nextras\Orm\Entity\Reflection\PropertyRelationshipMetadata; +use Nextras\Orm\InvalidStateException; use Nextras\Orm\Mapper\IRelationshipMapper; @@ -218,7 +219,6 @@ protected function executeCounts(DbalCollection $collection, IEntity $parent) private function fetchCounts(QueryBuilder $builder, array $values) { - $targetStoragePrimaryKey = $this->targetMapper->getStorageReflection()->getStoragePrimaryKey()[0]; $sourceTable = $builder->getFromAlias(); $builder = clone $builder; @@ -228,10 +228,24 @@ private function fetchCounts(QueryBuilder $builder, array $values) $result = $this->processMultiCountResult($builder, $values); } else { - $builder->orderBy(null); - $builder->addSelect('COUNT(DISTINCT %column) AS [count]', "{$sourceTable}.{$targetStoragePrimaryKey}"); + $targetStoragePrimaryKeys = $this->targetMapper->getStorageReflection()->getStoragePrimaryKey(); + $targetColumn = null; + foreach ($targetStoragePrimaryKeys as $targetStoragePrimaryKey) { + if ($targetStoragePrimaryKey === $this->joinStorageKey) { + continue; + } + $targetColumn = "$sourceTable.$targetStoragePrimaryKey"; + break; + } + + if ($targetColumn === null) { + throw new InvalidStateException('Unable to detect column for count query.'); + } + + $builder->addSelect('COUNT(DISTINCT %column) AS [count]', $targetColumn); $builder->andWhere('%column IN %any', "{$sourceTable}.{$this->joinStorageKey}", $values); $builder->groupBy('%column', "{$sourceTable}.{$this->joinStorageKey}"); + $builder->orderBy(null); $result = $this->connection->queryArgs($builder->getQuerySql(), $builder->getQueryParameters()); } diff --git a/tests/cases/integration/Relationships/relationships.oneHasMany.phpt b/tests/cases/integration/Relationships/relationships.oneHasMany.phpt index 264ab51f..df6bf39d 100644 --- a/tests/cases/integration/Relationships/relationships.oneHasMany.phpt +++ b/tests/cases/integration/Relationships/relationships.oneHasMany.phpt @@ -48,6 +48,22 @@ class RelationshipOneHasManyTest extends DataTestCase } + public function testCountOnCompositePkInTargetTable() + { + // add another tag to have >1 tags followers for tag#2 + $tag = $this->orm->tags->getById(1); + $author = $this->orm->authors->getById(2); + $tagFollower = new TagFollower(); + $tagFollower->author = $author; + $tagFollower->tag = $tag; + $this->orm->persistAndFlush($tagFollower); + $this->orm->clear(); + + $tag = $this->orm->tags->getById(1); + Assert::same(2, $tag->tagFollowers->countStored()); + } + + public function testWithDifferentPrimaryKey() { $publisher = $this->orm->publishers->getById(1);