diff --git a/Classes/Common/Paginator.php b/Classes/Common/Paginator.php index 09a41fb..93113a8 100644 --- a/Classes/Common/Paginator.php +++ b/Classes/Common/Paginator.php @@ -82,18 +82,28 @@ public function setPage(int $page): Paginator return $this; } - public function getPagination(): array + public function getTotalPages(): int { if ( $this->totalItems < 0 || - $this->currentPage < 0 || $this->itemsPerPage < 0 ) { - throw new \Exception('Please specify total items, items per page and current page before retrieving the pagination.'); + throw new \Exception('Please specify total items and items per page before retrieving the pagination.'); + } + + return (int) ceil($this->totalItems / $this->itemsPerPage); + } + + public function getPagination(): array + { + if ( + $this->currentPage < 0 + ) { + throw new \Exception('Please specify current page before retrieving the pagination.'); } $pagination = new Collection(); - $totalPages = (int) ceil($this->totalItems / $this->itemsPerPage); + $totalPages = $this->getTotalPages(); $currentPage = $this->currentPage; $pagesBefore = $this->paginationRange-> diff --git a/Classes/Common/QueryParamsBuilder.php b/Classes/Common/QueryParamsBuilder.php index 939389b..1484e5e 100644 --- a/Classes/Common/QueryParamsBuilder.php +++ b/Classes/Common/QueryParamsBuilder.php @@ -22,9 +22,11 @@ class QueryParamsBuilder protected string $indexName = ''; protected bool $searchAll = false; - public static function createQueryParamsBuilder(array $searchParams, array $settings): QueryParamsBuilder + // ToDo: @Matthias: check searchAll condition + + public static function createQueryParamsBuilder(array $searchParams, array $settings): self { - $queryParamsBuilder = new QueryParamsBuilder(); + $queryParamsBuilder = new self(); return $queryParamsBuilder-> setSettings($settings)-> @@ -65,7 +67,6 @@ public function setSearchParams($searchParams): QueryParamsBuilder return $this; } - //Todo: get Config for bibIndex, aggs etc. from extension config? public function getQueryParams(): array { $commonConf = GeneralUtility::makeInstance(ExtensionConfiguration::class)->get('liszt_common'); @@ -84,7 +85,7 @@ public function getQueryParams(): array ]; if ($this->searchAll == false) { - $this->query['body']['aggs'] = self::getAggs($this->settings, $this->indexName); + $this->query['body']['aggs'] = $this->getAggs(); } $this->setCommonParams(); @@ -95,78 +96,6 @@ public function getQueryParams(): array return $this->query; } - public function getCountQueryParams(): array - { - $this->query = [ 'body' => [ ] ]; - - $this->setCommonParams(); - -/* - $params = [ - //'index' => $bibIndex, - 'body' => [ ] - ]; - if (!isset($searchParams['searchText']) || $searchParams['searchText'] == '') { - $params['body']['query'] = [ - 'bool' => [ - 'must' => [[ - 'match_all' => new \stdClass() - ]] - ] - ]; - } else { - // search in field "fulltext" exakt phrase match boost over all words must contain - $params['body']['query'] = [ - 'bool' => [ - 'should' => [ - [ - 'match_phrase' => [ - 'tx_lisztcommon_searchable' => [ - 'query' => $searchParams['searchText'], - 'boost' => 2.0 // boosting for exakt phrases - ] - ] - ], - [ - 'query_string' => [ - 'query' => $searchParams['searchText'], - 'fields' => ['fulltext'], - 'default_operator' => 'AND' - ] - ] - ] - ] - ]; - } - - // Todo: automate the creation of parameters - if (isset($searchParams['f_itemType']) && $searchParams['f_itemType'] !== "") { - $params['body']['query']['bool']['filter'][] = ['term' => ['itemType.keyword' => $searchParams['f_itemType']]]; - } - if (isset($searchParams['f_place']) && $searchParams['f_place'] !== "") { - $params['body']['query']['bool']['filter'][] = ['term' => ['place.keyword' => $searchParams['f_place']]]; - } - if (isset($searchParams['f_date']) && $searchParams['f_date'] !== "") { - $params['body']['query']['bool']['filter'][] = ['term' => ['date.keyword' => $searchParams['f_date']]]; - } - // filter creators name, Todo: its not a filter query because they need 100% match (with spaces from f_creators_name) - // better would be to build the field 'fullName' at build time with PHP? - if (isset($searchParams['f_creators_name']) && $searchParams['f_creators_name'] !== "") { - $params['body']['query']['bool']['must'][] = [ - 'nested' => [ - 'path' => 'creators', - 'query' => [ - 'match' => [ - 'creators.fullName' => $searchParams['f_creators_name'] - ] - ] - ] - ]; - } - -*/ - return $this->query; - } private function getIndexName(): string { if (isset($this->params['index'])) { @@ -178,88 +107,136 @@ private function getIndexName(): string join(','); } - private static function getAggs(array $settings, string $index): array + private function getAggs(): array { - return Collection::wrap($settings)-> + $settings = $this->settings; + $index = $this->indexName; + $filterParams = $this->params['filter'] ?? []; + $filterTypes = $this->getFilterTypes(); + return Collection::wrap($settings)-> recursive()-> get('entityTypes')-> - filter(function($entityType) use ($index) {return $entityType->get('indexName') === $index;})-> + filter(function($entityTypes) use ($index) { + return $entityTypes->get('indexName') === $index; + })-> values()-> get(0)-> get('filters')-> - mapWithKeys(function($entityType) { - if ($entityType['type'] == 'terms') { - return [$entityType['field'] => [ - 'terms' => [ - 'field' => $entityType['field'] . '.keyword' - ] - ]]; - } - if ($entityType['type'] == 'keyword') { - return [$entityType['field'] => [ - 'terms' => [ - 'field' => $entityType['field'] - ] - ]]; - } - return [ - $entityType['field'] => [ - 'nested' => [ - 'path' => $entityType['field'] - ], - 'aggs' => [ - 'names' => [ - 'terms' => [ - 'script' => [ - 'source' => $entityType['script'], - 'lang' => 'painless' - ], - 'size' => 15, - ] - ] - ] - ] - ]; + mapWithKeys(function ($entityType) use ($filterParams, $filterTypes) { + return self::retrieveFilterParamsForEntityType($entityType, $filterParams, $filterTypes); })-> toArray(); } - private static function getFilter(array $field): array + private static function retrieveFilterParamsForEntityType( + Collection $entityType, + array $filterParams, + array $filterTypes + ): array { - if ( - isset($field['type']) && - $field['type'] == 'terms' - ) { - return [ - 'term' => [ - $field['name'] . '.keyword' => $field['value'] - ] + $entityField = $entityType['field']; + $entityTypeKey = $entityType['key'] ?? null; + $entityTypeMultiselect = $entityType['multiselect'] ?? null; + $entityTypeSize = $entityType['maxSize'] ?? 10; + + // create filter in aggs for filtering aggs (without filtering the current key for multiple selections if multiselect is set) + $filters = Collection::wrap($filterParams)-> + map(function ($value, $key) use ($entityField, $filterTypes) { + return self::retrieveFilterParamForEntityField($key, $value, $entityField, $filterTypes); + })-> + filter()-> + values()-> + toArray(); + + // return match_all if filters are empty because elasticsearch throws an error without the filter key + if (empty($filters)) { + $filters = [ + ['match_all' => (object) []] ]; } - if ( - isset($field['type']) && - $field['type'] == 'keyword' - ) { + // special aggs for nested fields + if ($entityType['type'] === 'nested') { + return [ - 'term' => [ - $field['name'] => $field['value'] + $entityType['field'] => [ + 'filter' => [ + 'bool' => [ + 'filter' => $filters + ] + ], + 'aggs' => [ + 'filtered_params' => [ + 'nested' => [ + 'path' => $entityField + ], + 'aggs' => [ + $entityField => [ + 'terms' => [ + 'field' => $entityField . '.' . $entityTypeKey . '.keyword', + 'size' => $entityTypeSize, + ] + ] + ] + ] + ] ] ]; + } + // all other (not nested fields) return [ - 'nested' => [ - 'path' => $field['name'], - 'query' => [ - 'match' => [ - $field['name'] . '.' . $field['path'] => $field['value'] + $entityField => [ + 'aggs' => [ + $entityField => [ + 'terms' => [ + 'field' => $entityField . '.keyword', + // show docs with count 0 only for multiple select fields + 'min_doc_count' => $entityTypeMultiselect ? 0 : 1, + 'size' => $entityTypeSize, + ] + ] + ], + 'filter' => [ + 'bool' => [ + 'filter' => $filters ] ] ] ]; } + private static function retrieveFilterParamForEntityField ( + string $key, + array $values, + string $entityField, + array $filterTypes + ): ?array + { + // exclude current key for multiple selects + if ($key === $entityField && isset($filterTypes[$key]['multiselect'])) { + return null; + } + // handle nested fields + if (($filterTypes[$key]['type'] == 'nested') && (isset($filterTypes[$key]['key']))) { + return [ + 'nested' => [ + 'path' => $key, + 'query' => [ + 'bool' => [ + 'filter' => [ + 'terms' => [ $key.'.'.$filterTypes[$key]['key'].'.keyword' => array_keys($values)] + ] + ] + ] + ] + ]; + } + // handle all other fields (not nested fields) + return ['terms' => [$key . '.keyword' => array_keys($values)]]; + } + /** * sets parameters needed for both search and count queries */ @@ -270,7 +247,7 @@ private function setCommonParams(): void $this->query['index'] = $index; // set body - if (!isset($this->params['searchText']) || $this->params['searchText'] == '') { + if (empty($this->params['searchText'])) { $this->query['body']['query'] = [ 'bool' => [ 'must' => [[ @@ -303,38 +280,69 @@ private function setCommonParams(): void ]; } - // set filters - if ($this->searchAll == false) { - $filterTypes = Collection::wrap($this->settings)-> - recursive()-> - get('entityTypes')-> - filter(function($entityType) use ($index) {return $entityType->get('indexName') === $index;})-> - values()-> - get(0)-> - get('filters')-> - mapWithKeys(function($filter) { return [ - $filter['field'] => [ - 'type' => $filter['type'], - 'path' => isset($filter['path']) ? $filter['path'] : '' - ]]; - })-> - all(); - - $query = $this->query; - Collection::wrap($this->params)-> - filter(function($_, $key) { return Str::of($key)->startsWith('f_'); })-> - each(function($value, $key) use (&$query, $filterTypes) { - $field = Str::of($key)->replace('f_', '')->__toString(); - $query['body']['query']['bool']['filter'][] = self::getFilter([ - 'name' => $field, - 'type' => $filterTypes[$field]['type'], - 'value' => $value, - 'path' => $filterTypes[$field]['path'] - ]); - }); - $this->query = $query; + $filterTypes = $this->getFilterTypes(); + $query = $this->query; + Collection::wrap($this->params['filter'] ?? []) + ->each(function($value, $key) use (&$query, $filterTypes) { + $value = array_keys($value); + if (($filterTypes[$key]['type'] == 'nested') && (isset($filterTypes[$key]['key']))) { + + // nested filter query (for multiple Names) + $query['body']['post_filter']['bool']['filter'][] = [ + 'nested' => [ + 'path' => $key, + 'query' => [ + 'terms' => [ + $key.'.'.$filterTypes[$key]['key'].'.keyword' => $value + ] + ] + ] + ]; + + } else { + + // post_filter, runs the search without considering the aggregations, for muliple select aggregations we run the filters again on each agg in getAggs() + $query['body']['post_filter']['bool']['filter'][] = [ + 'terms' => [ + $key . '.keyword' => $value + ] + ]; + } + }); + $this->query = $query; + + } + + /** + * Retrieves filter types based on the current indexName and settings from extension. + * + * @return array + */ + private function getFilterTypes(): array + { + $filters = Collection::wrap($this->settings) + ->recursive() + ->get('entityTypes') + ->filter(function ($entityType) { + return $entityType->get('indexName') === $this->indexName; + }) + ->values(); + if ($filters->count() === 0) { + return []; } + return $filters->get(0) + ->get('filters') + ->mapWithKeys(function ($filter) { + return [ + $filter['field'] => [ + 'type' => $filter['type'], + 'key' => $filter['key'] ?? '', + 'multiselect' => $filter['multiselect'] ?? null + ] + ]; + }) + ->all(); } } diff --git a/Classes/Controller/SearchController.php b/Classes/Controller/SearchController.php index 823bc96..2896502 100644 --- a/Classes/Controller/SearchController.php +++ b/Classes/Controller/SearchController.php @@ -42,17 +42,24 @@ public function indexAction(array $searchParams = []): ResponseInterface $currentPage = 1; } - $totalItems = $this->elasticSearchService->count($searchParams, $this->settings); - $pagination = Paginator::createPagination($currentPage, $totalItems, $this->extConf); + // $totalItems = $this->elasticSearchService->count($searchParams, $this->settings); + //$totalItems = 100; $elasticResponse = $this->elasticSearchService->search($searchParams, $this->settings); + $paginator = (new Paginator())-> + setPage($currentPage)-> + setTotalItems($elasticResponse['hits']['total']['value'])-> + setExtensionConfiguration($this->extConf); + $pagination = $paginator->getPagination(); + $showPagination = $paginator->getTotalPages() > 1 ? true : false; $this->view->assign('locale', $locale); $this->view->assign('totalItems', $elasticResponse['hits']['total']['value']); $this->view->assign('searchParams', $searchParams); $this->view->assign('searchResults', $elasticResponse); $this->view->assign('pagination', $pagination); - $this->view->assign('totalItems', $totalItems); + $this->view->assign('showPagination', $showPagination); + // $this->view->assign('totalItems', $totalItems); $this->view->assign('currentString', Paginator::CURRENT_PAGE); $this->view->assign('dots', Paginator::DOTS); diff --git a/Classes/Interfaces/ElasticSearchServiceInterface.php b/Classes/Interfaces/ElasticSearchServiceInterface.php index 280e92d..90a7102 100644 --- a/Classes/Interfaces/ElasticSearchServiceInterface.php +++ b/Classes/Interfaces/ElasticSearchServiceInterface.php @@ -11,6 +11,6 @@ public function getElasticInfo(): array; public function search(array $searchParams, array $settings): Collection; - public function count(array $searchParams, array $settings): int; + // public function count(array $searchParams, array $settings): int; } diff --git a/Classes/Services/ElasticSearchService.php b/Classes/Services/ElasticSearchService.php index 493ae55..82a4390 100644 --- a/Classes/Services/ElasticSearchService.php +++ b/Classes/Services/ElasticSearchService.php @@ -45,7 +45,6 @@ public function search(array $searchParams, array $settings): Collection { $this->init(); $this->params = QueryParamsBuilder::createQueryParamsBuilder($searchParams, $settings)->getQueryParams(); - // ToDo: handle exceptions! $response = $this->client->search($this->params)->asArray(); $aggs = $response['aggregations']; @@ -64,13 +63,4 @@ public function search(array $searchParams, array $settings): Collection return new Collection($response); } - - public function count(array $searchParams, array $settings): int - { - $this->init(); - $this->params = QueryParamsBuilder::createQueryParamsBuilder($searchParams, $settings)->getCountQueryParams(); - $response = $this->client->count($this->params); - return $response['count']; - } - } diff --git a/Classes/ViewHelpers/GetFilterEntitiesViewHelper.php b/Classes/ViewHelpers/GetFilterEntitiesViewHelper.php new file mode 100644 index 0000000..f736216 --- /dev/null +++ b/Classes/ViewHelpers/GetFilterEntitiesViewHelper.php @@ -0,0 +1,37 @@ +registerArgument('entityTypes', 'array', 'The settings.entityTypes array', true); + $this->registerArgument('filterKey', 'string', 'The field key to filter for', true); + } + + public static function renderStatic( + array $arguments, + \Closure $renderChildrenClosure, + RenderingContextInterface $renderingContext): array + { + $entityTypes = $arguments['entityTypes']; + $filterKey = $arguments['filterKey']; + + foreach ($entityTypes as $entityType) { + if (!empty($entityType['filters']) && is_array($entityType['filters'])) { + foreach ($entityType['filters'] as $filter) { + if (!empty($filter['field']) && $filter['field'] === $filterKey) { + return array_merge($entityType, $filter); + } + } + } + } + + return []; //if nothing is found + } +} diff --git a/Classes/ViewHelpers/GetValueByKeyPathViewHelper.php b/Classes/ViewHelpers/GetValueByKeyPathViewHelper.php new file mode 100644 index 0000000..b524fdd --- /dev/null +++ b/Classes/ViewHelpers/GetValueByKeyPathViewHelper.php @@ -0,0 +1,44 @@ +registerArgument('data', 'array', 'The array to search in', true); + $this->registerArgument('keys', 'array', 'An array of keys defining the path to the desired value', true); + } + + /** + * Resolve a value in a deeply nested array by following an array of keys + * + * @return mixed|null + */ + public function render() + { + $data = $this->arguments['data']; + $keys = $this->arguments['keys']; + + foreach ($keys as $key) { + if (is_array($data) && array_key_exists($key, $data)) { + $data = $data[$key]; + } else { + // Key does not exist, return null + return null; + } + } + + return $data; + } +} diff --git a/Classes/ViewHelpers/ProcessFacetsViewHelper.php b/Classes/ViewHelpers/ProcessFacetsViewHelper.php new file mode 100644 index 0000000..e29677e --- /dev/null +++ b/Classes/ViewHelpers/ProcessFacetsViewHelper.php @@ -0,0 +1,65 @@ +registerArgument('filterGroup', 'array', 'Array with facets from solr', true); + $this->registerArgument('key', 'string', 'key of the current facet', true); + $this->registerArgument('searchParams', 'array', 'Array with search params from url', true); + $this->registerArgument('filterEntities', 'array', 'Array with settings for filters from setup.typoscript', false, []); + } + + public static function renderStatic( + array $arguments, + \Closure $renderChildrenClosure, + RenderingContextInterface $renderingContext): array + { + + $filterGroup = $arguments['filterGroup']; + $key = $arguments['key']; + $searchParams = $arguments['searchParams']; + $returnBucket = []; + $filterEntities = $arguments['filterEntities']; + + // check if buckets exists on "normal" not nested filters + if (isset($filterGroup[$key]['buckets'])) { + $returnBucket = $filterGroup[$key]['buckets']; + } + + // check buckets on nested filters + if (isset($filterGroup['filtered_params'][$key]['buckets'])) { + $returnBucket = $filterGroup['filtered_params'][$key]['buckets']; + } + + // set size from entity settings in setup.typoscript or use 10 as default + $size = $filterEntities['size'] ?? $filterEntities['defaultFilterSize'] ?? 10; + + + // find active filter items and set selected and set hidden for items over size + foreach ($returnBucket as $index => &$item) { + $filterKey = $item['key'] ?? null; + $item['selected'] = isset($searchParams['filter'][$key][$filterKey]) + && $searchParams['filter'][$key][$filterKey] == 1; + + // if item is over $size set 'hidden' => true + if ($index >= $size && !$item['selected']) { + $item['hidden'] = true; + } + } + + // Remove items that are not selected and have a doc_count of 0 + $returnBucket = array_filter($returnBucket, function ($item) { + return $item['doc_count'] > 0 || ($item['selected'] ?? false); + }); + + return $returnBucket; + + } +} diff --git a/Classes/ViewHelpers/SearchParamsViewHelper.php b/Classes/ViewHelpers/SearchParamsViewHelper.php index 10b7fc2..0e16aa9 100644 --- a/Classes/ViewHelpers/SearchParamsViewHelper.php +++ b/Classes/ViewHelpers/SearchParamsViewHelper.php @@ -25,10 +25,25 @@ public static function renderStatic( $value = $arguments['value'] ?? null; $searchParamsArray = $arguments['searchParamsArray']; - if ($action === 'add') { - $searchParamsArray[$key] = $value; - } elseif ($action === 'remove') { - unset($searchParamsArray[$key]); + switch ($action) { + case 'add': + $searchParamsArray[$key] = $value; + break; + + case 'remove': + unset($searchParamsArray[$key]); + break; + // later here are special values possible like "disableFilter" with value=0 + case 'addFilter': + $searchParamsArray['filter'][$key][$value] = 1; + break; + + case 'removeFilter': + unset($searchParamsArray['filter'][$key][$value]); + break; + + default: + break; } // Convert the array to a string formatted as {key: 'value', key2: 'value2'} diff --git a/Resources/Private/Language/de.locallang.xlf b/Resources/Private/Language/de.locallang.xlf index 28c7178..a993c6d 100644 --- a/Resources/Private/Language/de.locallang.xlf +++ b/Resources/Private/Language/de.locallang.xlf @@ -30,6 +30,15 @@ Filtermenü schließen + + Filter entfernen + + + Filter auswählen + + + Mehr anzeigen + Treffer diff --git a/Resources/Private/Language/locallang.xlf b/Resources/Private/Language/locallang.xlf index c7918be..1f8da97 100644 --- a/Resources/Private/Language/locallang.xlf +++ b/Resources/Private/Language/locallang.xlf @@ -30,6 +30,15 @@ Filtermenü schließen + + Filter entfernen + + + Filter auswählen + + + Mehr anzeigen + Treffer diff --git a/Resources/Private/Partials/FilterBlock.html b/Resources/Private/Partials/FilterBlock.html index 88b11e3..3fda5d2 100644 --- a/Resources/Private/Partials/FilterBlock.html +++ b/Resources/Private/Partials/FilterBlock.html @@ -1,38 +1,23 @@ {namespace lc=Slub\LisztCommon\ViewHelpers} - -
-

{key}

- f_{key} {lc:searchParams(action: 'remove', searchParamsArray: searchParams, key: 'page')} {paramsRemovePage.searchParams} - -
- + {lc:getFilterEntities(filterKey: key, entityTypes: settings.entityTypes)} + {f:if(condition: filterEntities.size, then: filterEntities.size, else: filterEntities.defaultFilterSize)} + {lc:processFacets(filterGroup: filterGroup, key: key, searchParams: searchParams, filterEntities: filterEntities)} + +
+

{f:translate(key: '{languageFilePath}:{key}', default: '{key}')}

+ + + + +
+
diff --git a/Resources/Private/Partials/FilterBlockItem.html b/Resources/Private/Partials/FilterBlockItem.html new file mode 100644 index 0000000..6c9de08 --- /dev/null +++ b/Resources/Private/Partials/FilterBlockItem.html @@ -0,0 +1,18 @@ +{namespace lc=Slub\LisztCommon\ViewHelpers} + + +
  • + + + {f:translate(key: '{languageFilePath}:{key}_{filter.key}', default: '{filter.key}')} + {filter.doc_count} + + +
  • + diff --git a/Resources/Private/Templates/Search/Index.html b/Resources/Private/Templates/Search/Index.html index 4a3ce6f..12bfb7a 100644 --- a/Resources/Private/Templates/Search/Index.html +++ b/Resources/Private/Templates/Search/Index.html @@ -4,28 +4,33 @@ xmlns:f="http://typo3.org/ns/TYPO3/CMS/Fluid/ViewHelpers" xmlns:i="http://typo3.org/ns/Quellenform/Iconpack/ViewHelpers" data-namespace-typo3-fluid="true"> - +LLL:EXT:{settings.entityTypes.1.extensionName}/Resources/Private/Language/{settings.entityTypes.1.languageFile}.xlf
    {totalItems} {f:translate(key: 'searchResults_hits_label', extensionName: 'liszt_common')} -
    - Remove Page param from searchparams array for display filter tags - {lc:searchParams(action: 'remove', searchParamsArray: searchParams, key: 'page')} - -
    - - - - - - +
    @@ -73,6 +73,8 @@

    - + + + diff --git a/Tests/Unit/Common/QueryParamsBuilderTest.php b/Tests/Unit/Common/QueryParamsBuilderTest.php index c80de4b..cf9a1ee 100644 --- a/Tests/Unit/Common/QueryParamsBuilderTest.php +++ b/Tests/Unit/Common/QueryParamsBuilderTest.php @@ -39,7 +39,7 @@ protected function setUp(): void $this->subject = new QueryParamsBuilder(); $this->settings = []; $this->params = [ - 'index' => self:: EX_INDEX, + 'index' => self::EX_INDEX, 'page' => 3, 'f_filter' => self::EX_VAL ]; @@ -130,12 +130,12 @@ public function emptySearchParamsAreProcessedCorrectly(): void /** * @test */ - public function IndexParamIsProcessedCorrectly(): void + public function indexParamIsProcessedCorrectly(): void { $this->subject-> setSettings($this->settings)-> setSearchParams([ - 'index' => self:: EX_INDEX + 'index' => self::EX_INDEX ]); GeneralUtility::addInstance(ExtensionConfiguration::class, $this->extConf); @@ -153,27 +153,61 @@ public function IndexParamIsProcessedCorrectly(): void ], 'aggs' => [ self::EX_FIELD1 => [ - 'terms' => [ - 'field' => self::EX_FIELD1 . '.keyword' + 'aggs' => [ + self::EX_FIELD1 => [ + 'terms' => [ + 'field' => self::EX_FIELD1 . '.keyword', + 'min_doc_count' => 1, + 'size' => 10 + ] + ] + ], + 'filter' => [ + 'bool' => [ + 'filter' => [ + [ 'match_all' => new \StdClass() ] + ] + ] ] ], self::EX_FIELD2 => [ - 'terms' => [ - 'field' => self::EX_FIELD2 + 'aggs' => [ + self::EX_FIELD2 => [ + 'terms' => [ + 'field' => self::EX_FIELD2 . '.keyword', + 'min_doc_count' => 1, + 'size' => 10 + ] + ] + ], + 'filter' => [ + 'bool' => [ + 'filter' => [ + [ 'match_all' => new \StdClass() ] + ] + ] ] ], self::EX_FIELD3 => [ - 'nested' => [ - 'path' => self::EX_FIELD3 - ], 'aggs' => [ - 'names' => [ - 'terms' => [ - 'script' => [ - 'source' => self::EX_SCRIPT, - 'lang' => 'painless' - ], - 'size' => 15 + 'filtered_params' => [ + 'aggs' => [ + self::EX_FIELD3 => [ + 'terms' => [ + 'field' => self::EX_FIELD3 . '..keyword', + 'size' => 10 + ] + ] + ], + 'nested' => [ + 'path' => self::EX_FIELD3 + ] + ] + ], + 'filter' => [ + 'bool' => [ + 'filter' => [ + [ 'match_all' => new \StdClass() ] ] ] ] @@ -234,13 +268,17 @@ public function pageParamIsProcessedCorrectly(): void /** * @test */ - public function termsFilterParamIsProcessedCorrectly(): void + public function keywordFilterParamIsProcessedCorrectly(): void { $this->subject-> setSettings($this->settings)-> setSearchParams([ - 'index' => self:: EX_INDEX, - 'f_' . self::EX_FIELD1 => self::EX_VAL + 'index' => self::EX_INDEX, + 'filter' => [ + self::EX_FIELD2 => [ + self::EX_VAL => 1 + ] + ] ]); GeneralUtility::addInstance(ExtensionConfiguration::class, $this->extConf); @@ -258,99 +296,67 @@ public function termsFilterParamIsProcessedCorrectly(): void ], 'aggs' => [ self::EX_FIELD1 => [ - 'terms' => [ - 'field' => self::EX_FIELD1 . '.keyword' - ] - ], - self::EX_FIELD2 => [ - 'terms' => [ - 'field' => self::EX_FIELD2 - ] - ], - self::EX_FIELD3 => [ - 'nested' => [ - 'path' => self::EX_FIELD3 - ], 'aggs' => [ - 'names' => [ + self::EX_FIELD1 => [ 'terms' => [ - 'script' => [ - 'source' => self::EX_SCRIPT, - 'lang' => 'painless' - ], - 'size' => 15 + 'field' => self::EX_FIELD1 . '.keyword', + 'min_doc_count' => 1, + 'size' => 10 ] ] - ] - ] - ], - 'query' => [ - 'bool' => [ - 'must' => [ - [ 'match_all' => new \StdClass() ] ], 'filter' => [ - [ 'term' => [ - self::EX_FIELD1 . '.keyword' => self::EX_VAL + 'bool' => [ + 'filter' => [ + [ 'terms' => [ + self::EX_FIELD2 . '.keyword' => [ self::EX_VAL ] + ] ] ] ] ] - ] - ] - ] - ]; - - self::assertEquals($expected, $this->subject->getQueryParams()); - } - - /** - * @test - */ - public function keywordFilterParamIsProcessedCorrectly(): void - { - $this->subject-> - setSettings($this->settings)-> - setSearchParams([ - 'index' => self:: EX_INDEX, - 'f_' . self::EX_FIELD2 => self::EX_VAL - ]); - GeneralUtility::addInstance(ExtensionConfiguration::class, $this->extConf); - - $expected = [ - 'index' => self::EX_INDEX, - 'size' => PaginatorTest::ITEMS_PER_PAGE, - 'body' => [ - '_source' => [ - QueryParamsBuilder::TYPE_FIELD, - QueryParamsBuilder::HEADER_FIELD, - QueryParamsBuilder::BODY_FIELD, - QueryParamsBuilder::FOOTER_FIELD, - QueryParamsBuilder::SEARCHABLE_FIELD - - ], - 'aggs' => [ - self::EX_FIELD1 => [ - 'terms' => [ - 'field' => self::EX_FIELD1 . '.keyword' - ] ], self::EX_FIELD2 => [ - 'terms' => [ - 'field' => self::EX_FIELD2 + 'aggs' => [ + self::EX_FIELD2 => [ + 'terms' => [ + 'field' => self::EX_FIELD2 . '.keyword', + 'min_doc_count' => 1, + 'size' => 10 + ] + ] + ], + 'filter' => [ + 'bool' => [ + 'filter' => [ + [ 'terms' => [ + self::EX_FIELD2 . '.keyword' => [ self::EX_VAL ] + ] ] + ] + ] ] ], self::EX_FIELD3 => [ - 'nested' => [ - 'path' => self::EX_FIELD3 - ], 'aggs' => [ - 'names' => [ - 'terms' => [ - 'script' => [ - 'source' => self::EX_SCRIPT, - 'lang' => 'painless' - ], - 'size' => 15 + 'filtered_params' => [ + 'aggs' => [ + self::EX_FIELD3 => [ + 'terms' => [ + 'field' => self::EX_FIELD3 . '..keyword', + 'size' => 10 + ] + ] + ], + 'nested' => [ + 'path' => self::EX_FIELD3 + ] + ] + ], + 'filter' => [ + 'bool' => [ + 'filter' => [ + [ 'terms' => [ + self::EX_FIELD2 . '.keyword' => [ self::EX_VAL ] + ] ] ] ] ] @@ -360,14 +366,17 @@ public function keywordFilterParamIsProcessedCorrectly(): void 'bool' => [ 'must' => [ [ 'match_all' => new \StdClass() ] - ], - 'filter' => [ - [ 'term' => [ - self::EX_FIELD2 => self::EX_VAL - ] - ] ] ] + ], + 'post_filter' => [ + 'bool' => [ + 'filter' => [ [ + 'terms' => [ + self::EX_FIELD2 . '.keyword' => [ self::EX_VAL ] + ] + ] ] + ] ] ] ]; @@ -383,8 +392,12 @@ public function nestedFilterParamIsProcessedCorrectly(): void $this->subject-> setSettings($this->settings)-> setSearchParams([ - 'index' => self:: EX_INDEX, - 'f_' . self::EX_FIELD3 => self::EX_VAL + 'index' => self::EX_INDEX, + 'filter' => [ + self::EX_FIELD3 => [ + self::EX_VAL => 1 + ] + ] ]); GeneralUtility::addInstance(ExtensionConfiguration::class, $this->extConf); @@ -402,87 +415,123 @@ public function nestedFilterParamIsProcessedCorrectly(): void ], 'aggs' => [ self::EX_FIELD1 => [ - 'terms' => [ - 'field' => self::EX_FIELD1 . '.keyword' + 'aggs' => [ + self::EX_FIELD1 => [ + 'terms' => [ + 'field' => self::EX_FIELD1 . '.keyword', + 'min_doc_count' => 1, + 'size' => 10 + ] + ] + ], + 'filter' => [ + 'bool' => [ + 'filter' => [ + [ 'nested' => [ + 'path' => self::EX_FIELD3, + 'query' => [ + 'bool' => [ + 'filter' => [ + 'terms' => [ + self::EX_FIELD3 . '..keyword' => [ self::EX_VAL ] + ] + ] + ] + ] + ] ] + ] + ] ] ], self::EX_FIELD2 => [ - 'terms' => [ - 'field' => self::EX_FIELD2 + 'aggs' => [ + self::EX_FIELD2 => [ + 'terms' => [ + 'field' => self::EX_FIELD2 . '.keyword', + 'min_doc_count' => 1, + 'size' => 10 + ] + ] + ], + 'filter' => [ + 'bool' => [ + 'filter' => [ + [ 'nested' => [ + 'path' => self::EX_FIELD3, + 'query' => [ + 'bool' => [ + 'filter' => [ + 'terms' => [ + self::EX_FIELD3 . '..keyword' => [ self::EX_VAL ] + ] + ] + ] + ] + ] ] + ] + ] ] ], self::EX_FIELD3 => [ - 'nested' => [ - 'path' => self::EX_FIELD3 - ], 'aggs' => [ - 'names' => [ - 'terms' => [ - 'script' => [ - 'source' => self::EX_SCRIPT, - 'lang' => 'painless' - ], - 'size' => 15 + 'filtered_params' => [ + 'aggs' => [ + self::EX_FIELD3 => [ + 'terms' => [ + 'field' => self::EX_FIELD3 . '..keyword', + 'size' => 10 + ] + ] + ], + 'nested' => [ + 'path' => self::EX_FIELD3 ] ] - ] - ] - ], - 'query' => [ - 'bool' => [ - 'must' => [ - [ 'match_all' => new \StdClass() ] ], 'filter' => [ - [ 'nested' => [ - 'path' => self::EX_FIELD3, - 'query' => [ - 'match' => [ - self::EX_FIELD3 . '.' . self::EX_PATH => self::EX_VAL + 'bool' => [ + 'filter' => [ + [ 'nested' => [ + 'path' => self::EX_FIELD3, + 'query' => [ + 'bool' => [ + 'filter' => [ + 'terms' => [ + self::EX_FIELD3 . '..keyword' => [ self::EX_VAL ] + ] + ] + ] ] - ] + ] ] ] ] ] ] - ] - ] - ]; - - self::assertEquals($expected, $this->subject->getQueryParams()); - } - - /** - * @test - */ - public function countQueryIsBuiltCorrectly(): void - { - $this->subject-> - setSettings($this->settings)-> - setSearchParams([ - 'index' => self:: EX_INDEX, - 'f_' . self::EX_FIELD1 => self::EX_VAL - ]); - - $expected = [ - 'index' => self::EX_INDEX, - 'body' => [ + ], 'query' => [ 'bool' => [ 'must' => [ [ 'match_all' => new \StdClass() ] - ], - 'filter' => [ - [ 'term' => [ - self::EX_FIELD1 . '.keyword' => self::EX_VAL + ] + ] + ], + 'post_filter' => [ + 'bool' => [ + 'filter' => [ [ + 'nested' => [ + 'path' => self::EX_FIELD3, + 'query' => [ + 'terms' => [ + self::EX_FIELD3 . '..keyword' => [ self::EX_VAL ] + ] ] ] - ] + ] ] ] ] ] ]; - self::assertEquals($expected, $this->subject->getCountQueryParams()); + self::assertEquals($expected, $this->subject->getQueryParams()); } }