Skip to content
Snippets Groups Projects

Draft: Resolve #3024266 "Avoid multiple results"

1 file
+ 69
53
Compare changes
  • Side-by-side
  • Inline
@@ -2,7 +2,7 @@
namespace Drupal\search_api_autocomplete\Controller;
use Drupal\Component\Utility\DeprecationHelper;
use Drupal\Component\Transliteration\TransliterationInterface;
use Drupal\Core\Controller\ControllerBase;
use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
use Drupal\Core\Render\RendererInterface;
@@ -14,7 +14,6 @@ use Psr\Log\LoggerInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Drupal\Component\Transliteration\TransliterationInterface;
/**
* Provides a controller for autocompletion.
@@ -99,7 +98,7 @@ class AutocompleteController extends ControllerBase implements ContainerInjectio
$suggesters = $search->getSuggesters();
$suggester_weights = $search->getSuggesterWeights();
$suggester_weights = array_intersect_key($suggester_weights, $suggesters);
$suggester_weights += array_fill_keys(array_keys($suggesters), 0);
$suggester_weights = array_fill_keys(array_keys($suggesters), 0);
asort($suggester_weights);
/** @var \Drupal\search_api_autocomplete\Suggestion\SuggestionInterface[] $suggestions */
@@ -122,8 +121,7 @@ class AutocompleteController extends ControllerBase implements ContainerInjectio
// Add suggestions in a loop so we're sure they're numerically
// indexed.
$new_suggestions = $suggesters[$suggester_id]
->getAutocompleteSuggestions($tmp_query, $incomplete, $keys);
$new_suggestions = $suggesters[$suggester_id]->getAutocompleteSuggestions($tmp_query, $incomplete, $keys);
foreach ($new_suggestions as $suggestion) {
$suggestions[] = $suggestion;
@@ -144,54 +142,7 @@ class AutocompleteController extends ControllerBase implements ContainerInjectio
$this->moduleHandler()
->alter('search_api_autocomplete_suggestions', $suggestions, $alter_params);
// Then, add the suggestions to the $matches return array in the form
// expected by Drupal's autocomplete Javascript.
$show_count = $search->getOption('show_count');
foreach ($suggestions as $suggestion) {
// If "Display result count estimates" was disabled, remove the
// count from the suggestion.
if (!$show_count) {
$suggestion->setResultsCount(NULL);
}
$build = $suggestion->toRenderable();
if ($build) {
// Render the label.
try {
$label = DeprecationHelper::backwardsCompatibleCall(
\Drupal::VERSION,
'10.3.0',
fn () => $this->renderer->renderInIsolation($build),
fn () => $this->renderer->renderPlain($build),
);
}
catch (\Exception $e) {
Error::logException($this->logger, $e, '%type while rendering an autocomplete suggestion: @message in %function (line %line of %file).');
continue;
}
// Decide what the action of the suggestion is – entering specific
// search terms or redirecting to a URL.
if ($suggestion->getUrl()) {
// Generate an HTML-free version of the label to use as the value.
// Setting the label as the value here is necessary for proper
// accessibility via screen readers (which will otherwise read the
// URL).
$url = $suggestion->getUrl()->toString();
$trimmed_label = trim(strip_tags((string) $label)) ?: $url;
$matches[] = [
'value' => $trimmed_label,
'url' => $url,
'label' => $label,
];
}
else {
$matches[] = [
'value' => trim($suggestion->getSuggestedKeys()),
'label' => $label,
];
}
}
}
$matches = $this->convertSuggestionsToJson($suggestions, $search);
}
catch (SearchApiAutocompleteException $e) {
Error::logException($this->logger, $e, '%type while retrieving autocomplete suggestions: @message in %function (line %line of %file).');
@@ -200,4 +151,69 @@ class AutocompleteController extends ControllerBase implements ContainerInjectio
return new JsonResponse($matches);
}
/**
* Converts suggestions to the format expected by Drupal's autocomplete JS.
*
* @param \Drupal\search_api_autocomplete\Suggestion\SuggestionInterface[] $suggestions
* The suggestions to convert.
* @param \Drupal\search_api_autocomplete\SearchInterface $search
* The autocomplete search entity for which suggestions are generated.
*
* @return array[]
* An array of suggestions arrays, ready to be converted to JSON and sent to
* the browser as an autocomplete response.
*/
protected function convertSuggestionsToJson(array $suggestions, SearchInterface $search): array {
$matches = [];
$show_count = $search->getOption('show_count');
$suggested_keys = [];
foreach ($suggestions as $suggestion) {
// If "Display result count estimates" was disabled, remove the
// count from the suggestion.
if (!$show_count) {
$suggestion->setResultsCount(NULL);
}
$build = $suggestion->toRenderable();
if ($build) {
// Render the label.
try {
$label = $this->renderer->render($build);
}
catch (\Exception $e) {
Error::logException($this->logger, $e, '%type while rendering an autocomplete suggestion: !message in %function (line %line of %file).');
continue;
}
// Decide what the action of the suggestion is – entering specific
// search terms or redirecting to a URL.
if ($suggestion->getUrl()) {
// Generate an HTML-free version of the label to use as the value.
// Setting the label as the value here is necessary for proper
// accessibility via screen readers (which will otherwise read the
// URL).
$url = $suggestion->getUrl()->toString();
$trimmed_label = trim(strip_tags((string) $label)) ?: $url;
$matches[] = [
'value' => $trimmed_label,
'url' => $url,
'label' => $label,
];
}
else {
// Skip duplicate suggestions.
$keys = trim($suggestion->getSuggestedKeys());
if (isset($suggested_keys[$keys])) {
continue;
}
$suggested_keys[$keys] = TRUE;
$matches[] = [
'value' => $keys,
'label' => $label,
];
}
}
}
return $matches;
}
}
Loading