Skip to content

Commit 2b921c6

Browse files
committed
fix(mongodb): enhance ExactFilter and IriFilter to better handle relations
1 parent da4c493 commit 2b921c6

File tree

2 files changed

+80
-7
lines changed

2 files changed

+80
-7
lines changed

src/Doctrine/Odm/Filter/ExactFilter.php

Lines changed: 52 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,33 +13,80 @@
1313

1414
namespace ApiPlatform\Doctrine\Odm\Filter;
1515

16+
use ApiPlatform\Doctrine\Common\Filter\ManagerRegistryAwareInterface;
17+
use ApiPlatform\Doctrine\Common\Filter\ManagerRegistryAwareTrait;
1618
use ApiPlatform\Doctrine\Common\Filter\OpenApiFilterTrait;
1719
use ApiPlatform\Metadata\BackwardCompatibleFilterDescriptionTrait;
1820
use ApiPlatform\Metadata\OpenApiParameterFilterInterface;
1921
use ApiPlatform\Metadata\Operation;
2022
use Doctrine\ODM\MongoDB\Aggregation\Builder;
23+
use Doctrine\ODM\MongoDB\DocumentManager;
24+
use Doctrine\ODM\MongoDB\LockException;
25+
use Doctrine\ODM\MongoDB\Mapping\MappingException;
2126

2227
/**
2328
* @author Vincent Amstoutz <[email protected]>
2429
*/
25-
final class ExactFilter implements FilterInterface, OpenApiParameterFilterInterface
30+
final class ExactFilter implements FilterInterface, OpenApiParameterFilterInterface, ManagerRegistryAwareInterface
2631
{
2732
use BackwardCompatibleFilterDescriptionTrait;
33+
use ManagerRegistryAwareTrait;
2834
use OpenApiFilterTrait;
2935

36+
/**
37+
* @throws MappingException
38+
* @throws LockException
39+
*/
3040
public function apply(Builder $aggregationBuilder, string $resourceClass, ?Operation $operation = null, array &$context = []): void
3141
{
3242
$parameter = $context['parameter'];
3343
$property = $parameter->getProperty();
34-
3544
$value = $parameter->getValue();
36-
if (is_numeric($value)) {
37-
$property .= '.id';
45+
46+
$documentManager = $this->getManagerRegistry()?->getManagerForClass($resourceClass);
47+
if (!$documentManager instanceof DocumentManager) {
48+
return;
49+
}
50+
51+
$classMetadata = $documentManager->getClassMetadata($resourceClass);
52+
53+
if (!$classMetadata->hasReference($property)) {
54+
$aggregationBuilder
55+
->match()
56+
->field($property)
57+
->{is_iterable($value) ? 'in' : 'equals'}($value);
58+
59+
return;
3860
}
3961

62+
$mapping = $classMetadata->getFieldMapping($property);
63+
$targetDocument = $mapping['targetDocument'];
64+
$repository = $documentManager->getRepository($targetDocument);
65+
$method = $classMetadata->isCollectionValuedAssociation($property) ? 'includesReferenceTo' : 'references';
66+
67+
if (is_iterable($value)) {
68+
$documents = [];
69+
foreach ($value as $v) {
70+
if ($doc = $repository->find($v)) {
71+
$documents[] = $doc;
72+
}
73+
}
74+
75+
$match = $aggregationBuilder->match();
76+
$or = $match->expr();
77+
foreach ($documents as $doc) {
78+
$or->addOr($match->expr()->field($property)->{$method}($doc));
79+
}
80+
$match->addAnd($or);
81+
82+
return;
83+
}
84+
85+
$referencedDoc = $repository->find($value);
86+
4087
$aggregationBuilder
4188
->match()
4289
->field($property)
43-
->{(is_iterable($value)) ? 'in' : 'equals'}($value);
90+
->{$method}($referencedDoc);
4491
}
4592
}

src/Doctrine/Odm/Filter/IriFilter.php

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
use ApiPlatform\State\ParameterProvider\IriConverterParameterProvider;
2424
use Doctrine\ODM\MongoDB\Aggregation\Builder;
2525
use Doctrine\ODM\MongoDB\DocumentManager;
26+
use Symfony\Component\PropertyAccess\PropertyAccess;
2627

2728
/**
2829
* @author Vincent Amstoutz <[email protected]>
@@ -40,17 +41,42 @@ public function apply(Builder $aggregationBuilder, string $resourceClass, ?Opera
4041
$value = $parameter->getValue();
4142

4243
$documentManager = $this->getManagerRegistry()?->getManagerForClass($resourceClass);
43-
4444
if (!$documentManager instanceof DocumentManager) {
4545
return;
4646
}
4747

4848
$classMetadata = $documentManager->getClassMetadata($resourceClass);
49-
5049
if (!$classMetadata->hasReference($property)) {
5150
return;
5251
}
5352

53+
$mapping = $classMetadata->getFieldMapping($property);
54+
55+
if (isset($mapping['mappedBy'])) {
56+
$propertyAccessor = PropertyAccess::createPropertyAccessor();
57+
$mappedByProperty = $mapping['mappedBy'];
58+
$identifier = '_id';
59+
60+
if (is_iterable($value)) {
61+
$ids = [];
62+
foreach ($value as $v) {
63+
if ($relatedDoc = $propertyAccessor->getValue($v, $mappedByProperty)) {
64+
$ids[] = $propertyAccessor->getValue($relatedDoc, 'id');
65+
}
66+
}
67+
68+
$aggregationBuilder->match()->field($identifier)->in($ids);
69+
70+
return;
71+
}
72+
73+
if ($relatedDoc = $propertyAccessor->getValue($value, $mappedByProperty)) {
74+
$aggregationBuilder->match()->field($identifier)->equals($propertyAccessor->getValue($relatedDoc, 'id'));
75+
}
76+
77+
return;
78+
}
79+
5480
$method = $classMetadata->isCollectionValuedAssociation($property) ? 'includesReferenceTo' : 'references';
5581

5682
if (is_iterable($value)) {

0 commit comments

Comments
 (0)