Commit 6fb49a58 authored by Thomas Seidl's avatar Thomas Seidl
Browse files

Issue #2947273 by drunken monkey: Fixed keywords preprocessing for “Live results” suggester.

parent c39bb1ae
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
Search API Autocomplete 1.x, dev (xxxx-xx-xx):
----------------------------------------------
- #2947273 by drunken monkey: Fixed keywords preprocessing for “Live
  results” suggester.

Search API Autocomplete 1.2 (2019-03-11):
-----------------------------------------
+0 −7
Original line number Diff line number Diff line
@@ -88,12 +88,6 @@ class AutocompleteController extends ControllerBase implements ContainerInjectio

    try {
      $keys = $request->query->get('q');
      // If the "Transliteration" processor is enabled for the search index, we
      // also need to transliterate the user input for autocompletion.
      if ($search->getIndex()->isValidProcessor('transliteration')) {
        $langcode = $this->languageManager()->getCurrentLanguage()->getId();
        $keys = $this->transliterator->transliterate($keys, $langcode);
      }
      $split_keys = $this->autocompleteHelper->splitKeys($keys);
      list($complete, $incomplete) = $split_keys;
      $data = $request->query->all();
@@ -106,7 +100,6 @@ class AutocompleteController extends ControllerBase implements ContainerInjectio
      // Prepare the query.
      $query->setSearchId('search_api_autocomplete:' . $search->id());
      $query->addTag('search_api_autocomplete');
      $query->preExecute();

      // Get total limit and per-suggester limits.
      $limit = $search->getOption('limit');
+100 −3
Original line number Diff line number Diff line
@@ -2,14 +2,18 @@

namespace Drupal\search_api_autocomplete\Plugin\search_api_autocomplete\suggester;

use Drupal\Component\Transliteration\TransliterationInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Language\LanguageManagerInterface;
use Drupal\Core\Plugin\PluginFormInterface;
use Drupal\search_api\IndexInterface;
use Drupal\search_api\Plugin\PluginFormTrait;
use Drupal\search_api\Query\QueryInterface;
use Drupal\search_api\SearchApiException;
use Drupal\search_api_autocomplete\AutocompleteBackendInterface;
use Drupal\search_api_autocomplete\SearchInterface;
use Drupal\search_api_autocomplete\Suggester\SuggesterPluginBase;
use Symfony\Component\DependencyInjection\ContainerInterface;

/**
 * Provides a suggester plugin that retrieves suggestions from the server.
@@ -27,6 +31,20 @@ class Server extends SuggesterPluginBase implements PluginFormInterface {

  use PluginFormTrait;

  /**
   * The language manager.
   *
   * @var \Drupal\Core\Language\LanguageManagerInterface|null
   */
  protected $languageManager;

  /**
   * The transliteration.
   *
   * @var \Drupal\Component\Transliteration\TransliterationInterface|null
   */
  protected $transliterator;

  /**
   * {@inheritdoc}
   */
@@ -34,6 +52,65 @@ class Server extends SuggesterPluginBase implements PluginFormInterface {
    return (bool) static::getBackend($search->getIndex());
  }

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
    /** @var static $plugin */
    $plugin = parent::create($container, $configuration, $plugin_id, $plugin_definition);

    $plugin->setLanguageManager($container->get('language_manager'));
    $plugin->setTransliterator($container->get('transliteration'));

    return $plugin;
  }

  /**
   * Retrieves the language manager.
   *
   * @return \Drupal\Core\Language\LanguageManagerInterface
   *   The language manager.
   */
  public function getLanguageManager() {
    return $this->languageManager ?: \Drupal::service('language_manager');
  }

  /**
   * Sets the language manager.
   *
   * @param \Drupal\Core\Language\LanguageManagerInterface $language_manager
   *   The new language manager.
   *
   * @return $this
   */
  public function setLanguageManager(LanguageManagerInterface $language_manager) {
    $this->languageManager = $language_manager;
    return $this;
  }

  /**
   * Retrieves the transliteration.
   *
   * @return \Drupal\Component\Transliteration\TransliterationInterface
   *   The transliteration.
   */
  public function getTransliterator() {
    return $this->transliterator ?: \Drupal::service('transliteration');
  }

  /**
   * Sets the transliteration.
   *
   * @param \Drupal\Component\Transliteration\TransliterationInterface $transliterator
   *   The new transliteration.
   *
   * @return $this
   */
  public function setTransliterator(TransliterationInterface $transliterator) {
    $this->transliterator = $transliterator;
    return $this;
  }

  /**
   * {@inheritdoc}
   */
