diff --git a/core/modules/entity_reference/lib/Drupal/entity_reference/EntityReferenceAutocomplete.php b/core/modules/entity_reference/lib/Drupal/entity_reference/EntityReferenceAutocomplete.php index c1d6114..ecf448e 100644 --- a/core/modules/entity_reference/lib/Drupal/entity_reference/EntityReferenceAutocomplete.php +++ b/core/modules/entity_reference/lib/Drupal/entity_reference/EntityReferenceAutocomplete.php @@ -9,7 +9,9 @@ use Drupal\Component\Utility\Tags; use Drupal\Core\Entity\EntityManagerInterface; +use Drupal\Core\Field\FieldDefinitionInterface; use Drupal\entity_reference\Plugin\Type\SelectionPluginManager; +use Drupal\field\FieldInstanceConfigInterface; use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException; /** @@ -50,12 +52,12 @@ public function __construct(EntityManagerInterface $entity_manager, SelectionPlu * 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 \Drupal\Core\Field\FieldDefinitionInterface $field_definition + * The field definition. * @param string $entity_type * The entity type. + * @param string $bundle + * The entity bundle. * @param string $entity_id * (optional) The entity ID the entity reference field is attached to. * Defaults to ''. @@ -72,7 +74,7 @@ public function __construct(EntityManagerInterface $entity_manager, SelectionPlu * * @see \Drupal\entity_reference\EntityReferenceController */ - public function getMatches($field, $instance, $entity_type, $entity_id = '', $prefix = '', $string = '') { + public function getMatches(FieldDefinitionInterface $field_definition, $entity_type, $bundle, $entity_id = '', $prefix = '', $string = '') { $matches = array(); $entity = NULL; @@ -82,11 +84,11 @@ public function getMatches($field, $instance, $entity_type, $entity_id = '', $pr throw new AccessDeniedHttpException(); } } - $handler = $this->selectionHandlerManager->getSelectionHandler($instance, $entity); + $handler = $this->selectionHandlerManager->getSelectionHandler($field_definition, $entity); if (isset($string)) { // Get an array of matching entities. - $widget = entity_get_form_display($instance->entity_type, $instance->bundle, 'default')->getComponent($instance->getName()); + $widget = entity_get_form_display($entity_type, $bundle, 'default')->getComponent($field_definition->getName()); $match_operator = !empty($widget['settings']['match_operator']) ? $widget['settings']['match_operator'] : 'CONTAINS'; $entity_labels = $handler->getReferenceableEntities($string, $match_operator, 10); diff --git a/core/modules/entity_reference/lib/Drupal/entity_reference/EntityReferenceController.php b/core/modules/entity_reference/lib/Drupal/entity_reference/EntityReferenceController.php index 4b9e2e9..2383ba6 100644 --- a/core/modules/entity_reference/lib/Drupal/entity_reference/EntityReferenceController.php +++ b/core/modules/entity_reference/lib/Drupal/entity_reference/EntityReferenceController.php @@ -71,12 +71,15 @@ public static function create(ContainerInterface $container) { * The matched labels as json. */ public function handleAutocomplete(Request $request, $type, $field_name, $entity_type, $bundle_name, $entity_id) { - if (!$instance = field_info_instance($entity_type, $field_name, $bundle_name)) { + $definitions = $this->entityManager()->getFieldDefinitions($entity_type, $bundle_name); + + if (!isset($definitions[$field_name])) { throw new AccessDeniedHttpException(); } + $field_definition = $definitions[$field_name]; $access_controller = $this->entityManager()->getAccessController($entity_type); - if ($instance->getType() != 'entity_reference' || !$access_controller->fieldAccess('edit', $instance)) { + if ($field_definition->getType() != 'entity_reference' || !$access_controller->fieldAccess('edit', $field_definition)) { throw new AccessDeniedHttpException(); } @@ -92,7 +95,7 @@ public function handleAutocomplete(Request $request, $type, $field_name, $entity $prefix = count($items_typed) ? Tags::implode($items_typed) . ', ' : ''; } - $matches = $this->entityReferenceAutocomplete->getMatches($instance->getField(), $instance, $entity_type, $entity_id, $prefix, $last_item); + $matches = $this->entityReferenceAutocomplete->getMatches($field_definition, $entity_type, $bundle_name, $entity_id, $prefix, $last_item); return new JsonResponse($matches); } diff --git a/core/modules/entity_reference/lib/Drupal/entity_reference/Tests/EntityReferenceAutocompleteTest.php b/core/modules/entity_reference/lib/Drupal/entity_reference/Tests/EntityReferenceAutocompleteTest.php index 84e48f8..7c7ba59 100644 --- a/core/modules/entity_reference/lib/Drupal/entity_reference/Tests/EntityReferenceAutocompleteTest.php +++ b/core/modules/entity_reference/lib/Drupal/entity_reference/Tests/EntityReferenceAutocompleteTest.php @@ -7,11 +7,13 @@ namespace Drupal\entity_reference\Tests; +use Drupal\Component\Utility\Json; +use Drupal\Component\Utility\String; use Drupal\Component\Utility\Tags; use Drupal\entity_reference\EntityReferenceController; use Drupal\system\Tests\Entity\EntityUnitTestBase; - use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException; /** * Tests the autocomplete functionality of Entity Reference. @@ -44,7 +46,7 @@ class EntityReferenceAutocompleteTest extends EntityUnitTestBase { * * @var array */ - public static $modules = array('entity_reference'); + public static $modules = array('entity_reference', 'entity_reference_test'); public static function getInfo() { return array( @@ -80,8 +82,8 @@ function testEntityReferenceAutocompletion() { // We should get both entities in a JSON encoded string. $input = '10/'; $data = $this->getAutocompleteResult('single', $input); - $this->assertIdentical($data[0]['label'], check_plain($entity_1->name->value), 'Autocomplete returned the first matching entity'); - $this->assertIdentical($data[1]['label'], check_plain($entity_2->name->value), 'Autocomplete returned the second matching entity'); + $this->assertIdentical($data[0]['label'], String::checkPlain($entity_1->name->value), 'Autocomplete returned the first matching entity'); + $this->assertIdentical($data[1]['label'], String::checkPlain($entity_2->name->value), 'Autocomplete returned the second matching entity'); // Try to autocomplete a entity label that matches the first entity. // We should only get the first entity in a JSON encoded string. @@ -89,7 +91,7 @@ function testEntityReferenceAutocompletion() { $data = $this->getAutocompleteResult('single', $input); $target = array( 'value' => $entity_1->name->value . ' (1)', - 'label' => check_plain($entity_1->name->value), + 'label' => String::checkPlain($entity_1->name->value), ); $this->assertIdentical(reset($data), $target, 'Autocomplete returns only the expected matching entity.'); @@ -97,7 +99,7 @@ function testEntityReferenceAutocompletion() { // the first entity is already typed in the autocomplete (tags) widget. $input = $entity_1->name->value . ' (1), 10/17'; $data = $this->getAutocompleteResult('tags', $input); - $this->assertIdentical($data[0]['label'], check_plain($entity_2->name->value), 'Autocomplete returned the second matching entity'); + $this->assertIdentical($data[0]['label'], String::checkPlain($entity_2->name->value), 'Autocomplete returned the second matching entity'); // Try to autocomplete a entity label with both a comma and a slash. $input = '"label with, and / t'; @@ -107,7 +109,7 @@ function testEntityReferenceAutocompletion() { $n = Tags::encode($n); $target = array( 'value' => $n, - 'label' => check_plain($entity_3->name->value), + 'label' => String::checkPlain($entity_3->name->value), ); $this->assertIdentical(reset($data), $target, 'Autocomplete returns an entity label containing a comma and a slash.'); } @@ -130,6 +132,37 @@ protected function getAutocompleteResult($type, $input) { $entity_reference_controller = EntityReferenceController::create($this->container); $result = $entity_reference_controller->handleAutocomplete($request, $type, $this->fieldName, $this->entityType, $this->bundle, 'NULL')->getContent(); - return drupal_json_decode($result); + return Json::decode($result); } + + /** + * Tests autocomplete for entity base fields. + */ + public function testBaseField() { + // Add two users. + $user_1 = entity_create('user', array('name' => 'auto1')); + $user_1->save(); + $user_2 = entity_create('user', array('name' => 'auto2')); + $user_2->save(); + + $request = Request::create('entity_reference/autocomplete/single/user_id/entity_test/entity_test/NULL'); + $request->query->set('q', 'auto'); + + $entity_reference_controller = EntityReferenceController::create($this->container); + $result = $entity_reference_controller->handleAutocomplete($request, 'single', 'user_id', 'entity_test', 'entity_test', 'NULL')->getContent(); + + $data = Json::decode($result); + $this->assertIdentical($data[0]['label'], String::checkPlain($user_1->getUsername()), 'Autocomplete returned the first matching entity'); + $this->assertIdentical($data[1]['label'], String::checkPlain($user_2->getUsername()), 'Autocomplete returned the second matching entity'); + + // Checks that exception thrown for unknown field. + try { + $entity_reference_controller->handleAutocomplete($request, 'single', 'unknown_field', 'entity_test', 'entity_test', 'NULL')->getContent(); + $this->fail('Autocomplete throws exception for unknown field.'); + } + catch (AccessDeniedHttpException $e) { + $this->pass('Autocomplete throws exception for unknown field.'); + } + } + } diff --git a/core/modules/entity_reference/tests/modules/entity_reference_test/entity_reference_test.module b/core/modules/entity_reference/tests/modules/entity_reference_test/entity_reference_test.module new file mode 100644 index 0000000..2013fd1 --- /dev/null +++ b/core/modules/entity_reference/tests/modules/entity_reference_test/entity_reference_test.module @@ -0,0 +1,24 @@ +id() === 'entity_test') { + // Allow user_id field to use configurable widget. + $fields['user_id'] + ->setSetting('handler', 'default') + ->setDisplayOptions('form', array( + 'type' => 'entity_reference_autocomplete', + 'weight' => 0, + )) + ->setDisplayConfigurable('form', TRUE); + } +}