diff --git a/core/modules/taxonomy/lib/Drupal/taxonomy/Taxonomy.php b/core/modules/taxonomy/lib/Drupal/taxonomy/Taxonomy.php new file mode 100644 index 0000000..345ad3e --- /dev/null +++ b/core/modules/taxonomy/lib/Drupal/taxonomy/Taxonomy.php @@ -0,0 +1,118 @@ +container = $container; + } + + /** + * Page callback: Outputs JSON for taxonomy autocomplete suggestions. + * + * This callback outputs term name suggestions in response to Ajax requests + * made by the taxonomy autocomplete widget for taxonomy term reference + * fields. 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 field, 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 string $field_name + * The name of the term reference field. + * + * @see taxonomy_menu() + * @see taxonomy_field_widget_info() + */ + public function autocomplete($field_name) { + $tags_typed = drupal_container()->get('request')->query->get('q'); + + // Make sure the field exists and is a taxonomy field. + if (!($field = field_info_field($field_name)) || $field['type'] !== 'taxonomy_term_reference') { + // Error string. The JavaScript handler will realize this is not JSON and + // will display it as debugging information. + return new Response(t('Taxonomy field @field_name not found.', array('@field_name' => $field_name))); + } + + // The user enters a comma-separated list of tags. We only autocomplete + // the last tag. + $tags_typed = drupal_explode_tags($tags_typed); + $tag_last = drupal_strtolower(array_pop($tags_typed)); + + $matches = array(); + if ($tag_last != '') { + + // Part of the criteria for the query come from the field's own settings. + $vids = array(); + $vocabularies = taxonomy_vocabulary_get_names(); + foreach ($field['settings']['allowed_values'] as $tree) { + $vids[] = $vocabularies[$tree['vocabulary']]->vid; + } + + $query = db_select('taxonomy_term_data', 't'); + $query->addTag('translatable'); + $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', $vids) + ->condition('t.name', '%' . db_like($tag_last) . '%', 'LIKE') + ->range(0, 10) + ->execute() + ->fetchAllKeyed(); + + $prefix = count($tags_typed) ? drupal_implode_tags($tags_typed) . ', ' : ''; + + $term_matches = array(); + 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) . '"'; + } + $term_matches[$prefix . $n] = check_plain($name); + } + } + return new JsonResponse($term_matches); + } +} diff --git a/core/modules/taxonomy/lib/Drupal/taxonomy/TaxonomyRouteController.php b/core/modules/taxonomy/lib/Drupal/taxonomy/TaxonomyRouteController.php new file mode 100644 index 0000000..922f930 --- /dev/null +++ b/core/modules/taxonomy/lib/Drupal/taxonomy/TaxonomyRouteController.php @@ -0,0 +1,27 @@ +autocomplete($field_name, $tags_typed); + } +} diff --git a/core/modules/taxonomy/taxonomy.module b/core/modules/taxonomy/taxonomy.module index 3a1d297..d336a4b 100644 --- a/core/modules/taxonomy/taxonomy.module +++ b/core/modules/taxonomy/taxonomy.module @@ -10,6 +10,10 @@ use Drupal\taxonomy\Plugin\Core\Entity\Vocabulary; use Drupal\Core\Entity\EntityInterface; +use Symfony\Component\HttpFoundation\JsonResponse; +use Symfony\Component\Routing\RouteCollection; +use Symfony\Component\Routing\Route; + /** * Denotes that no term in the vocabulary has a parent. */ @@ -307,15 +311,6 @@ function taxonomy_menu() { 'type' => MENU_CALLBACK, 'file' => 'taxonomy.pages.inc', ); - $items['taxonomy/autocomplete/%'] = array( - 'title' => 'Autocomplete taxonomy', - 'page callback' => 'taxonomy_autocomplete', - 'page arguments' => array(2), - 'access arguments' => array('access content'), - 'type' => MENU_CALLBACK, - 'file' => 'taxonomy.pages.inc', - ); - $items['admin/structure/taxonomy/%taxonomy_vocabulary_machine_name'] = array( 'title callback' => 'entity_page_label', 'title arguments' => array(3), diff --git a/core/modules/taxonomy/taxonomy.pages.inc b/core/modules/taxonomy/taxonomy.pages.inc index 62202fb..0506645 100644 --- a/core/modules/taxonomy/taxonomy.pages.inc +++ b/core/modules/taxonomy/taxonomy.pages.inc @@ -81,87 +81,3 @@ function taxonomy_term_feed(Term $term) { return node_feed($nids, $channel); } -/** - * Page callback: Outputs JSON for taxonomy autocomplete suggestions. - * - * This callback outputs term name suggestions in response to Ajax requests - * made by the taxonomy autocomplete widget for taxonomy term reference - * fields. 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 - * field, 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 $field_name - * The name of the term reference field. - * - * @see taxonomy_menu() - * @see taxonomy_field_widget_info() - */ -function taxonomy_autocomplete($field_name) { - // A comma-separated list of term names entered in the autocomplete form - // element. Only the last term is used for autocompletion. - $tags_typed = drupal_container()->get('request')->query->get('q'); - - // Make sure the field exists and is a taxonomy field. - if (!($field = field_info_field($field_name)) || $field['type'] !== 'taxonomy_term_reference') { - // Error string. The JavaScript handler will realize this is not JSON and - // will display it as debugging information. - print t('Taxonomy field @field_name not found.', array('@field_name' => $field_name)); - exit; - } - - // The user enters a comma-separated list of tags. We only autocomplete the last tag. - $tags_typed = drupal_explode_tags($tags_typed); - $tag_last = drupal_strtolower(array_pop($tags_typed)); - - $matches = array(); - if ($tag_last != '') { - - // Part of the criteria for the query come from the field's own settings. - $vids = array(); - $vocabularies = taxonomy_vocabulary_get_names(); - foreach ($field['settings']['allowed_values'] as $tree) { - $vids[] = $vocabularies[$tree['vocabulary']]->vid; - } - - $query = db_select('taxonomy_term_data', 't'); - $query->addTag('translatable'); - $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', $vids) - ->condition('t.name', '%' . db_like($tag_last) . '%', 'LIKE') - ->range(0, 10) - ->execute() - ->fetchAllKeyed(); - - $prefix = count($tags_typed) ? drupal_implode_tags($tags_typed) . ', ' : ''; - - $term_matches = array(); - 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) . '"'; - } - $term_matches[$prefix . $n] = check_plain($name); - } - } - - return new JsonResponse($term_matches); -} diff --git a/core/modules/taxonomy/taxonomy.routing.yml b/core/modules/taxonomy/taxonomy.routing.yml new file mode 100644 index 0000000..5cca0f5 --- /dev/null +++ b/core/modules/taxonomy/taxonomy.routing.yml @@ -0,0 +1,6 @@ +taxonomy_autocomplete: + pattern: '/taxonomy/autocomplete/{field_name}' + defaults: + _controller: '\Drupal\taxonomy\TaxonomyRouteController::autocomplete' + requirements: + _permission: 'access content'