Skip to content

Commit 062bf2a

Browse files
committed
Introduce AtlasSearchFilter
1 parent c9692b5 commit 062bf2a

File tree

2 files changed

+104
-1
lines changed

2 files changed

+104
-1
lines changed

src/Doctrine/Odm/Extension/ParameterExtension.php

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ private function applyFilter(Builder $aggregationBuilder, ?string $resourceClass
8989
$filter->setProperties($properties ?? []);
9090
}
9191

92-
$filterContext = ['filters' => $values, 'parameter' => $parameter, 'match' => $context['match'] ?? null];
92+
$filterContext = ['filters' => $values, 'parameter' => $parameter, 'match' => $context['match'] ?? null, 'search' => $context['search'] ?? null];
9393
$filter->apply($aggregationBuilder, $resourceClass, $operation, $filterContext);
9494
// update by reference
9595
if (isset($filterContext['mongodb_odm_sort_fields'])) {
@@ -98,6 +98,9 @@ private function applyFilter(Builder $aggregationBuilder, ?string $resourceClass
9898
if (isset($filterContext['match'])) {
9999
$context['match'] = $filterContext['match'];
100100
}
101+
if (isset($filterContext['search'])) {
102+
$context['search'] = $filterContext['search'];
103+
}
101104
}
102105

103106
if (isset($context['match'])) {
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace ApiPlatform\Doctrine\Odm\Filter;
6+
7+
use ApiPlatform\Doctrine\Common\Filter\ManagerRegistryAwareInterface;
8+
use ApiPlatform\Doctrine\Common\Filter\ManagerRegistryAwareTrait;
9+
use ApiPlatform\Doctrine\Common\Filter\OpenApiFilterTrait;
10+
use ApiPlatform\Metadata\BackwardCompatibleFilterDescriptionTrait;
11+
use ApiPlatform\Metadata\OpenApiParameterFilterInterface;
12+
use ApiPlatform\Metadata\Operation;
13+
use Doctrine\ODM\MongoDB\Aggregation\Builder;
14+
use Doctrine\ODM\MongoDB\LockException;
15+
use Doctrine\ODM\MongoDB\Mapping\MappingException;
16+
17+
/**
18+
* @author Jérôme Tamarelle <jerome@tamarelle.net>
19+
*/
20+
final class AtlasSearchFilter implements FilterInterface, OpenApiParameterFilterInterface, ManagerRegistryAwareInterface
21+
{
22+
use BackwardCompatibleFilterDescriptionTrait;
23+
use ManagerRegistryAwareTrait;
24+
use OpenApiFilterTrait;
25+
26+
/**
27+
* @see https://www.mongodb.com/docs/atlas/atlas-search/compound/
28+
*
29+
* @param string $term The term to use in the Atlas Search query (must, mustNot, should, filter). Default to "must".
30+
*/
31+
public function __construct(
32+
private readonly string $index = 'default',
33+
private readonly string $operator = 'text',
34+
private readonly string $term = 'must',
35+
private readonly ?array $facet = null,
36+
) {
37+
}
38+
39+
/**
40+
* @throws MappingException
41+
* @throws LockException
42+
*/
43+
public function apply(Builder $aggregationBuilder, string $resourceClass, ?Operation $operation = null, array &$context = []): void
44+
{
45+
$parameter = $context['parameter'];
46+
$property = $parameter->getProperty();
47+
$value = $parameter->getValue();
48+
49+
if (!isset($context['search'])) {
50+
$searchStage = $context['search']['stage'] = $aggregationBuilder->search();
51+
$searchStage->index($this->index);
52+
53+
if ($this->facet) {
54+
$searchStage->facet()
55+
->operator($compound = $searchStage->compound())
56+
->add(...$this->facet);
57+
} else {
58+
$compound = $context['search']['compound'] = $searchStage->compound();
59+
}
60+
$context['search']['compound'] = $compound;
61+
} else {
62+
$compound = $context['search']['compound'];
63+
}
64+
65+
$compound->{$this->term}();
66+
67+
switch ($this->operator) {
68+
case 'queryString':
69+
$operator = $compound->queryString()
70+
->defaultPath($property)
71+
->query($value);
72+
break;
73+
case 'wildcard':
74+
$operator = $compound->wildcard()
75+
->path($property)
76+
->query($value);
77+
break;
78+
case 'text':
79+
$operator = $compound->text()
80+
->path($property)
81+
->query($value)
82+
->fuzzy(maxEdits: 1);
83+
break;
84+
case 'phrase':
85+
$operator = $compound->phrase()
86+
->path($property)
87+
->query($value)
88+
->slop(2);
89+
break;
90+
case 'autocomplete':
91+
$operator = $compound->autocomplete()
92+
->path($property)
93+
->query($value)
94+
->fuzzy(maxEdits: 1);
95+
break;
96+
default:
97+
throw new \InvalidArgumentException(sprintf('Unsupported operator "%s" for AtlasSearchFilter', $this->operator));
98+
}
99+
}
100+
}

0 commit comments

Comments
 (0)