Commit 6fb49a58 authored by drunken monkey's avatar drunken monkey

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

parent c39bb1ae
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):
-----------------------------------------
......
......@@ -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');
......
......@@ -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;
}
$server = $index->getServerInstance();
$backend = $server->getBackend();
try {
$server = $index->getServerInstance();
$backend = $server->getBackend();
}
catch (SearchApiException $e) {
return NULL;
}
if ($server->supportsFeature('search_api_autocomplete') || $backend instanceof AutocompleteBackendInterface) {
return $backend;
}
......
......@@ -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.');
......
......@@ -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\"]");
......
......@@ -167,7 +167,6 @@ class PagesIntegrationTest extends IntegrationTestBase {
$elements = $this->getAutocompleteSuggestions();
$suggestions = [];
$suggestion_elements = [];
foreach ($elements as $element) {
$label = $this->getElementText($element, '.autocomplete-suggestion-label');
$user_input = $this->getElementText($element, '.autocomplete-suggestion-user-input');
......@@ -178,27 +177,26 @@ class PagesIntegrationTest extends IntegrationTestBase {
'keys' => $keys,
'count' => $count,
];
$suggestion_elements[$keys] = $element;
}
$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,
],
];
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment