search_api_autocomplete-8.x-1.x-dev/src/Controller/AutocompleteController.php

src/Controller/AutocompleteController.php
<?php

namespace Drupal\search_api_autocomplete\Controller;

use Drupal\Component\Utility\DeprecationHelper;
use Drupal\Core\Controller\ControllerBase;
use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
use Drupal\Core\Render\RendererInterface;
use Drupal\Core\Utility\Error;
use Drupal\search_api_autocomplete\SearchApiAutocompleteException;
use Drupal\search_api_autocomplete\SearchInterface;
use Drupal\search_api_autocomplete\Utility\AutocompleteHelperInterface;
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.
 */
class AutocompleteController extends ControllerBase implements ContainerInjectionInterface {

  /**
   * Creates a new AutocompleteController instance.
   *
   * @param \Drupal\search_api_autocomplete\Utility\AutocompleteHelperInterface $autocompleteHelper
   *   The autocomplete helper service.
   * @param \Drupal\Core\Render\RendererInterface $renderer
   *   The renderer.
   * @param \Drupal\Component\Transliteration\TransliterationInterface $transliterator
   *   The transliterator.
   * @param \Psr\Log\LoggerInterface $logger
   *   The logger.
   */
  public function __construct(
    protected AutocompleteHelperInterface $autocompleteHelper,
    protected RendererInterface $renderer,
    protected TransliterationInterface $transliterator,
    protected LoggerInterface $logger,
  ) {
  }

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container) {
    /** @var \Psr\Log\LoggerInterface $logger */
    $logger = $container->get('logger.channel.search_api_autocomplete');
    return new static(
      $container->get('search_api_autocomplete.helper'),
      $container->get('renderer'),
      $container->get('transliteration'),
      $logger,
    );
  }

  /**
   * Page callback: Retrieves autocomplete suggestions.
   *
   * @param \Drupal\search_api_autocomplete\SearchInterface $search_api_autocomplete_search
   *   The search for which to retrieve autocomplete suggestions.
   * @param \Symfony\Component\HttpFoundation\Request $request
   *   The request.
   *
   * @return \Symfony\Component\HttpFoundation\JsonResponse
   *   The autocompletion response.
   */
  public function autocomplete(SearchInterface $search_api_autocomplete_search, Request $request) {
    $matches = [];
    $search = $search_api_autocomplete_search;

    if (!$search->status() || !$search->hasValidIndex()) {
      return new JsonResponse($matches);
    }

    try {
      $keys = $request->query->get('q');
      if ("$keys" === '') {
        return new JsonResponse($matches);
      }
      [$complete, $incomplete] = $this->autocompleteHelper->splitKeys($keys);
      $data = $request->query->all();
      unset($data['q']);
      $query = $search->createQuery($complete, $data);
      if (!$query) {
        return new JsonResponse($matches);
      }

      // Prepare the query.
      $query->setSearchId('search_api_autocomplete:' . $search->id());
      $query->addTag('search_api_autocomplete');

      // Get total limit and per-suggester limits.
      $limit = $search->getOption('limit');
      $suggester_limits = $search->getSuggesterLimits();

      // Get all enabled suggesters, ordered by weight.
      $suggesters = $search->getSuggesters();
      $suggester_weights = $search->getSuggesterWeights();
      $suggester_weights = array_intersect_key($suggester_weights, $suggesters);
      $suggester_weights += array_fill_keys(array_keys($suggesters), 0);
      asort($suggester_weights);

      /** @var \Drupal\search_api_autocomplete\Suggestion\SuggestionInterface[] $suggestions */
      $suggestions = [];
      // Go through all enabled suggesters in order of increasing weight and
      // add their suggestions (until the limit is reached).
      foreach (array_keys($suggester_weights) as $suggester_id) {
        // Clone the query in case the suggester makes any modifications.
        $tmp_query = clone $query;

        // Compute the applicable limit based on (remaining) total limit and
        // the suggester-specific limit (if set).
        if (isset($suggester_limits[$suggester_id])) {
          $suggester_limit = min($limit, $suggester_limits[$suggester_id]);
        }
        else {
          $suggester_limit = $limit;
        }
        $tmp_query->range(0, $suggester_limit);

        // Add suggestions in a loop so we're sure they're numerically
        // indexed.
        $new_suggestions = $suggesters[$suggester_id]
          ->getAutocompleteSuggestions($tmp_query, $incomplete, $keys);
        foreach ($new_suggestions as $suggestion) {
          $suggestions[] = $suggestion;

          if (--$limit == 0) {
            // If we've reached the limit, stop adding suggestions.
            break 2;
          }
        }
      }

      // Allow other modules to alter the created suggestions.
      $alter_params = [
        'query' => $query,
        'search' => $search,
        'incomplete_key' => $incomplete,
        'user_input' => $keys,
      ];
      $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,
            ];
          }
        }
      }
    }
    catch (SearchApiAutocompleteException $e) {
      Error::logException($this->logger, $e, '%type while retrieving autocomplete suggestions: @message in %function (line %line of %file).');
    }

    return new JsonResponse($matches);
  }

}

Главная | Обратная связь

drupal hosting | друпал хостинг | it patrol .inc