Skip to content

Commit 61e1b9a

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

File tree

2 files changed

+85
-8
lines changed

2 files changed

+85
-8
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: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@
2323
use ApiPlatform\State\ParameterProvider\IriConverterParameterProvider;
2424
use Doctrine\ODM\MongoDB\Aggregation\Builder;
2525
use Doctrine\ODM\MongoDB\DocumentManager;
26+
use Doctrine\ODM\MongoDB\Mapping\MappingException;
27+
use Symfony\Component\PropertyAccess\PropertyAccess;
2628

2729
/**
2830
* @author Vincent Amstoutz <[email protected]>
@@ -33,24 +35,52 @@ final class IriFilter implements FilterInterface, OpenApiParameterFilterInterfac
3335
use ManagerRegistryAwareTrait;
3436
use OpenApiFilterTrait;
3537

38+
/**
39+
* @throws MappingException
40+
*/
3641
public function apply(Builder $aggregationBuilder, string $resourceClass, ?Operation $operation = null, array &$context = []): void
3742
{
3843
$parameter = $context['parameter'];
3944
$property = $parameter->getProperty();
4045
$value = $parameter->getValue();
4146

42-
$documentManager = $this->getManagerRegistry()?->getManagerForClass($resourceClass);
43-
47+
$documentManager = $this->getManagerRegistry()->getManagerForClass($resourceClass);
4448
if (!$documentManager instanceof DocumentManager) {
4549
return;
4650
}
4751

4852
$classMetadata = $documentManager->getClassMetadata($resourceClass);
49-
5053
if (!$classMetadata->hasReference($property)) {
5154
return;
5255
}
5356

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

5686
if (is_iterable($value)) {

0 commit comments

Comments
 (0)