diff --git a/doc/04_Searching_For_Data_In_Index/05_Search_Modifiers/README.md b/doc/04_Searching_For_Data_In_Index/05_Search_Modifiers/README.md index 658cb283..91358217 100644 --- a/doc/04_Searching_For_Data_In_Index/05_Search_Modifiers/README.md +++ b/doc/04_Searching_For_Data_In_Index/05_Search_Modifiers/README.md @@ -20,6 +20,7 @@ $search->addModifier(new ParentIdFilter(1)) | [ExcludeFoldersFilter](https://github.com/pimcore/generic-data-index-bundle/blob/1.x/src/Model/Search/Modifier/Filter/Basic/ExcludeFoldersFilter.php) | Basic filters | Exclude folders from search result | | [ParentIdsFilter](https://github.com/pimcore/generic-data-index-bundle/blob/1.x/src/Model/Search/Modifier/Filter/Tree/ParentIdsFilter.php) | Tree related filters | Filter by parent ID | | [PathFilter](https://github.com/pimcore/generic-data-index-bundle/blob/1.x/src/Model/Search/Modifier/Filter/Tree/PathFilter.php) | Tree related filters | Filter by path (depending on use case for all levels or direct children only and with or without the parent item included) | +| [ClassIdsFilter](https://github.com/pimcore/generic-data-index-bundle/blob/1.x/src/Model/Search/Modifier/Filter/Tree/ClassIdsFilter.php) | Tree related filters | Filter object items by class IDs (depending on use case the folders can be included in the result) | | [TagFilter](https://github.com/pimcore/generic-data-index-bundle/blob/1.x/src/Model/Search/Modifier/Filter/Tree/TagFilter.php) | Tree related filters | Filter by tag IDs (it is also possible to include child tags) | | [AssetMetaDataFilter](https://github.com/pimcore/generic-data-index-bundle/blob/1.x/src/Model/Search/Modifier/Filter/Asset/AssetMetaDataFilter.php) | Asset filters | Filter by asset meta data attribute. The format of the `$data` which needs to be passed depends on the type of the meta data attribute and is handled by its [field definition adapter](https://github.com/pimcore/generic-data-index-bundle/tree/1.x/src/SearchIndexAdapter/DefaultSearch/Asset/FieldDefinitionAdapter). | | [WorkspaceQuery](https://github.com/pimcore/generic-data-index-bundle/blob/1.x/src/Model/Search/Modifier/Filter/Workspaces/WorkspaceQuery.php) | Workspace related filters | Filter based on the user workspaces and permissions for a defined element type (this query is added to the asset/document/data object search by default) | diff --git a/src/Model/Search/Modifier/Filter/Tree/ClassIdsFilter.php b/src/Model/Search/Modifier/Filter/Tree/ClassIdsFilter.php new file mode 100644 index 00000000..8dcbcde7 --- /dev/null +++ b/src/Model/Search/Modifier/Filter/Tree/ClassIdsFilter.php @@ -0,0 +1,41 @@ +classIds; + } + + public function includeFolders(): bool + { + return $this->includeFolders; + } +} diff --git a/src/SearchIndexAdapter/DefaultSearch/Search/Modifier/Filter/TreeFilters.php b/src/SearchIndexAdapter/DefaultSearch/Search/Modifier/Filter/TreeFilters.php index eb3c1ee7..19b1f8c0 100644 --- a/src/SearchIndexAdapter/DefaultSearch/Search/Modifier/Filter/TreeFilters.php +++ b/src/SearchIndexAdapter/DefaultSearch/Search/Modifier/Filter/TreeFilters.php @@ -22,6 +22,8 @@ use Pimcore\Bundle\GenericDataIndexBundle\Model\DefaultSearch\Modifier\SearchModifierContextInterface; use Pimcore\Bundle\GenericDataIndexBundle\Model\DefaultSearch\Query\BoolQuery; use Pimcore\Bundle\GenericDataIndexBundle\Model\DefaultSearch\Query\TermFilter; +use Pimcore\Bundle\GenericDataIndexBundle\Model\DefaultSearch\Query\TermsFilter; +use Pimcore\Bundle\GenericDataIndexBundle\Model\Search\Modifier\Filter\Tree\ClassIdsFilter; use Pimcore\Bundle\GenericDataIndexBundle\Model\Search\Modifier\Filter\Tree\ParentIdFilter; use Pimcore\Bundle\GenericDataIndexBundle\Model\Search\Modifier\Filter\Tree\PathFilter; use Pimcore\Bundle\GenericDataIndexBundle\Model\Search\Modifier\Filter\Tree\TagFilter; @@ -156,4 +158,35 @@ public function handleTagFilter(TagFilter $tagFilter, SearchModifierContextInter ); } + + #[AsSearchModifierHandler] + public function handleClassesFilter( + ClassIdsFilter $classesFilter, + SearchModifierContextInterface $context + ): void { + if (empty($classesFilter->getClassIds())) { + return; + } + + $query = new TermsFilter( + field: SystemField::CLASS_NAME->getPath('keyword'), + terms: $classesFilter->getClassIds() + ); + + if ($classesFilter->includeFolders()) { + $query = new BoolQuery([ + ConditionType::SHOULD->value => [ + new TermFilter( + field: SystemField::TYPE->getPath(), + term: 'folder' + ), + $query, + ], + ]); + } + + $context->getSearch()->addQuery( + new BoolQuery([ConditionType::MUST->value => [$query]]) + ); + } } diff --git a/tests/Functional/Search/Modifier/Filter/TreeFiltersTest.php b/tests/Functional/Search/Modifier/Filter/TreeFiltersTest.php index 724596cf..fd011864 100644 --- a/tests/Functional/Search/Modifier/Filter/TreeFiltersTest.php +++ b/tests/Functional/Search/Modifier/Filter/TreeFiltersTest.php @@ -16,10 +16,12 @@ namespace Pimcore\Bundle\GenericDataIndexBundle\Tests\Functional\Search\Modifier\Filter; use Pimcore\Bundle\GenericDataIndexBundle\Model\Search\Modifier\Filter\Basic\ExcludeFoldersFilter; +use Pimcore\Bundle\GenericDataIndexBundle\Model\Search\Modifier\Filter\Tree\ClassIdsFilter; use Pimcore\Bundle\GenericDataIndexBundle\Model\Search\Modifier\Filter\Tree\ParentIdFilter; use Pimcore\Bundle\GenericDataIndexBundle\Model\Search\Modifier\Filter\Tree\PathFilter; use Pimcore\Bundle\GenericDataIndexBundle\Model\Search\Modifier\Filter\Tree\TagFilter; use Pimcore\Bundle\GenericDataIndexBundle\Service\Search\SearchService\Asset\AssetSearchServiceInterface; +use Pimcore\Bundle\GenericDataIndexBundle\Service\Search\SearchService\DataObject\DataObjectSearchServiceInterface; use Pimcore\Bundle\GenericDataIndexBundle\Service\Search\SearchService\SearchProviderInterface; use Pimcore\Tests\Support\Util\TestHelper; @@ -194,6 +196,44 @@ public function testTagFilter(): void $this->assertEquals($asset->getId(), $searchResult->getIds()[0]); } + public function testClassIdsFilter(): void + { + $objects = TestHelper::createEmptyObjects(count: 2); + $folder = TestHelper::createObjectFolder(); + + /** @var DataObjectSearchServiceInterface $searchService */ + $searchService = $this->tester->grabService('generic-data-index.test.service.data-object-search-service'); + /** @var SearchProviderInterface $searchProvider */ + $searchProvider = $this->tester->grabService(SearchProviderInterface::class); + + $assetSearch = $searchProvider + ->createDataObjectSearch() + ->addModifier(new ClassIdsFilter([$objects[0]->getClassId()])); + $searchResult = $searchService->search($assetSearch); + + $this->assertCount(2, $searchResult->getIds()); + + $assetSearch = $searchProvider + ->createDataObjectSearch() + ->addModifier(new ClassIdsFilter([$objects[0]->getClassId()], true)); + $searchResult = $searchService->search($assetSearch); + + $this->assertCount(3, $searchResult->getIds()); + + $assetSearch = $searchProvider + ->createDataObjectSearch() + ->addModifier(new ClassIdsFilter(['someNonExistingClass'])); + $searchResult = $searchService->search($assetSearch); + + $this->assertEmpty($searchResult->getIds()); + $assetSearch = $searchProvider + ->createDataObjectSearch() + ->addModifier(new ClassIdsFilter(['someNonExistingClass'], true)); + $searchResult = $searchService->search($assetSearch); + + $this->assertEquals([$folder->getId()], $searchResult->getIds()); + } + private function assertIdArrayEquals(array $ids1, array $ids2) { sort($ids1);