diff --git a/src/Doctrine/Orm/Filter/IriFilter.php b/src/Doctrine/Orm/Filter/IriFilter.php index 5b8bde7ce5..b27558ff2c 100644 --- a/src/Doctrine/Orm/Filter/IriFilter.php +++ b/src/Doctrine/Orm/Filter/IriFilter.php @@ -24,6 +24,7 @@ use ApiPlatform\State\ParameterProvider\IriConverterParameterProvider; use Doctrine\ORM\Mapping\ClassMetadata; use Doctrine\ORM\Mapping\FieldMapping; +use Doctrine\ORM\Query\Expr\Join; use Doctrine\ORM\QueryBuilder; /** @@ -68,7 +69,11 @@ public function apply(QueryBuilder $queryBuilder, QueryNameGeneratorInterface $q // Collection associations (OneToMany/ManyToMany) require a JOIN to compare individual elements. if ($ormLeafMetadata['is_collection_valued']) { - $queryBuilder->join(\sprintf('%s.%s', $alias, $property), $parameterName); + if (Join::LEFT_JOIN === $this->joinTypeFor($context)) { + $queryBuilder->leftJoin(\sprintf('%s.%s', $alias, $property), $parameterName); + } else { + $queryBuilder->innerJoin(\sprintf('%s.%s', $alias, $property), $parameterName); + } if (is_iterable($value)) { $queryBuilder diff --git a/src/Doctrine/Orm/Tests/Filter/NestedPropertyJoinTypeTest.php b/src/Doctrine/Orm/Tests/Filter/NestedPropertyJoinTypeTest.php index 20cb7432c4..6d9ead76b2 100644 --- a/src/Doctrine/Orm/Tests/Filter/NestedPropertyJoinTypeTest.php +++ b/src/Doctrine/Orm/Tests/Filter/NestedPropertyJoinTypeTest.php @@ -15,10 +15,12 @@ use ApiPlatform\Doctrine\Orm\Filter\EndSearchFilter; use ApiPlatform\Doctrine\Orm\Filter\FilterInterface; +use ApiPlatform\Doctrine\Orm\Filter\IriFilter; use ApiPlatform\Doctrine\Orm\Filter\PartialSearchFilter; use ApiPlatform\Doctrine\Orm\Filter\StartSearchFilter; use ApiPlatform\Doctrine\Orm\Filter\WordStartSearchFilter; use ApiPlatform\Doctrine\Orm\Tests\Fixtures\Entity\Dummy; +use ApiPlatform\Doctrine\Orm\Tests\Fixtures\Entity\RelatedDummy; use ApiPlatform\Doctrine\Orm\Util\QueryNameGenerator; use ApiPlatform\Metadata\QueryParameter; use Doctrine\ORM\EntityManagerInterface; @@ -54,6 +56,33 @@ public function testNestedJoinTypeDependsOnWhereClause(string $whereClause, stri $this->assertStringNotContainsString($unexpectedJoin, $dql); } + #[DataProvider('provideWhereClauses')] + public function testIriFilterCollectionJoinTypeDependsOnWhereClause(string $whereClause, string $expectedJoin, string $unexpectedJoin): void + { + $entityManager = $this->createStub(EntityManagerInterface::class); + $queryBuilder = (new QueryBuilder($entityManager))->select('o')->from(Dummy::class, 'o'); + $parameter = (new QueryParameter(key: 'relatedDummies', property: 'relatedDummies')) + ->withExtraProperties([ + '_api_values' => 'x', + 'nested_properties_info' => ['relatedDummies' => [ + 'relation_classes' => [], + 'converted_relation_segments' => [], + 'leaf_property' => 'relatedDummies', + 'orm_leaf_metadata' => [ + 'is_collection_valued' => true, + 'association_target_class' => RelatedDummy::class, + 'identifier_type' => null, + ], + ]], + ]); + + (new IriFilter())->apply($queryBuilder, new QueryNameGenerator(), Dummy::class, null, ['parameter' => $parameter, 'whereClause' => $whereClause]); + + $dql = $queryBuilder->getDQL(); + $this->assertStringContainsString($expectedJoin.' o.relatedDummies', $dql); + $this->assertStringNotContainsString($unexpectedJoin, $dql); + } + /** * @return iterable */