Skip to content

Commit a56b54d

Browse files
authored
[Modifiers]: Nested fields (#348)
* add nested type filter * Apply php-cs-fixer changes * fix: remove unused parameters * remove unused parameters * add test cases * Apply php-cs-fixer changes * update docs --------- Co-authored-by: lukmzig <[email protected]>
1 parent af97989 commit a56b54d

File tree

11 files changed

+678
-72
lines changed

11 files changed

+678
-72
lines changed

config/services/search-index-adapter/default-search/modifiers/search-modifiers.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ services:
1313
Pimcore\Bundle\GenericDataIndexBundle\SearchIndexAdapter\DefaultSearch\Search\Modifier\Filter\TreeFilters: ~
1414
Pimcore\Bundle\GenericDataIndexBundle\SearchIndexAdapter\DefaultSearch\Search\Modifier\Filter\DependencyFilters: ~
1515
Pimcore\Bundle\GenericDataIndexBundle\SearchIndexAdapter\DefaultSearch\Search\Modifier\Filter\FieldTypeFilters: ~
16+
Pimcore\Bundle\GenericDataIndexBundle\SearchIndexAdapter\DefaultSearch\Search\Modifier\Filter\NestedTypeFilters: ~
1617

1718
Pimcore\Bundle\GenericDataIndexBundle\SearchIndexAdapter\DefaultSearch\Search\Modifier\FullTextSearch\FullTextSearchHandlers: ~
1819

doc/04_Searching_For_Data_In_Index/05_Search_Modifiers/README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ $search->addModifier(new ParentIdFilter(1))
1616
|--------------------------------------------------------------------------------------------------------------------------------------------------------|---------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
1717
| [IdFilter](https://github.com/pimcore/generic-data-index-bundle/blob/2.0/src/Model/Search/Modifier/Filter/Basic/IdFilter.php) | Basic filters | Filter by element ID |
1818
| [IdsFilter](https://github.com/pimcore/generic-data-index-bundle/blob/2.0/src/Model/Search/Modifier/Filter/Basic/IdsFilter.php) | Basic filters | Filter by multiple element IDs |
19-
| [BooleanFilter](https://github.com/pimcore/generic-data-index-bundle/blob/2.x/src/Model/Search/Modifier/Filter/Basic/BooleanFilter.php) | Basic filters | Filter boolean fields based on the value with [PQL field name resolution support](#pql-field-name-resolution) |
19+
| [BooleanFilter](https://github.com/pimcore/generic-data-index-bundle/blob/2.x/src/Model/Search/Modifier/Filter/Basic/BooleanFilter.php) | Basic filters | Filter boolean fields based on the value with [PQL field name resolution support](#pql-field-name-resolution) |
2020
| [IntegerFilter](https://github.com/pimcore/generic-data-index-bundle/blob/2.0/src/Model/Search/Modifier/Filter/Basic/IntegerFilter.php) | Basic filters | Filter integer fields based on the value with [PQL field name resolution support](#pql-field-name-resolution) |
2121
| [ExcludeFoldersFilter](https://github.com/pimcore/generic-data-index-bundle/blob/2.0/src/Model/Search/Modifier/Filter/Basic/ExcludeFoldersFilter.php) | Basic filters | Exclude folders from search result |
2222
| [ParentIdsFilter](https://github.com/pimcore/generic-data-index-bundle/blob/2.0/src/Model/Search/Modifier/Filter/Tree/ParentIdsFilter.php) | Tree related filters | Filter by parent ID |
@@ -28,8 +28,8 @@ $search->addModifier(new ParentIdFilter(1))
2828
| [ElementWorkspacesQuery](https://github.com/pimcore/generic-data-index-bundle/blob/2.0/src/Model/Search/Modifier/Filter/Workspaces/WorkspaceQuery.php) | Workspace related filters | Filter based on the user workspaces and permissions respecting all element types (this query is added to the element search by default) |
2929
| [MultiSelectFilter](https://github.com/pimcore/generic-data-index-bundle/blob/2.0/src/Model/Search/Modifier/Filter/FieldType/MultiSelectFilter.php) | Field type filters | Filter text fields by a list of exact strings. Supports [PQL field name resolution](#pql-field-name-resolution). |
3030
| [DateFilter](https://github.com/pimcore/generic-data-index-bundle/blob/2.0/src/Model/Search/Modifier/Filter/FieldType/DateFilter.php) | Field type filters | Filter date fields based on an exact date or a range of dates. Supports [PQL field name resolution](#pql-field-name-resolution). |
31-
32-
31+
| [ClassificationStoreFilter](https://github.com/pimcore/generic-data-index-bundle/blob/2.x/src/Model/Search/Modifier/Filter/FieldType/ClassificationStoreFilter.php) | Nested filters | Filter based on the classification store field values. Requires sub-modifier based on the filtered field type. Only fields types, which are supported by classificaiton store can be used for sub-modifier. |
32+
| [NestedFilter](https://github.com/pimcore/generic-data-index-bundle/blob/2.x/src/Model/Search/Modifier/Filter/FieldType/NestedFilter.php) | Nested filters | Filter for nested fields. Requires sub-modifier based on the field type of nested field. |
3333

3434
### Full Text Search Queries
3535

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/**
6+
* This source file is available under the terms of the
7+
* Pimcore Open Core License (POCL)
8+
* Full copyright and license information is available in
9+
* LICENSE.md which is distributed with this source code.
10+
*
11+
* @copyright Copyright (c) Pimcore GmbH (https://www.pimcore.com)
12+
* @license Pimcore Open Core License (POCL)
13+
*/
14+
15+
namespace Pimcore\Bundle\GenericDataIndexBundle\Model\DefaultSearch\Query;
16+
17+
use Pimcore\Bundle\GenericDataIndexBundle\Enum\SearchIndex\DefaultSearch\ConditionType;
18+
19+
final class NestedFilter extends BoolQuery implements AsSubQueryInterface
20+
{
21+
public function __construct(
22+
private readonly string $path,
23+
private readonly array $subQuery,
24+
) {
25+
parent::__construct([
26+
ConditionType::FILTER->value => [
27+
'nested' => [
28+
'path' => $this->path,
29+
'query' => $this->subQuery,
30+
],
31+
],
32+
]);
33+
}
34+
35+
public function getPath(): string
36+
{
37+
return $this->path;
38+
}
39+
40+
public function toArrayAsSubQuery(): array
41+
{
42+
return [
43+
'nested' => [
44+
'path' => $this->path,
45+
'query' => $this->subQuery,
46+
],
47+
];
48+
}
49+
}
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
<?php
2+
declare(strict_types=1);
3+
4+
/**
5+
* This source file is available under the terms of the
6+
* Pimcore Open Core License (POCL)
7+
* Full copyright and license information is available in
8+
* LICENSE.md which is distributed with this source code.
9+
*
10+
* @copyright Copyright (c) Pimcore GmbH (https://www.pimcore.com)
11+
* @license Pimcore Open Core License (POCL)
12+
*/
13+
14+
namespace Pimcore\Bundle\GenericDataIndexBundle\Model\Search\Modifier\Filter\FieldType;
15+
16+
use Pimcore\Bundle\GenericDataIndexBundle\Model\Search\Modifier\Filter\Basic\BooleanFilter;
17+
use Pimcore\Bundle\GenericDataIndexBundle\Model\Search\Modifier\Filter\Basic\IntegerFilter;
18+
use Pimcore\Bundle\GenericDataIndexBundle\Model\Search\Modifier\FullTextSearch\FullTextSearch;
19+
use Pimcore\Bundle\GenericDataIndexBundle\Model\Search\Modifier\FullTextSearch\WildcardSearch;
20+
use Pimcore\Bundle\GenericDataIndexBundle\Model\Search\Modifier\SearchModifierInterface;
21+
use Pimcore\Bundle\GenericDataIndexBundle\Model\SearchIndexAdapter\MappingProperty;
22+
23+
final readonly class ClassificationStoreFilter implements SearchModifierInterface
24+
{
25+
public function __construct(
26+
private string $fieldName,
27+
private string $group,
28+
private BooleanFilter|DateFilter|FullTextSearch|IntegerFilter|MultiSelectFilter|NumberRangeFilter|
29+
WildcardSearch $subModifier,
30+
private string $locale = MappingProperty::NOT_LOCALIZED_KEY,
31+
) {
32+
}
33+
34+
public function getFieldName(): string
35+
{
36+
return $this->fieldName;
37+
}
38+
39+
public function getGroup(): string
40+
{
41+
return $this->group;
42+
}
43+
44+
public function getSubModifier(): BooleanFilter|DateFilter|FullTextSearch|IntegerFilter|
45+
MultiSelectFilter|NumberRangeFilter|WildcardSearch
46+
{
47+
return $this->subModifier;
48+
}
49+
50+
public function getLocale(): string
51+
{
52+
return $this->locale;
53+
}
54+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
<?php
2+
declare(strict_types=1);
3+
4+
/**
5+
* This source file is available under the terms of the
6+
* Pimcore Open Core License (POCL)
7+
* Full copyright and license information is available in
8+
* LICENSE.md which is distributed with this source code.
9+
*
10+
* @copyright Copyright (c) Pimcore GmbH (https://www.pimcore.com)
11+
* @license Pimcore Open Core License (POCL)
12+
*/
13+
14+
namespace Pimcore\Bundle\GenericDataIndexBundle\Model\Search\Modifier\Filter\FieldType;
15+
16+
use Pimcore\Bundle\GenericDataIndexBundle\Model\Search\Modifier\SearchModifierInterface;
17+
18+
final readonly class NestedFilter implements SearchModifierInterface
19+
{
20+
public function __construct(
21+
private string $fieldName,
22+
private SearchModifierInterface $subModifier
23+
) {
24+
}
25+
26+
public function getFieldName(): string
27+
{
28+
return $this->fieldName;
29+
}
30+
31+
public function getSubModifier(): SearchModifierInterface
32+
{
33+
return $this->subModifier;
34+
}
35+
}

src/SearchIndexAdapter/DefaultSearch/Search/Modifier/Filter/BasicFilters.php

Lines changed: 37 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
use Pimcore\Bundle\GenericDataIndexBundle\Model\DefaultSearch\Query\BoolQuery;
2121
use Pimcore\Bundle\GenericDataIndexBundle\Model\DefaultSearch\Query\TermFilter;
2222
use Pimcore\Bundle\GenericDataIndexBundle\Model\DefaultSearch\Query\TermsFilter;
23+
use Pimcore\Bundle\GenericDataIndexBundle\Model\Search\Interfaces\SearchInterface;
2324
use Pimcore\Bundle\GenericDataIndexBundle\Model\Search\Modifier\Filter\Basic\BooleanFilter;
2425
use Pimcore\Bundle\GenericDataIndexBundle\Model\Search\Modifier\Filter\Basic\ExcludeFoldersFilter;
2526
use Pimcore\Bundle\GenericDataIndexBundle\Model\Search\Modifier\Filter\Basic\IdFilter;
@@ -51,46 +52,60 @@ public function handleIdFilter(IdFilter $idFilter, SearchModifierContextInterfac
5152
#[AsSearchModifierHandler]
5253
public function handleIntegerFilter(IntegerFilter $integerFilter, SearchModifierContextInterface $context): void
5354
{
55+
$context->getSearch()->addQuery(
56+
$this->getIntegerQuery($integerFilter, null, $context->getOriginalSearch())
57+
);
58+
}
59+
60+
public function getIntegerQuery(
61+
IntegerFilter $integerFilter,
62+
?string $prefix = null,
63+
?SearchInterface $search = null
64+
): TermFilter {
5465
$fieldName = $integerFilter->getFieldName();
55-
if ($integerFilter->isPqlFieldNameResolutionEnabled()) {
56-
$fieldName = $this->fieldNameTransformationService->transformFieldnameForSearch(
57-
$context->getOriginalSearch(),
58-
$fieldName
59-
);
66+
if ($prefix) {
67+
$fieldName = $prefix . '.' . $fieldName;
68+
}
69+
if ($search && $integerFilter->isPqlFieldNameResolutionEnabled()) {
70+
$fieldName = $this->fieldNameTransformationService->transformFieldnameForSearch($search, $fieldName);
6071
}
6172

62-
$context->getSearch()->addQuery(
63-
new TermFilter(
64-
field: $fieldName,
65-
term: $integerFilter->getSearchTerm(),
66-
)
73+
return new TermFilter(
74+
field: $fieldName,
75+
term: $integerFilter->getSearchTerm(),
6776
);
6877
}
6978

7079
#[AsSearchModifierHandler]
7180
public function handleBooleanFilter(BooleanFilter $booleanFilter, SearchModifierContextInterface $context): void
7281
{
82+
$context->getSearch()->addQuery(
83+
$this->getBooleanQuery($booleanFilter, null, $context->getOriginalSearch())
84+
);
85+
}
86+
87+
public function getBooleanQuery(
88+
BooleanFilter $booleanFilter,
89+
?string $prefix = null,
90+
?SearchInterface $search = null
91+
): BoolExistsQuery|TermFilter {
7392
$fieldName = $booleanFilter->getFieldName();
74-
if ($booleanFilter->isPqlFieldNameResolutionEnabled()) {
75-
$fieldName = $this->fieldNameTransformationService->transformFieldnameForSearch(
76-
$context->getOriginalSearch(),
77-
$fieldName
78-
);
93+
if ($prefix) {
94+
$fieldName = $prefix . '.' . $fieldName;
95+
}
96+
if ($search && $booleanFilter->isPqlFieldNameResolutionEnabled()) {
97+
$fieldName = $this->fieldNameTransformationService->transformFieldnameForSearch($search, $fieldName);
7998
}
80-
81-
$query = new BoolExistsQuery(
82-
field: $fieldName,
83-
);
8499

85100
if ($booleanFilter->getSearchTerm() !== null) {
86-
$query = new TermFilter(
101+
return new TermFilter(
87102
field: $fieldName,
88103
term: $booleanFilter->getSearchTerm(),
89104
);
90105
}
91106

92-
$context->getSearch()->addQuery(
93-
$query
107+
return new BoolExistsQuery(
108+
field: $fieldName,
94109
);
95110
}
96111

0 commit comments

Comments
 (0)