@@ -81,13 +158,28 @@ class Server extends SuggesterPluginBase implements PluginFormInterface {
   * {@inheritdoc}
   */
  public function getAutocompleteSuggestions(QueryInterface $query, $incomplete_key, $user_input) {
    if (!($backend = static::getBackend($this->getSearch()->getIndex()))) {
    $index = $query->getIndex();
    if (!($backend = static::getBackend($index))) {
      return [];
    }

    // If the "Transliteration" processor is enabled for the search index, we
    // also need to transliterate the user input for autocompletion.
    if ($index->isValidProcessor('transliteration')) {
      $langcode = $this->getLanguageManager()->getCurrentLanguage()->getId();
      $incomplete_key = $this->getTransliterator()->transliterate($incomplete_key, $langcode);
      $user_input = $this->getTransliterator()->transliterate($user_input, $langcode);
    }

    if ($this->configuration['fields']) {
      $query->setFulltextFields($this->configuration['fields']);
    }
    try {
      $query->preExecute();
    }
    catch (SearchApiException $e) {
      return [];
    }
    return $backend->getAutocompleteSuggestions($query, $this->getSearch(), $incomplete_key, $user_input);
  }

@@ -105,8 +197,13 @@ class Server extends SuggesterPluginBase implements PluginFormInterface {
    if (!$index->hasValidServer()) {
      return NULL;
    }
    try {
      $server = $index->getServerInstance();
      $backend = $server->getBackend();
    }
    catch (SearchApiException $e) {
      return NULL;
    }
    if ($server->supportsFeature('search_api_autocomplete') || $backend instanceof AutocompleteBackendInterface) {
      return $backend;
    }
+12 −37
Original line number Diff line number Diff line
@@ -232,23 +232,23 @@ class IntegrationTest extends IntegrationTestBase {
    }
    $expected = [
      [
        'keys' => 'test-suggester-1',
        'keys' => 'st-suggester-1',
        'count' => 1,
      ],
      [
        'keys' => 'test-suggester-2',
        'keys' => 'st-suggester-2',
        'count' => 2,
      ],
      [
        'keys' => 'test-suggester-url',
        'keys' => 'st-suggester-url',
        'count' => NULL,
      ],
      [
        'keys' => 'test-backend-1',
        'keys' => 'st-backend-1',
        'count' => 1,
      ],
      [
        'keys' => 'test-backend-2',
        'keys' => 'st-backend-2',
        'count' => 2,
      ],
    ];
@@ -264,17 +264,19 @@ class IntegrationTest extends IntegrationTestBase {
    if ($click_url_suggestion) {
      // Click the URL suggestion and verify it correctly redirects the browser
      // to that URL.
      $suggestion_elements['test-suggester-url']->click();
      $suggestion_elements['st-suggester-url']->click();
      $this->logPageChange();
      $assert_session->addressEquals("/user/{$this->adminUser->id()}");
      return;
    }

    // Click one of the search key suggestions. The form should now auto-submit.
    $suggestion_elements['test-suggester-1']->click();
    $keys = 'Tést-suggester-1';
    $suggestion_elements[$keys]->click();
    $this->logPageChange();
    $assert_session->addressEquals('/search-api-autocomplete-test');
    $this->assertRegExp('#[?&]keys=test-suggester-1#', $this->getUrl());
    $keys = urlencode($keys);
    $this->assertRegExp("#[?&]keys=$keys#", $this->getUrl());

    // Check that autocomplete in the "Name" filter works, too, and that it sets
    // the correct fields on the query.
@@ -328,7 +330,7 @@ class IntegrationTest extends IntegrationTestBase {
    $this->assertEquals(0, $query->getOption('offset'));
    $this->assertEquals(5, $query->getOption('limit'));
    $this->assertEquals(['body'], $query->getFulltextFields());
    $this->assertEquals('test', $query->getOriginalKeys());
    $this->assertEquals('st', $query->getOriginalKeys());

    // Click on one of the suggestions and verify it takes us to the expected
    // page.
@@ -338,33 +340,6 @@ class IntegrationTest extends IntegrationTestBase {
    $assert_session->addressEquals('/' . $path);
  }

  /**
   * Retrieves autocomplete suggestions from a field on the current page.
   *
   * @param string $field_html_id
   *   (optional) The HTML ID of the field.
   * @param string $input
   *   (optional) The input to write into the field.
   *
   * @return \Behat\Mink\Element\NodeElement[]
   *   The suggestion elements from the page.
   */
  protected function getAutocompleteSuggestions($field_html_id = 'edit-keys', $input = 'test') {
    $assert_session = $this->assertSession();
    $field = $assert_session->elementExists('css', "input[data-drupal-selector=\"$field_html_id\"]");
    $field->setValue(substr($input, 0, -1));
    $this->getSession()->getDriver()->keyDown($field->getXpath(), substr($input, -1));

    $element = $assert_session->waitOnAutocomplete();
    $this->assertTrue($element && $element->isVisible());
    $this->logPageChange();

    // Contrary to documentation, this can also return NULL. Therefore, we need
    // to make sure to return an array even in this case.
    $page = $this->getSession()->getPage();
    return $page->findAll('css', '.ui-autocomplete .ui-menu-item') ?: [];
  }

  /**
   * Tests whether using a custom autocomplete script is properly supported.
   *
@@ -404,7 +379,7 @@ class IntegrationTest extends IntegrationTestBase {
    $expected = [
      'display: page',
      'filter: keys',
      'q: test',
      'q: st',
      "search_api_autocomplete_search: {$this->searchId}",
    ];
    $this->assertEquals($expected, $suggestions, 'Unexpected suggestions returned by custom script.');
+4 −2
Original line number Diff line number Diff line
@@ -27,12 +27,14 @@ abstract class IntegrationTestBase extends JavascriptTestBase {
   * @param string $field_html_id
   *   (optional) The HTML ID of the field.
   * @param string $input
   *   (optional) The input to write into the field.
   *   (optional) The input to write into the field. The default contains
   *   uppercase characters and accents to verify input is properly
   *   preprocessed.
   *
   * @return \Behat\Mink\Element\NodeElement[]
   *   The suggestion elements from the page.
   */
  protected function getAutocompleteSuggestions($field_html_id = 'edit-keys', $input = 'test') {
  protected function getAutocompleteSuggestions($field_html_id = 'edit-keys', $input = 'st') {
    $page = $this->getSession()->getPage();
    $assert_session = $this->assertSession();
    $field = $assert_session->elementExists('css', "input[data-drupal-selector=\"$field_html_id\"]");
Loading