diff --git a/core/modules/entity_reference/entity_reference.module b/core/modules/entity_reference/entity_reference.module index f5e968c..7e52b8f 100644 --- a/core/modules/entity_reference/entity_reference.module +++ b/core/modules/entity_reference/entity_reference.module @@ -63,18 +63,16 @@ function entity_reference_menu() { $items['entity_reference/autocomplete/single/%/%/%'] = array( 'title' => 'Entity Reference Autocomplete', - 'page callback' => 'entity_reference_autocomplete_callback', + 'page callback' => 'NOT_USED', 'page arguments' => array(2, 3, 4, 5), - 'access callback' => 'entity_reference_autocomplete_access_callback', - 'access arguments' => array(2, 3, 4, 5), + 'access callback' => TRUE, 'type' => MENU_CALLBACK, ); $items['entity_reference/autocomplete/tags/%/%/%'] = array( 'title' => 'Entity Reference Autocomplete', - 'page callback' => 'entity_reference_autocomplete_callback', + 'page callback' => 'NOT_USED', 'page arguments' => array(2, 3, 4, 5), - 'access callback' => 'entity_reference_autocomplete_access_callback', - 'access arguments' => array(2, 3, 4, 5), + 'access callback' => TRUE, 'type' => MENU_CALLBACK, ); diff --git a/core/modules/entity_reference/entity_reference.routing.yml b/core/modules/entity_reference/entity_reference.routing.yml new file mode 100644 index 0000000..e0b23b8 --- /dev/null +++ b/core/modules/entity_reference/entity_reference.routing.yml @@ -0,0 +1,7 @@ +entity_reference.autocomplete: + pattern: '/entity_reference/autocomplete/{type}/{field_name}/{entity_type}/{bundle_name}/{entity_id}' + defaults: + _controller: '\Drupal\entity_reference\EntityReferenceController::handleAutocomplete' + entity_id: 'NULL' + requirements: + _access: 'TRUE' diff --git a/core/modules/entity_reference/lib/Drupal/entity_reference/EntityReferenceAutocomplete.php b/core/modules/entity_reference/lib/Drupal/entity_reference/EntityReferenceAutocomplete.php new file mode 100644 index 0000000..a5b41af --- /dev/null +++ b/core/modules/entity_reference/lib/Drupal/entity_reference/EntityReferenceAutocomplete.php @@ -0,0 +1,102 @@ +entityManager = $entity_manager; + } + + /** + * Returns matched labels based on a given field, instance and search string. + * + * This function can be used by other modules that wish to pass a mocked + * definition of the field on instance. + * + * @param array $field + * The field array definition. + * @param array $instance + * The instance array definition. + * @param string $entity_type + * The entity type. + * @param string $entity_id + * (optional) The entity ID the entity reference field is attached to. + * Defaults to ''. + * @param string $prefix + * (optional) A prefix for all the keys returned by this function. + * @param string $string + * (optional) The label of the entity to query by. + * + * @throws \Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException + * Thrown when the current user doesn't have access to the specifies entity. + * + * @return array + * A list of matched entity labels. + * + * @see \Drupal\entity_reference\EntityReferenceController + */ + public function getMatches($field, $instance, $entity_type, $entity_id = '', $prefix = '', $string = '') { + $target_type = $field['settings']['target_type']; + $matches = array(); + $entity = NULL; + + if ($entity_id !== 'NULL') { + $entities = $this->entityManager->getStorageController($entity_type)->load(array($entity_id)); + $entity = reset($entities); + // @todo: Improve when we have entity_access(). + $entity_access = $target_type == 'node' ? node_access('view', $entity) : TRUE; + if (!$entity || !$entity_access) { + throw new AccessDeniedHttpException(); + } + } + $handler = entity_reference_get_selection_handler($field, $instance, $entity); + + if (isset($string)) { + // Get an array of matching entities. + $match_operator = !empty($instance['widget']['settings']['match_operator']) ? $instance['widget']['settings']['match_operator'] : 'CONTAINS'; + $entity_labels = $handler->getReferencableEntities($string, $match_operator, 10); + + // Loop through the entities and convert them into autocomplete output. + foreach ($entity_labels as $values) { + foreach ($values as $entity_id => $label) { + $key = "$label ($entity_id)"; + // Strip things like starting/trailing white spaces, line breaks and + // tags. + $key = preg_replace('/\s\s+/', ' ', str_replace("\n", '', trim(decode_entities(strip_tags($key))))); + // Names containing commas or quotes must be wrapped in quotes. + if (strpos($key, ',') !== FALSE || strpos($key, '"') !== FALSE) { + $key = '"' . str_replace('"', '""', $key) . '"'; + } + $matches[$prefix . $key] = '
' . $label . '
'; + } + } + } + + return $matches; + } + +} diff --git a/core/modules/entity_reference/lib/Drupal/entity_reference/EntityReferenceBundle.php b/core/modules/entity_reference/lib/Drupal/entity_reference/EntityReferenceBundle.php index 56bd797..f9762b6 100644 --- a/core/modules/entity_reference/lib/Drupal/entity_reference/EntityReferenceBundle.php +++ b/core/modules/entity_reference/lib/Drupal/entity_reference/EntityReferenceBundle.php @@ -8,6 +8,7 @@ namespace Drupal\entity_reference; use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\DependencyInjection\Reference; use Symfony\Component\HttpKernel\Bundle\Bundle; /** @@ -19,9 +20,11 @@ class EntityReferenceBundle extends Bundle { * Overrides Symfony\Component\HttpKernel\Bundle\Bundle::build(). */ public function build(ContainerBuilder $container) { - // Register the SelectionPluginManager class with the dependency injection - // container. + // Register the SelectionPluginManager class and the autocomplete helper + // with the dependency injection container. $container->register('plugin.manager.entity_reference.selection', 'Drupal\entity_reference\Plugin\Type\SelectionPluginManager') ->addArgument('%container.namespaces%'); + $container->register('entity_reference.autocomplete', 'Drupal\entity_reference\EntityReferenceAutocomplete') + ->addArgument(new Reference('plugin.manager.entity')); } } diff --git a/core/modules/entity_reference/lib/Drupal/entity_reference/EntityReferenceController.php b/core/modules/entity_reference/lib/Drupal/entity_reference/EntityReferenceController.php new file mode 100644 index 0000000..fe10916 --- /dev/null +++ b/core/modules/entity_reference/lib/Drupal/entity_reference/EntityReferenceController.php @@ -0,0 +1,73 @@ +query->get('q'); + $items_typed = drupal_explode_tags($items_typed); + $last_item = drupal_strtolower(array_pop($items_typed)); + + $prefix = ''; + // The user entered a comma-separated list of entity labels, so we generate + // a prefix. + if ($type == 'tags' && !empty($last_item)) { + $prefix = count($items_typed) ? drupal_implode_tags($items_typed) . ', ' : ''; + } + + $matches = $this->container->get('entity_reference.autocomplete')->getMatches($field, $instance, $entity_type, $entity_id, $prefix, $last_item); + + return new JsonResponse($matches); + } +}