Skip to content

Commit 1632ea7

Browse files
damcoubsuravech
andauthored
Add Disjunctive facets compatibility for Client V2.0 (#990)
Co-authored-by: Betty Suravech <[email protected]>
1 parent 0a3266a commit 1632ea7

File tree

1 file changed

+128
-5
lines changed

1 file changed

+128
-5
lines changed

Helper/AlgoliaHelper.php

Lines changed: 128 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,10 @@ public function query($indexName, $q, $params)
109109
{
110110
$this->checkClient(__FUNCTION__);
111111

112+
if (isset($params['disjunctiveFacets'])) {
113+
return $this->searchWithDisjunctiveFaceting($indexName, $q, $params);
114+
}
115+
112116
return $this->client->initIndex($indexName)->search($q, $params);
113117
}
114118

@@ -491,7 +495,7 @@ private function prepareRecords(&$objects, $indexName)
491495

492496
if ($object === false) {
493497
$longestAttribute = $this->getLongestAttribute($previousObject);
494-
$modifiedIds[] = $indexName . '
498+
$modifiedIds[] = $indexName . '
495499
- ID ' . $previousObject['objectID'] . ' - skipped - longest attribute: ' . $longestAttribute;
496500

497501
unset($objects[$key]);
@@ -506,10 +510,10 @@ private function prepareRecords(&$objects, $indexName)
506510
if ($modifiedIds && $modifiedIds !== []) {
507511
$separator = php_sapi_name() === 'cli' ? "\n" : '<br>';
508512

509-
$errorMessage = 'Algolia reindexing:
510-
You have some records which are too big to be indexed in Algolia.
511-
They have either been truncated
512-
(removed attributes: ' . implode(', ', $this->potentiallyLongAttributes) . ')
513+
$errorMessage = 'Algolia reindexing:
514+
You have some records which are too big to be indexed in Algolia.
515+
They have either been truncated
516+
(removed attributes: ' . implode(', ', $this->potentiallyLongAttributes) . ')
513517
or skipped completely: ' . $separator . implode($separator, $modifiedIds);
514518

515519
if (php_sapi_name() === 'cli') {
@@ -665,4 +669,123 @@ private function calculateObjectSize($object)
665669
{
666670
return mb_strlen(json_encode($object));
667671
}
672+
673+
protected function searchWithDisjunctiveFaceting($indexName, $q, $params)
674+
{
675+
if (! is_array($params['disjunctiveFacets']) || count($params['disjunctiveFacets']) <= 0) {
676+
throw new \InvalidArgumentException('disjunctiveFacets needs to be an non empty array');
677+
}
678+
679+
if (isset($params['filters'])) {
680+
throw new \InvalidArgumentException('You can not use disjunctive faceting and the filters parameter');
681+
}
682+
683+
/**
684+
* Prepare queries
685+
*/
686+
// Get the list of disjunctive queries to do: 1 per disjunctive facet
687+
$disjunctiveQueries = $this->getDisjunctiveQueries($params);
688+
689+
// Format disjunctive queries for multipleQueries call
690+
foreach ($disjunctiveQueries as &$disjunctiveQuery) {
691+
$disjunctiveQuery['indexName'] = $indexName;
692+
$disjunctiveQuery['query'] = $q;
693+
unset($disjunctiveQuery['disjunctiveFacets']);
694+
}
695+
696+
// Merge facets and disjunctiveFacets for the hits query
697+
$facets = isset($params['facets']) ? $params['facets'] : [];
698+
$facets = array_merge($facets, $params['disjunctiveFacets']);
699+
unset($params['disjunctiveFacets']);
700+
701+
// format the hits query for multipleQueries call
702+
$params['query'] = $q;
703+
$params['indexName'] = $indexName;
704+
$params['facets'] = $facets;
705+
706+
// Put the hit query first
707+
array_unshift($disjunctiveQueries, $params);
708+
709+
/**
710+
* Do all queries in one call
711+
*/
712+
$results = $this->client->multipleQueries(array_values($disjunctiveQueries));
713+
$results = $results['results'];
714+
715+
/**
716+
* Merge facets from disjunctive queries with facets from the hits query
717+
*/
718+
// The first query is the hits query that the one we'll return to the user
719+
$queryResults = array_shift($results);
720+
721+
// To be able to add facets from disjunctive query we create 'facets' key in case we only have disjunctive facets
722+
if (false === isset($queryResults['facets'])) {
723+
$queryResults['facets'] =[];
724+
}
725+
726+
foreach ($results as $disjunctiveResults) {
727+
if (isset($disjunctiveResults['facets'])) {
728+
foreach ($disjunctiveResults['facets'] as $facetName => $facetValues) {
729+
$queryResults['facets'][$facetName] = $facetValues;
730+
}
731+
}
732+
}
733+
734+
return $queryResults;
735+
}
736+
737+
protected function getDisjunctiveQueries($queryParams)
738+
{
739+
$queriesParams = [];
740+
741+
foreach ($queryParams['disjunctiveFacets'] as $facetName) {
742+
$params = $queryParams;
743+
$params['facets'] = [$facetName];
744+
$facetFilters = isset($params['facetFilters']) ? $params['facetFilters'] : [];
745+
$numericFilters = isset($params['numericFilters']) ? $params['numericFilters'] : [];
746+
747+
$additionalParams = [
748+
'hitsPerPage' => 1,
749+
'page' => 0,
750+
'attributesToRetrieve' => [],
751+
'attributesToHighlight' => [],
752+
'attributesToSnippet' => [],
753+
'analytics' => false,
754+
];
755+
756+
$additionalParams['facetFilters'] =
757+
$this->getAlgoliaFiltersArrayWithoutCurrentRefinement($facetFilters, $facetName . ':');
758+
$additionalParams['numericFilters'] =
759+
$this->getAlgoliaFiltersArrayWithoutCurrentRefinement($numericFilters, $facetName);
760+
761+
$queriesParams[$facetName] = array_merge($params, $additionalParams);
762+
}
763+
764+
return $queriesParams;
765+
}
766+
767+
protected function getAlgoliaFiltersArrayWithoutCurrentRefinement($filters, $needle)
768+
{
769+
// iterate on each filters which can be string or array and filter out every refinement matching the needle
770+
for ($i = 0; $i < count($filters); $i++) {
771+
if (is_array($filters[$i])) {
772+
foreach ($filters[$i] as $filter) {
773+
if (mb_substr($filter, 0, mb_strlen($needle)) === $needle) {
774+
unset($filters[$i]);
775+
$filters = array_values($filters);
776+
$i--;
777+
break;
778+
}
779+
}
780+
} else {
781+
if (mb_substr($filters[$i], 0, mb_strlen($needle)) === $needle) {
782+
unset($filters[$i]);
783+
$filters = array_values($filters);
784+
$i--;
785+
}
786+
}
787+
}
788+
789+
return $filters;
790+
}
668791
}

0 commit comments

Comments
 (0)