Skip to content

Commit d959323

Browse files
committed
SearchFilter: Refactor code to reduce code duplication and makes it easier to add new strategies to classes inheriting from SearchFilter class
1 parent cfc05d1 commit d959323

File tree

2 files changed

+64
-72
lines changed

2 files changed

+64
-72
lines changed

src/Bridge/Doctrine/MongoDbOdm/Filter/SearchFilter.php

Lines changed: 27 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@
1919
use ApiPlatform\Core\Bridge\Doctrine\Common\Filter\SearchFilterTrait;
2020
use ApiPlatform\Core\Exception\InvalidArgumentException;
2121
use Doctrine\Common\Persistence\ManagerRegistry;
22-
use Doctrine\Common\Persistence\Mapping\ClassMetadata;
2322
use Doctrine\ODM\MongoDB\Aggregation\Builder;
2423
use Doctrine\ODM\MongoDB\Mapping\ClassMetadata as MongoDBClassMetadata;
2524
use Doctrine\ODM\MongoDB\Types\Type as MongoDbType;
@@ -94,6 +93,14 @@ protected function filterProperty(string $property, $value, Builder $aggregation
9493

9594
$caseSensitive = true;
9695

96+
$strategy = $this->properties[$property] ?? self::STRATEGY_EXACT;
97+
98+
// prefixing the strategy with i makes it case insensitive
99+
if (0 === strpos($strategy, 'i')) {
100+
$strategy = substr($strategy, 1);
101+
$caseSensitive = false;
102+
}
103+
97104
if ($metadata->hasField($field) && !$metadata->hasAssociation($field)) {
98105
if ('id' === $field) {
99106
$values = array_map([$this, 'getIdFromValue'], $values);
@@ -107,23 +114,8 @@ protected function filterProperty(string $property, $value, Builder $aggregation
107114
return;
108115
}
109116

110-
$strategy = $this->properties[$property] ?? self::STRATEGY_EXACT;
111-
112-
// prefixing the strategy with i makes it case insensitive
113-
if (0 === strpos($strategy, 'i')) {
114-
$strategy = substr($strategy, 1);
115-
$caseSensitive = false;
116-
}
117-
118-
$inValues = [];
119-
foreach ($values as $inValue) {
120-
$inValues[] = $this->addEqualityMatchStrategy($strategy, $field, $inValue, $caseSensitive, $metadata);
121-
}
122-
123-
$aggregationBuilder
124-
->match()
125-
->field($matchField)
126-
->in($inValues);
117+
$type = $metadata->getTypeOfField($field);
118+
$this->addEqualityMatchStrategy($strategy, $aggregationBuilder, $matchField, $type, $values, $caseSensitive);
127119
}
128120

129121
// metadata doesn't have the field, nor an association on the field
@@ -149,10 +141,25 @@ protected function filterProperty(string $property, $value, Builder $aggregation
149141
return;
150142
}
151143

144+
$this->addEqualityMatchStrategy($strategy, $aggregationBuilder, $matchField, $doctrineTypeField, $values, $caseSensitive);
145+
}
146+
147+
/**
148+
* Adds where clause according to the strategy.
149+
*
150+
* @throws InvalidArgumentException If strategy does not exist
151+
*/
152+
protected function addEqualityMatchStrategy(string $strategy, Builder $aggregationBuilder, string $matchField, $fieldType, $values, bool $caseSensitive)
153+
{
154+
$inValues = [];
155+
foreach ($values as $inValue) {
156+
$inValues[] = $this->getEqualityMatchStrategy($strategy, $inValue, $caseSensitive, $fieldType);
157+
}
158+
152159
$aggregationBuilder
153160
->match()
154161
->field($matchField)
155-
->in($values);
162+
->in($inValues);
156163
}
157164

158165
/**
@@ -162,10 +169,8 @@ protected function filterProperty(string $property, $value, Builder $aggregation
162169
*
163170
* @return Regex|string
164171
*/
165-
private function addEqualityMatchStrategy(string $strategy, string $field, $value, bool $caseSensitive, ClassMetadata $metadata)
172+
private function getEqualityMatchStrategy(string $strategy, $value, bool $caseSensitive, string $type)
166173
{
167-
$type = $metadata->getTypeOfField($field);
168-
169174
switch ($strategy) {
170175
case MongoDbType::STRING !== $type:
171176
return MongoDbType::getType($type)->convertToDatabaseValue($value);

src/Bridge/Doctrine/Orm/Filter/SearchFilter.php

Lines changed: 37 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,14 @@ protected function filterProperty(string $property, $value, QueryBuilder $queryB
9595
$doctrineTypeField = $this->getDoctrineFieldType($property, $resourceClass);
9696
$values = array_map([$this, 'getIdFromValue'], $values);
9797

98+
$strategy = $this->properties[$property] ?? self::STRATEGY_EXACT;
99+
100+
// prefixing the strategy with i makes it case insensitive
101+
if (0 === strpos($strategy, 'i')) {
102+
$strategy = substr($strategy, 1);
103+
$caseSensitive = false;
104+
}
105+
98106
if ($metadata->hasField($field)) {
99107
if (!$this->hasValidValues($values, $doctrineTypeField)) {
100108
$this->logger->notice('Invalid filter ignored', [
@@ -104,34 +112,7 @@ protected function filterProperty(string $property, $value, QueryBuilder $queryB
104112
return;
105113
}
106114

107-
$strategy = $this->properties[$property] ?? self::STRATEGY_EXACT;
108-
109-
// prefixing the strategy with i makes it case insensitive
110-
if (0 === strpos($strategy, 'i')) {
111-
$strategy = substr($strategy, 1);
112-
$caseSensitive = false;
113-
}
114-
115-
if (1 === \count($values)) {
116-
$this->addWhereByStrategy($strategy, $queryBuilder, $queryNameGenerator, $alias, $field, $doctrineTypeField, $values[0], $caseSensitive);
117-
118-
return;
119-
}
120-
121-
if (self::STRATEGY_EXACT !== $strategy) {
122-
$this->logger->notice('Invalid filter ignored', [
123-
'exception' => new InvalidArgumentException(sprintf('"%s" strategy selected for "%s" property, but only "%s" strategy supports multiple values', $strategy, $property, self::STRATEGY_EXACT)),
124-
]);
125-
126-
return;
127-
}
128-
129-
$wrapCase = $this->createWrapCase($caseSensitive);
130-
$valueParameter = $queryNameGenerator->generateParameterName($field);
131-
132-
$queryBuilder
133-
->andWhere(sprintf($wrapCase('%s.%s').' IN (:%s)', $alias, $field, $valueParameter))
134-
->setParameter($valueParameter, $caseSensitive ? $values : array_map('strtolower', $values));
115+
$this->addWhereByStrategy($strategy, $queryBuilder, $queryNameGenerator, $alias, $field, $doctrineTypeField, $values, $caseSensitive);
135116
}
136117

137118
// metadata doesn't have the field, nor an association on the field
@@ -155,63 +136,69 @@ protected function filterProperty(string $property, $value, QueryBuilder $queryB
155136
return;
156137
}
157138

158-
$association = $field;
159-
$valueParameter = $queryNameGenerator->generateParameterName($association);
160-
if ($metadata->isCollectionValuedAssociation($association)) {
161-
$associationAlias = QueryBuilderHelper::addJoinOnce($queryBuilder, $queryNameGenerator, $alias, $association);
139+
$valueParameter = $queryNameGenerator->generateParameterName($field);
140+
if ($metadata->isCollectionValuedAssociation($field)) {
141+
$associationAlias = QueryBuilderHelper::addJoinOnce($queryBuilder, $queryNameGenerator, $alias, $field);
162142
$associationField = $associationFieldIdentifier;
163143
} else {
164144
$associationAlias = $alias;
165145
$associationField = $field;
166146
}
167147

168-
if (1 === \count($values)) {
169-
$queryBuilder
170-
->andWhere(sprintf('%s.%s = :%s', $associationAlias, $associationField, $valueParameter))
171-
->setParameter($valueParameter, $values[0], $doctrineTypeField);
172-
} else {
173-
$queryBuilder
174-
->andWhere(sprintf('%s.%s IN (:%s)', $associationAlias, $associationField, $valueParameter))
175-
->setParameter($valueParameter, $values, $doctrineTypeField);
176-
}
148+
$this->addWhereByStrategy($strategy, $queryBuilder, $queryNameGenerator, $associationAlias, $associationField, $doctrineTypeField, $values, $caseSensitive, $valueParameter);
177149
}
178150

179151
/**
180152
* Adds where clause according to the strategy.
181153
*
182154
* @throws InvalidArgumentException If strategy does not exist
183155
*/
184-
protected function addWhereByStrategy(string $strategy, QueryBuilder $queryBuilder, QueryNameGeneratorInterface $queryNameGenerator, string $alias, string $field, $fieldType, $value, bool $caseSensitive)
156+
protected function addWhereByStrategy(string $strategy, QueryBuilder $queryBuilder, QueryNameGeneratorInterface $queryNameGenerator, string $alias, string $field, $fieldType, $values, bool $caseSensitive, string $valueParameter = null)
185157
{
186158
$wrapCase = $this->createWrapCase($caseSensitive);
187-
$valueParameter = $queryNameGenerator->generateParameterName($field);
159+
$valueParameter = $valueParameter ?? $queryNameGenerator->generateParameterName($field);
160+
$values = (array) $values;
161+
162+
if (self::STRATEGY_EXACT !== $strategy && 1 !== \count($values)) {
163+
$this->logger->notice('Invalid filter ignored', [
164+
'exception' => new InvalidArgumentException(sprintf('"%s" strategy selected for "%s" property, but only "%s" strategy supports multiple values', $strategy, $field, self::STRATEGY_EXACT)),
165+
]);
166+
167+
return;
168+
}
188169

189170
switch ($strategy) {
190171
case null:
191172
case self::STRATEGY_EXACT:
192-
$queryBuilder
193-
->andWhere(sprintf($wrapCase('%s.%s').' = '.$wrapCase(':%s'), $alias, $field, $valueParameter))
194-
->setParameter($valueParameter, $value, $fieldType);
173+
if (1 === \count($values)) {
174+
$queryBuilder
175+
->andWhere(sprintf($wrapCase('%s.%s').' = '.$wrapCase(':%s'), $alias, $field, $valueParameter))
176+
->setParameter($valueParameter, $values[0], $fieldType);
177+
} else {
178+
$queryBuilder
179+
->andWhere(sprintf($wrapCase('%s.%s').' IN (:%s)', $alias, $field, $valueParameter))
180+
->setParameter($valueParameter, $caseSensitive ? $values : array_map('strtolower', $values));
181+
}
195182
break;
196183
case self::STRATEGY_PARTIAL:
197184
$queryBuilder
198185
->andWhere(sprintf($wrapCase('%s.%s').' LIKE '.$wrapCase('CONCAT(\'%%\', :%s, \'%%\')'), $alias, $field, $valueParameter))
199-
->setParameter($valueParameter, $value, $fieldType);
186+
->setParameter($valueParameter, $values[0], $fieldType);
200187
break;
201188
case self::STRATEGY_START:
202189
$queryBuilder
203190
->andWhere(sprintf($wrapCase('%s.%s').' LIKE '.$wrapCase('CONCAT(:%s, \'%%\')'), $alias, $field, $valueParameter))
204-
->setParameter($valueParameter, $value, $fieldType);
191+
->setParameter($valueParameter, $values[0], $fieldType);
205192
break;
206193
case self::STRATEGY_END:
207194
$queryBuilder
208195
->andWhere(sprintf($wrapCase('%s.%s').' LIKE '.$wrapCase('CONCAT(\'%%\', :%s)'), $alias, $field, $valueParameter))
209-
->setParameter($valueParameter, $value, $fieldType);
196+
->setParameter($valueParameter, $values[0], $fieldType);
210197
break;
211198
case self::STRATEGY_WORD_START:
212199
$queryBuilder
213200
->andWhere(sprintf($wrapCase('%1$s.%2$s').' LIKE '.$wrapCase('CONCAT(:%3$s, \'%%\')').' OR '.$wrapCase('%1$s.%2$s').' LIKE '.$wrapCase('CONCAT(\'%% \', :%3$s, \'%%\')'), $alias, $field, $valueParameter))
214-
->setParameter($valueParameter, $value, $fieldType);
201+
->setParameter($valueParameter, $values[0], $fieldType);
215202
break;
216203
default:
217204
throw new InvalidArgumentException(sprintf('strategy %s does not exist.', $strategy));

0 commit comments

Comments
 (0)