getResponse(); $fieldName = $facetConfiguration['field']; $label = $this->getPlainLabelOrApplyCObject($facetConfiguration); $optionsFromMeilisearchResponse = isset($response->facet_counts->facet_fields->{$fieldName}) ? ParsingUtil::getMapArrayFromFlatArray($response->facet_counts->facet_fields->{$fieldName}) : []; $optionsFromRequest = $this->getActiveFacetValuesFromRequest($resultSet, $facetName); $hasOptionsInResponse = !empty($optionsFromMeilisearchResponse); $hasSelectedOptionsInRequest = count($optionsFromRequest) > 0; $hasNoOptionsToShow = !$hasOptionsInResponse && !$hasSelectedOptionsInRequest; $hideEmpty = !$resultSet->getUsedSearchRequest()->getContextTypoScriptConfiguration()->getSearchFacetingShowEmptyFacetsByName($facetName); if ($hasNoOptionsToShow && $hideEmpty) { return null; } /** @var $facet HierarchyFacet */ $facet = $this->objectManager->get(HierarchyFacet::class, $resultSet, $facetName, $fieldName, $label, $facetConfiguration); $hasActiveOptions = count($optionsFromRequest) > 0; $facet->setIsUsed($hasActiveOptions); $facet->setIsAvailable($hasOptionsInResponse); $nodesToCreate = $this->getMergedFacetValueFromSearchRequestAndMeilisearchResponse($optionsFromMeilisearchResponse, $optionsFromRequest); if ($this->facetOptionsMustBeResorted($facetConfiguration)) { $nodesToCreate = $this->sortFacetOptionsInNaturalOrder($nodesToCreate); } foreach ($nodesToCreate as $value => $count) { if ($this->getIsExcludedFacetValue($value, $facetConfiguration)) { continue; } $isActive = in_array($value, $optionsFromRequest); $delimiterPosition = strpos($value, '-'); $path = substr($value, $delimiterPosition + 1); $pathArray = $this->getPathAsArray($path); $key = array_pop($pathArray); $parentKey = array_pop($pathArray); $value = '/' . $path; $label = $this->getLabelFromRenderingInstructions($key, $count, $facetName, $facetConfiguration); $facet->createNode($parentKey, $key, $label, $value, $count, $isActive); } return $facet; } /** * Sorts facet options in natural order. * Options must be sorted in natural order, * because lower nesting levels must be instantiated first, to serve as parents for higher nested levels. * See implementation of HierarchyFacet::createNode(). * * @param array $flatOptionsListForFacet * @return void sorted list of facet options */ protected function sortFacetOptionsInNaturalOrder(array $flatOptionsListForHierarchyFacet) { uksort($flatOptionsListForHierarchyFacet, "strnatcmp"); return $flatOptionsListForHierarchyFacet; } /** * Checks if options must be resorted. * * Meilisearch facet.sort can be set globally or per facet. * Relevant TypoScript paths: * plugin.tx_meilisearch.search.faceting.sortBy causes facet.sort Meilisearch parameter * plugin.tx_meilisearch.search.faceting.facets.[facetName].sortBy causes f..facet.sort parameter * * see: https://lucene.apache.org/meilisearch/guide/6_6/faceting.html#Faceting-Thefacet.sortParameter * see: https://wiki.apache.org/meilisearch/SimpleFacetParameters#facet.sort : "This parameter can be specified on a per field basis." * * @param array $facetConfiguration * @return bool */ protected function facetOptionsMustBeResorted(array $facetConfiguration) { if (isset($facetConfiguration['sortBy']) && $facetConfiguration['sortBy'] === 'index') { return true; } return false; } /** * This method is used to get the path array from a hierarchical facet. It substitutes escaped slashes to keep them * when they are used inside a facetValue. * * @param string $path * @return array */ protected function getPathAsArray($path) { $path = str_replace('\/', '@@@', $path); $path = rtrim($path, "/"); $segments = explode('/', $path); return array_map(function($item) { return str_replace('@@@', '/', $item); }, $segments); } /** * Retrieves the active facetValue for a facet from the search request. * @param SearchResultSet $resultSet * @param string $facetName * @return array */ protected function getActiveFacetValuesFromRequest(SearchResultSet $resultSet, $facetName) { $activeFacetValues = []; $values = $resultSet->getUsedSearchRequest()->getActiveFacetValuesByName($facetName); foreach (is_array($values) ? $values : [] as $valueFromRequest) { // Attach the 'depth' param again to the value if (strpos($valueFromRequest, '-') === false) { $valueFromRequest = HierarchyTool::substituteSlashes($valueFromRequest); $valueFromRequest = trim($valueFromRequest, '/'); $valueFromRequest = (count(explode('/', $valueFromRequest)) - 1) . '-' . $valueFromRequest . '/'; $valueFromRequest = HierarchyTool::unSubstituteSlashes($valueFromRequest); } $activeFacetValues[] = $valueFromRequest; } return $activeFacetValues; } }