Skip to content

Commit 51061fc

Browse files
authored
IBX-11146: Updated filtering logic to use LanguageCode criterion with {terms} clause (#107)
* IBX-1146: Updated filtering logic to use LanguageCode criterion with {terms} clause * rewrote `matchAlwaysAvailable === true` part to also use {terms} query parser * added phpdoc
1 parent 3c271b9 commit 51061fc

File tree

4 files changed

+69
-15
lines changed

4 files changed

+69
-15
lines changed

phpstan-baseline.neon

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -996,12 +996,6 @@ parameters:
996996
count: 1
997997
path: src/lib/Query/Common/CriterionVisitor/Field/FieldRelation.php
998998

999-
-
1000-
message: '#^Parameter \#2 \$array of function array_map expects array, array\<bool\|float\|int\|string\>\|bool\|float\|int\|string given\.$#'
1001-
identifier: argument.type
1002-
count: 1
1003-
path: src/lib/Query/Common/CriterionVisitor/LanguageCodeIn.php
1004-
1005999
-
10061000
message: '#^Method Ibexa\\Solr\\Query\\Common\\CriterionVisitor\\MapLocation\:\:getSearchFields\(\) return type has no value type specified in iterable type array\.$#'
10071001
identifier: missingType.iterableValue

src/lib/CoreFilter/NativeCoreFilter.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
use Ibexa\Contracts\Core\Repository\Values\Content\Query;
1010
use Ibexa\Contracts\Core\Repository\Values\Content\Query\Criterion;
1111
use Ibexa\Contracts\Core\Repository\Values\Content\Query\Criterion\CustomField;
12+
use Ibexa\Contracts\Core\Repository\Values\Content\Query\Criterion\LanguageCode;
1213
use Ibexa\Contracts\Core\Repository\Values\Content\Query\Criterion\LogicalAnd;
1314
use Ibexa\Contracts\Core\Repository\Values\Content\Query\Criterion\LogicalNot;
1415
use Ibexa\Contracts\Core\Repository\Values\Content\Query\Criterion\LogicalOr;
@@ -182,7 +183,7 @@ private function getLanguageFilter(array $languageCodes)
182183
[
183184
$condition,
184185
new LogicalNot(
185-
new CustomField(self::FIELD_LANGUAGES, Operator::IN, $excluded)
186+
new LanguageCode($excluded, false)
186187
),
187188
]
188189
);

src/lib/Query/Common/CriterionVisitor/LanguageCodeIn.php

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -30,19 +30,25 @@ public function canVisit(Criterion $criterion)
3030

3131
public function visit(Criterion $criterion, ?CriterionVisitor $subVisitor = null): string
3232
{
33-
$languageCodeExpressions = array_map(
34-
static function ($value) {
35-
return 'content_language_codes_ms:"' . $value . '"';
36-
},
37-
$criterion->value
33+
/** @var Criterion\LanguageCode $criterion */
34+
$values = is_array($criterion->value) ? $criterion->value : [$criterion->value];
35+
// content_language_codes_ms is a string field which uses LowerCaseFilter.
36+
// Since {!terms} bypasses analysis, we must manually lowercase the values to match the index.
37+
/** @param bool|float|int|string $value */
38+
$values = array_map(static function ($value): string {
39+
return strtolower((string)$value);
40+
}, $values);
41+
42+
$termsQuery = sprintf(
43+
'_query_:"{!terms f=content_language_codes_ms}%s"',
44+
implode(',', $values)
3845
);
3946

40-
/** @var Criterion\LanguageCode $criterion */
4147
if ($criterion->matchAlwaysAvailable) {
42-
$languageCodeExpressions[] = 'content_always_available_b:true';
48+
return '(' . $termsQuery . ' OR content_always_available_b:true)';
4349
}
4450

45-
return '(' . implode(' OR ', $languageCodeExpressions) . ')';
51+
return $termsQuery;
4652
}
4753
}
4854

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
<?php
2+
3+
/**
4+
* @copyright Copyright (C) Ibexa AS. All rights reserved.
5+
* @license For full copyright and license information view LICENSE file distributed with this source code.
6+
*/
7+
declare(strict_types=1);
8+
9+
namespace Ibexa\Tests\Solr\Search\Query\Common\CriterionVisitor;
10+
11+
use Ibexa\Contracts\Core\Repository\Values\Content\Query\Criterion\LanguageCode;
12+
use Ibexa\Contracts\Solr\Query\CriterionVisitor;
13+
use Ibexa\Solr\Query\Common\CriterionVisitor\LanguageCodeIn;
14+
use Ibexa\Tests\Solr\Search\Query\BaseCriterionVisitorTestCase;
15+
16+
final class LanguageCodeInTest extends BaseCriterionVisitorTestCase
17+
{
18+
protected function getVisitor(): CriterionVisitor
19+
{
20+
return new LanguageCodeIn();
21+
}
22+
23+
protected function getSupportedCriterion(): LanguageCode
24+
{
25+
return new LanguageCode('eng-GB');
26+
}
27+
28+
/**
29+
* @return iterable<string, array{0: string, 1: \Ibexa\Contracts\Core\Repository\Values\Content\Query\Criterion\LanguageCode}>
30+
*/
31+
public function provideDataForTestVisit(): iterable
32+
{
33+
yield 'Single language, match always available' => [
34+
'(_query_:"{!terms f=content_language_codes_ms}eng-gb" OR content_always_available_b:true)',
35+
new LanguageCode('eng-GB', true),
36+
];
37+
38+
yield 'Multiple languages, match always available' => [
39+
'(_query_:"{!terms f=content_language_codes_ms}eng-gb,pol-pl" OR content_always_available_b:true)',
40+
new LanguageCode(['eng-GB', 'pol-PL'], true),
41+
];
42+
43+
yield 'Multiple languages, do NOT match always available (optimization)' => [
44+
'_query_:"{!terms f=content_language_codes_ms}eng-gb,pol-pl"',
45+
new LanguageCode(['eng-GB', 'pol-PL'], false),
46+
];
47+
48+
yield 'Single language, do NOT match always available (optimization)' => [
49+
'_query_:"{!terms f=content_language_codes_ms}eng-gb"',
50+
new LanguageCode('eng-GB', false),
51+
];
52+
}
53+
}

0 commit comments

Comments
 (0)