Skip to content

Commit 6ba9c8b

Browse files
feat(doctrine): Add caseSensitive option to PartialSearchFilter (#7675)
1 parent 97f53df commit 6ba9c8b

6 files changed

Lines changed: 68 additions & 5 deletions

File tree

src/Doctrine/Odm/Filter/PartialSearchFilter.php

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,10 @@ final class PartialSearchFilter implements FilterInterface, OpenApiParameterFilt
2929
use BackwardCompatibleFilterDescriptionTrait;
3030
use OpenApiFilterTrait;
3131

32+
public function __construct(private readonly bool $caseSensitive = true)
33+
{
34+
}
35+
3236
public function apply(Builder $aggregationBuilder, string $resourceClass, ?Operation $operation = null, array &$context = []): void
3337
{
3438
$parameter = $context['parameter'];
@@ -47,7 +51,7 @@ public function apply(Builder $aggregationBuilder, string $resourceClass, ?Opera
4751
if (!is_iterable($values)) {
4852
$escapedValue = preg_quote($values, '/');
4953
$match->{$operator}(
50-
$aggregationBuilder->matchExpr()->field($property)->equals(new Regex($escapedValue, 'i'))
54+
$aggregationBuilder->matchExpr()->field($property)->equals(new Regex($escapedValue, $this->caseSensitive ? '' : 'i'))
5155
);
5256

5357
return;
@@ -60,7 +64,7 @@ public function apply(Builder $aggregationBuilder, string $resourceClass, ?Opera
6064
$or->addOr(
6165
$aggregationBuilder->matchExpr()
6266
->field($property)
63-
->equals(new Regex($escapedValue, 'i'))
67+
->equals(new Regex($escapedValue, $this->caseSensitive ? '' : 'i'))
6468
);
6569
}
6670

src/Doctrine/Orm/Filter/PartialSearchFilter.php

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,10 @@ final class PartialSearchFilter implements FilterInterface, OpenApiParameterFilt
2929
use BackwardCompatibleFilterDescriptionTrait;
3030
use OpenApiFilterTrait;
3131

32+
public function __construct(private readonly bool $caseSensitive = false)
33+
{
34+
}
35+
3236
public function apply(QueryBuilder $queryBuilder, QueryNameGeneratorInterface $queryNameGenerator, string $resourceClass, ?Operation $operation = null, array $context = []): void
3337
{
3438
$parameter = $context['parameter'];
@@ -46,7 +50,9 @@ public function apply(QueryBuilder $queryBuilder, QueryNameGeneratorInterface $q
4650
$parameterName = $queryNameGenerator->generateParameterName($property);
4751
$queryBuilder->setParameter($parameterName, $this->formatLikeValue($values));
4852

49-
$likeExpression = 'LOWER('.$field.') LIKE LOWER(:'.$parameterName.') ESCAPE \'\\\'';
53+
$likeExpression = $this->caseSensitive
54+
? $field.' LIKE :'.$parameterName.' ESCAPE \'\\\''
55+
: 'LOWER('.$field.') LIKE LOWER(:'.$parameterName.') ESCAPE \'\\\'';
5056
$queryBuilder->{$context['whereClause'] ?? 'andWhere'}($likeExpression);
5157

5258
return;
@@ -55,7 +61,10 @@ public function apply(QueryBuilder $queryBuilder, QueryNameGeneratorInterface $q
5561
$likeExpressions = [];
5662
foreach ($values as $val) {
5763
$parameterName = $queryNameGenerator->generateParameterName($property);
58-
$likeExpressions[] = 'LOWER('.$field.') LIKE LOWER(:'.$parameterName.') ESCAPE \'\\\'';
64+
$likeExpressions[] = $this->caseSensitive
65+
? $field.' LIKE :'.$parameterName.' ESCAPE \'\\\''
66+
: 'LOWER('.$field.') LIKE LOWER(:'.$parameterName.') ESCAPE \'\\\'';
67+
5968
$queryBuilder->setParameter($parameterName, $this->formatLikeValue($val));
6069
}
6170

tests/Fixtures/TestBundle/Document/Chicken.php

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,14 @@
3232
'name' => new QueryParameter(filter: new ExactFilter()),
3333
'nameExactNoProperty' => new QueryParameter(filter: new ExactFilter()),
3434
'namePartial' => new QueryParameter(
35-
filter: new PartialSearchFilter(),
35+
filter: new PartialSearchFilter(false),
3636
property: 'name',
3737
),
3838
'namePartialNoProperty' => new QueryParameter(filter: new PartialSearchFilter()),
39+
'namePartialSensitive' => new QueryParameter(
40+
filter: new PartialSearchFilter(true),
41+
property: 'name',
42+
),
3943
'autocomplete' => new QueryParameter(filter: new FreeTextQueryFilter(new OrFilter(new ExactFilter())), properties: ['name', 'ean']),
4044
'q' => new QueryParameter(filter: new FreeTextQueryFilter(new PartialSearchFilter()), properties: ['name', 'ean']),
4145
],

tests/Fixtures/TestBundle/Entity/Chicken.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,10 @@
3636
property: 'name',
3737
),
3838
'namePartialNoProperty' => new QueryParameter(filter: new PartialSearchFilter()),
39+
'namePartialSensitive' => new QueryParameter(
40+
filter: new PartialSearchFilter(true),
41+
property: 'name',
42+
),
3943
'autocomplete' => new QueryParameter(filter: new FreeTextQueryFilter(new OrFilter(new ExactFilter())), properties: ['name', 'ean']),
4044
'q' => new QueryParameter(filter: new FreeTextQueryFilter(new PartialSearchFilter()), properties: ['name', 'ean']),
4145
],

tests/Functional/Parameters/PartialSearchFilterTest.php

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,43 @@ public function testPartialSearchFilterThrowsExceptionWhenPropertyIsMissing(): v
193193
);
194194
}
195195

196+
#[DataProvider('partialSearchFilterCaseSensitiveProvider')]
197+
public function testPartialSearchCaseSensitiveFilter(string $url, int $expectedCount, array $expectedNames): void
198+
{
199+
if ($this->isMysql() || $this->isSqlite()) {
200+
$this->markTestSkipped('Mysql and sqlite use case insensitive LIKE.');
201+
}
202+
203+
$this->testPartialSearchFilter($url, $expectedCount, $expectedNames);
204+
}
205+
206+
public static function partialSearchFilterCaseSensitiveProvider(): \Generator
207+
{
208+
yield 'filter by partial name "tru"' => [
209+
'/chickens?namePartial=tru',
210+
1,
211+
['Gertrude'],
212+
];
213+
214+
yield 'filter by partial name "TRU"' => [
215+
'/chickens?namePartial=TRU',
216+
1,
217+
['Gertrude'],
218+
];
219+
220+
yield 'filter by case sensitive partial name "tru"' => [
221+
'/chickens?namePartialSensitive=tru',
222+
1,
223+
['Gertrude'],
224+
];
225+
226+
yield 'filter by case sensitive partial name "TRU"' => [
227+
'/chickens?namePartialSensitive=TRU',
228+
0,
229+
[],
230+
];
231+
}
232+
196233
/**
197234
* @throws \Throwable
198235
* @throws MongoDBException

tests/RecreateSchemaTrait.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,11 @@ private function isMongoDB(): bool
7878
return 'mongodb' === static::getContainer()->getParameter('kernel.environment');
7979
}
8080

81+
private function isMysql(): bool
82+
{
83+
return 'mysql' === static::getContainer()->getParameter('kernel.environment');
84+
}
85+
8186
private function isPostgres(): bool
8287
{
8388
return 'postgres' === static::getContainer()->getParameter('kernel.environment');

0 commit comments

Comments
 (0)