diff --git a/core/modules/views/includes/ajax.inc b/core/modules/views/includes/ajax.inc index a662cc8..c3b493e 100644 --- a/core/modules/views/includes/ajax.inc +++ b/core/modules/views/includes/ajax.inc @@ -80,53 +80,5 @@ function views_ajax_form_wrapper($form_id, &$form_state) { } /** - * Page callback for views taxonomy autocomplete. - * - * @param $vid - * The vocabulary id of the tags which should be returned. - * - * @see taxonomy_autocomplete() - */ -function views_ajax_autocomplete_taxonomy($vid) { - // The user enters a comma-separated list of tags. We only autocomplete the - // last tag. - $tags_typed = Tags::explode(Drupal::request()->query->get('q')); - $tag_last = Unicode::strtolower(array_pop($tags_typed)); - $term_matches = array(); - - if ($tag_last != '') { - $query = db_select('taxonomy_term_data', 't'); - $query->addTag('term_access'); - - // Do not select already entered terms. - if (!empty($tags_typed)) { - $query->condition('t.name', $tags_typed, 'NOT IN'); - } - // Select rows that match by term name. - $tags_return = $query - ->fields('t', array('tid', 'name')) - ->condition('t.vid', $vid) - ->condition('t.name', '%' . db_like($tag_last) . '%', 'LIKE') - ->range(0, 10) - ->execute() - ->fetchAllKeyed(); - - $prefix = count($tags_typed) ? Tags::implode($tags_typed) . ', ' : ''; - - foreach ($tags_return as $tid => $name) { - $n = $name; - // Term names containing commas or quotes must be wrapped in quotes. - if (strpos($name, ',') !== FALSE || strpos($name, '"') !== FALSE) { - $n = '"' . str_replace('"', '""', $name) . '"'; - } - // Add term name to list of matches. - $term_matches[$prefix . $n] = String::checkPlain($name); - } - } - - return new JsonResponse($term_matches); -} - -/** * @} */ diff --git a/core/modules/views/lib/Drupal/views/Controller/TagsAutocompleteController.php b/core/modules/views/lib/Drupal/views/Controller/TagsAutocompleteController.php new file mode 100644 index 0000000..139fe4e --- /dev/null +++ b/core/modules/views/lib/Drupal/views/Controller/TagsAutocompleteController.php @@ -0,0 +1,125 @@ +queryFactory = $query_factory; + $this->termStorageController = $entity_manager->getStorageController('taxonomy_term'); + } + + /** + * {@inheritdoc} + */ + public static function create(ContainerInterface $container) { + return new static($container->get('entity.query'), $container->get('plugin.manager.entity')); + } + + /** + * Retrieves suggestions for taxonomy term autocompletion. + * + * This function outputs term name suggestions in response to Ajax requests + * made by views tags filter. The output is a JSON object of plain-text term + * suggestions, keyed by the user-entered value with the completed term name + * appended. Term names containing commas are wrapped in quotes. + * + * For example, suppose the user has entered the string 'red fish, blue' in + * the filter, and there are two taxonomy terms, 'blue fish' and 'blue moon'. + * The JSON output would have the following structure: + * @code + * { + * "red fish, blue fish": "blue fish", + * "red fish, blue moon": "blue moon", + * }; + * @endcode + * + * @param \Symfony\Component\HttpFoundation\Request $request + * The request object. + * @param \Drupal\taxonomy\VocabularyInterface $taxonomy_vocabulary + * The vocabulary to filter by. + * + * @return \Symfony\Component\HttpFoundation\JsonResponse + * When the vocabulary is specified, a JSON response containing the + * autocomplete suggestions for taxonomy terms. + */ + public function autocomplete(Request $request, VocabularyInterface $taxonomy_vocabulary) { + // The user enters a comma-separated list of tags. We only autocomplete the + // last tag. + $tags_typed = Tags::explode($request->query->get('q')); + $tag_last = Unicode::strtolower(array_pop($tags_typed)); + $term_matches = array(); + + if ($tag_last != '') { + // Select rows that match by term name. + $query = $this->queryFactory->get('taxonomy_term'); + $query->addTag('term_access'); + $query->condition('vid', $taxonomy_vocabulary->id()) + ->condition('name', $tag_last, 'STARTS_WITH'); + + // Do not select already entered terms. + if (!empty($tags_typed)) { + $query->condition('t.name', $tags_typed, 'NOT IN'); + } + + $query->range(0, 10); + $tags = $this->termStorageController->loadMultiple($query->execute()); + + $prefix = count($tags_typed) ? Tags::implode($tags_typed) . ', ' : ''; + + foreach ($tags as $term) { + $key = $name = $term->name->value; + // Term names containing commas or quotes must be wrapped in quotes. + if (strpos($name, ',') !== FALSE || strpos($name, '"') !== FALSE) { + $key = '"' . str_replace('"', '""', $name) . '"'; + } + // Add term name to list of matches. + $term_matches[$prefix . $key] = String::checkPlain($name); + } + } + + return new JsonResponse($term_matches); + } + +} diff --git a/core/modules/views/views.module b/core/modules/views/views.module index 26a9dbb..a45d29f 100644 --- a/core/modules/views/views.module +++ b/core/modules/views/views.module @@ -322,17 +322,6 @@ function views_menu() { 'route_name' => 'views_ajax', 'type' => MENU_CALLBACK, ); - // Define another taxonomy autocomplete because the default one of drupal - // does not support a vid a argument anymore - $items['admin/views/ajax/autocomplete/taxonomy/%'] = array( - 'page callback' => 'views_ajax_autocomplete_taxonomy', - 'page arguments' => array(5), - 'theme callback' => 'ajax_base_page_theme', - 'access callback' => 'user_access', - 'access arguments' => array('access content'), - 'type' => MENU_CALLBACK, - 'file' => 'includes/ajax.inc', - ); return $items; } diff --git a/core/modules/views/views.routing.yml b/core/modules/views/views.routing.yml index 016b2a5..7648308 100644 --- a/core/modules/views/views.routing.yml +++ b/core/modules/views/views.routing.yml @@ -4,3 +4,9 @@ views_ajax: _controller: '\Drupal\views\Controller\ViewAjaxController::ajaxView' requirements: _access: 'TRUE' +views_taxonomy_autocomplete: + pattern: 'admin/views/ajax/autocomplete/taxonomy/{taxonomy_vocabulary}' + defaults: + _controller: '\Drupal\views\Controller\TagsAutocompleteController::autocomplete' + requirements: + _permission: 'access content'