diff --git a/core/modules/entity_reference/entity_reference.module b/core/modules/entity_reference/entity_reference.module
index 4e98d15..5b28b13 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,
);
@@ -418,140 +416,3 @@ function entity_reference_query_entity_reference_alter(AlterableInterface $query
$handler = $query->getMetadata('entity_reference_selection_handler');
$handler->entityQueryAlter($query);
}
-
-/**
- * Menu Access callback for the autocomplete widget.
- *
- * @param string $type
- * The widget type (i.e. 'single' or 'tags').
- * @param string $field_name
- * The name of the entity reference field.
- * @param string $entity_type
- * The entity type.
- * @param string $bundle_name
- * The bundle name.
- *
- * @return bool
- * TRUE if user can access this menu item, FALSE otherwise.
- */
-function entity_reference_autocomplete_access_callback($type, $field_name, $entity_type, $bundle_name) {
- if (!$field = field_info_field($field_name)) {
- return FALSE;
- }
- if (!$instance = field_info_instance($entity_type, $field_name, $bundle_name)){
- return FALSE;
- }
-
- if ($field['type'] != 'entity_reference' || !field_access('edit', $field, $entity_type)) {
- return FALSE;
- }
-
- return TRUE;
-}
-
-/**
- * Menu callback; Autocomplete the label of an entity.
- *
- * @param string $type
- * The widget type (i.e. 'single' or 'tags').
- * @param string $field_name
- * The name of the entity reference field.
- * @param string $entity_type
- * The entity type.
- * @param string $bundle_name
- * The bundle name.
- * @param string $entity_id
- * (optional) The entity ID the entity reference field is attached to.
- * Defaults to ''.
- *
- * @return \Symfony\Component\HttpFoundation\JsonResponse
- */
-function entity_reference_autocomplete_callback($type, $field_name, $entity_type, $bundle_name, $entity_id = '') {
- $field = field_info_field($field_name);
- $instance = field_info_instance($entity_type, $field_name, $bundle_name);
-
- // Get the typed string, if exists from the URL.
- $tags_typed = drupal_container()->get('request')->query->get('q');
- $tags_typed = drupal_explode_tags($tags_typed);
- $string = drupal_strtolower(array_pop($tags_typed));
-
- return entity_reference_autocomplete_callback_get_matches($type, $field, $instance, $entity_type, $entity_id, $string);
-}
-
-/**
- * Returns JSON data 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 string $type
- * The widget type (i.e. 'single' or 'tags').
- * @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 $string
- * The label of the entity to query by.
- *
- * @return \Symfony\Component\HttpFoundation\JsonResponse
- *
- * @see entity_reference_autocomplete_callback()
- */
-function entity_reference_autocomplete_callback_get_matches($type, $field, $instance, $entity_type, $entity_id = '', $string = '') {
- $target_type = $field['settings']['target_type'];
- $matches = array();
- $entity = NULL;
-
- if ($entity_id !== 'NULL') {
- $entity = entity_load($entity_type, $entity_id);
- // @todo: Improve when we have entity_access().
- $entity_access = $target_type == 'node' ? node_access('view', $entity) : TRUE;
- if (!$entity || !$entity_access) {
- return MENU_ACCESS_DENIED;
- }
- }
- $handler = entity_reference_get_selection_handler($field, $instance, $entity);
-
- if ($type == 'tags') {
- // The user enters a comma-separated list of tags. We only autocomplete the
- // last tag.
- $tags_typed = drupal_explode_tags($string);
- $tag_last = drupal_strtolower(array_pop($tags_typed));
- if (!empty($tag_last)) {
- $prefix = count($tags_typed) ? implode(', ', $tags_typed) . ', ' : '';
- }
- }
- else {
- // The user enters a single tag.
- $prefix = '';
- $tag_last = $string;
- }
-
- if (isset($tag_last)) {
- // Get an array of matching entities.
- $match_operator = !empty($instance['widget']['settings']['match_operator']) ? $instance['widget']['settings']['match_operator'] : 'CONTAINS';
- $entity_labels = $handler->getReferencableEntities($tag_last, $match_operator, 10);
-
- // Loop through the products 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 new JsonResponse($matches);
-}
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..36280a6
--- /dev/null
+++ b/core/modules/entity_reference/entity_reference.routing.yml
@@ -0,0 +1,15 @@
+entity_reference.autocomplete:
+ pattern: '/entity_reference/autocomplete/{type}/{field_name}/{entity_type}/{bundle_name}'
+ defaults:
+ _controller: 'entity_reference.controller:handleAutocomplete'
+ entity_id: ''
+ requirements:
+ _access: 'TRUE'
+
+entity_reference.autocomplete.single:
+ pattern: '/entity_reference/autocomplete/{type}/{field_name}/{entity_type}/{bundle_name}/{entity_id}'
+ defaults:
+ _controller: 'entity_reference.controller:handleAutocomplete'
+ entity_id: ''
+ requirements:
+ _access: 'TRUE'
diff --git a/core/modules/entity_reference/lib/Drupal/entity_reference/EntityReferenceAutocompletion.php b/core/modules/entity_reference/lib/Drupal/entity_reference/EntityReferenceAutocompletion.php
new file mode 100644
index 0000000..85ca2a5
--- /dev/null
+++ b/core/modules/entity_reference/lib/Drupal/entity_reference/EntityReferenceAutocompletion.php
@@ -0,0 +1,117 @@
+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 string $type
+ * The widget type (i.e. 'single' or 'tags').
+ * @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 $string
+ * 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($type, $field, $instance, $entity_type, $entity_id = '', $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 ($type == 'tags') {
+ // The user enters a comma-separated list of tags. We only autocomplete the
+ // last tag.
+ $tags_typed = drupal_explode_tags($string);
+ $tag_last = drupal_strtolower(array_pop($tags_typed));
+ if (!empty($tag_last)) {
+ $prefix = count($tags_typed) ? implode(', ', $tags_typed) . ', ' : '';
+ }
+ }
+ else {
+ // The user enters a single tag.
+ $prefix = '';
+ $tag_last = $string;
+ }
+
+ if (isset($tag_last)) {
+ // Get an array of matching entities.
+ $match_operator = !empty($instance['widget']['settings']['match_operator']) ? $instance['widget']['settings']['match_operator'] : 'CONTAINS';
+ $entity_labels = $handler->getReferencableEntities($tag_last, $match_operator, 10);
+
+ // Loop through the products 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 e490441..d175b23 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;
/**
@@ -22,5 +23,13 @@ public function build(ContainerBuilder $container) {
// Register the SelectionPluginManager class with the dependency injection
// container.
$container->register('plugin.manager.entity_reference.selection', 'Drupal\entity_reference\Plugin\Type\SelectionPluginManager');
+
+ // Register the page controller and autocompletion helper.
+ $container->register('entity_reference.controller', 'Drupal\entity_reference\EntityReferenceController')
+ ->addArgument(new Reference('entity_reference.autocompletion'));
+
+ $container->register('entity_reference.autocompletion', 'Drupal\entity_reference\EntityReferenceAutocompletion')
+ ->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..e1f1715
--- /dev/null
+++ b/core/modules/entity_reference/lib/Drupal/entity_reference/EntityReferenceController.php
@@ -0,0 +1,82 @@
+entityReferenceAutocompletion = $entity_reference_autcompletion;
+ }
+
+ /**
+ * Autocomplete the label of an entity.
+ *
+ * @param Request $request
+ * The request object that contains the typed tags.
+ * @param string $type
+ * The widget type (i.e. 'single' or 'tags').
+ * @param string $field_name
+ * The name of the entity reference field.
+ * @param string $entity_type
+ * The entity type.
+ * @param string $bundle_name
+ * The bundle name.
+ * @param string $entity_id
+ * (optional) The entity ID the entity reference field is attached to.
+ * Defaults to ''.
+ *
+ * @throws \Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException
+ * Throws access denied when either the field or field instance does not
+ * exists or the user does not have access to edit the field.
+ *
+ * @return \Symfony\Component\HttpFoundation\JsonResponse
+ * The matched labels as json.
+ */
+ public function handleAutocomplete(Request $request, $type, $field_name, $entity_type, $bundle_name, $entity_id) {
+ if (!$field = field_info_field($field_name)) {
+ throw new AccessDeniedHttpException();
+ }
+ if (!$instance = field_info_instance($entity_type, $field_name, $bundle_name)) {
+ throw new AccessDeniedHttpException();
+ }
+
+ if ($field['type'] != 'entity_reference' || !field_access('edit', $field, $entity_type)) {
+ throw new AccessDeniedHttpException();
+ }
+
+ // Get the typed string, if exists from the URL.
+ $tags_typed = $request->query->get('q');
+ $tags_typed = drupal_explode_tags($tags_typed);
+ $string = drupal_strtolower(array_pop($tags_typed));
+
+ $matches = $this->entityReferenceAutocompletion->getMatches($type, $field, $instance, $entity_type, $entity_id, $string);
+
+ return new JsonResponse($matches);
+ }
+
+}