diff --git a/core/lib/Drupal/Core/Entity/Element/EntityAutocomplete.php b/core/lib/Drupal/Core/Entity/Element/EntityAutocomplete.php index 2a52b79..4d1a257 100644 --- a/core/lib/Drupal/Core/Entity/Element/EntityAutocomplete.php +++ b/core/lib/Drupal/Core/Entity/Element/EntityAutocomplete.php @@ -10,6 +10,7 @@ use Drupal\Component\Utility\Crypt; use Drupal\Component\Utility\Tags; use Drupal\Core\Entity\EntityInterface; +use Drupal\Core\Entity\EntityReferenceSelection\SelectionWithAutocreateInterface; use Drupal\Core\Form\FormStateInterface; use Drupal\Core\Render\Element\Textfield; use Drupal\Core\Site\Settings; @@ -147,7 +148,7 @@ public static function validateEntityAutocomplete(array &$element, FormStateInte 'handler_settings' => $element['#selection_settings'], ); $handler = \Drupal::service('plugin.manager.entity_reference_selection')->getInstance($options); - $autocreate = (bool) $element['#autocreate']; + $autocreate = (bool) $element['#autocreate'] && $handler instanceof SelectionWithAutocreateInterface; $input_values = $element['#tags'] ? Tags::explode($element['#value']) : array($element['#value']); foreach ($input_values as $input) { @@ -167,13 +168,14 @@ public static function validateEntityAutocomplete(array &$element, FormStateInte // Auto-create item. See an example of how this is handled in // \Drupal\Core\Field\Plugin\Field\FieldType\EntityReferenceItem::presave(). $value[] = array( - 'entity' => static::createNewEntity($element['#target_type'], $element['#autocreate']['bundle'], $input, $element['#autocreate']['uid']) + 'entity' => $handler->createNewEntity($element['#target_type'], $element['#autocreate']['bundle'], $input, $element['#autocreate']['uid']), ); } } // Check that the referenced entities are valid, if needed. - if ($element['#validate_reference'] && !$autocreate && !empty($value)) { + if ($element['#validate_reference'] && !empty($value)) { + // Validate existing entities. $ids = array_reduce($value, function ($return, $item) { if (isset($item['target_id'])) { $return[] = $item['target_id']; @@ -189,6 +191,30 @@ public static function validateEntityAutocomplete(array &$element, FormStateInte } } } + + // Validate newly created entities. + $new_entities = array_reduce($value, function ($return, $item) { + if (isset($item['entity'])) { + $return[] = $item['entity']; + } + return $return; + }); + + if ($new_entities) { + if ($autocreate) { + $valid_new_entities = $handler->validateReferenceableNewEntities($new_entities); + $invalid_new_entities = array_diff_key($new_entities, $valid_new_entities); + } + else { + // If the selection handler does not support referencing newly + // created entities, all of them should be invalidated. + $invalid_new_entities = $new_entities; + } + + foreach ($invalid_new_entities as $entity) { + $form_state->setError($element, t('This entity (%type: %label) cannot be referenced.', array('%type' => $element['#target_type'], '%label' => $entity->label()))); + } + } } // Use only the last value if the form element does not support multiple @@ -310,37 +336,4 @@ public static function extractEntityIdFromAutocompleteInput($input) { return $match; } - /** - * Creates a new entity from a label entered in the autocomplete input. - * - * @param string $entity_type_id - * The entity type ID. - * @param string $bundle - * The bundle name. - * @param string $label - * The entity label. - * @param int $uid - * The entity owner ID. - * - * @return \Drupal\Core\Entity\EntityInterface - */ - protected static function createNewEntity($entity_type_id, $bundle, $label, $uid) { - $entity_manager = \Drupal::entityManager(); - - $entity_type = $entity_manager->getDefinition($entity_type_id); - $bundle_key = $entity_type->getKey('bundle'); - $label_key = $entity_type->getKey('label'); - - $entity = $entity_manager->getStorage($entity_type_id)->create(array( - $bundle_key => $bundle, - $label_key => $label, - )); - - if ($entity instanceof EntityOwnerInterface) { - $entity->setOwnerId($uid); - } - - return $entity; - } - } diff --git a/core/lib/Drupal/Core/Entity/EntityReferenceSelection/SelectionInterface.php b/core/lib/Drupal/Core/Entity/EntityReferenceSelection/SelectionInterface.php index 83120d1..132b9a7 100644 --- a/core/lib/Drupal/Core/Entity/EntityReferenceSelection/SelectionInterface.php +++ b/core/lib/Drupal/Core/Entity/EntityReferenceSelection/SelectionInterface.php @@ -30,7 +30,7 @@ public function getReferenceableEntities($match = NULL, $match_operator = 'CONTAINS', $limit = 0); /** - * Counts entities that are referenceable by a given field. + * Counts entities that are referenceable. * * @return int * The number of referenceable entities. @@ -38,7 +38,7 @@ public function getReferenceableEntities($match = NULL, $match_operator = 'CONTA public function countReferenceableEntities($match = NULL, $match_operator = 'CONTAINS'); /** - * Validates that entities can be referenced by this field. + * Validates which existing entities can be referenced. * * @return array * An array of valid entity IDs. diff --git a/core/lib/Drupal/Core/Entity/EntityReferenceSelection/SelectionWithAutocreateInterface.php b/core/lib/Drupal/Core/Entity/EntityReferenceSelection/SelectionWithAutocreateInterface.php new file mode 100644 index 0000000..f81d5fa --- /dev/null +++ b/core/lib/Drupal/Core/Entity/EntityReferenceSelection/SelectionWithAutocreateInterface.php @@ -0,0 +1,52 @@ +entityManager->getDefinition($entity_type_id); + $bundle_key = $entity_type->getKey('bundle'); + $label_key = $entity_type->getKey('label'); + + $entity = $this->entityManager->getStorage($entity_type_id)->create(array( + $bundle_key => $bundle, + $label_key => $label, + )); + + if ($entity instanceof EntityOwnerInterface) { + $entity->setOwnerId($uid); + } + + return $entity; + } + + /** + * {@inheritdoc} + */ + public function validateReferenceableNewEntities(array $entities) { + return array_filter($entities, function ($entity) { + if (isset($this->configuration['handler_settings']['target_bundles'])) { + return in_array($entity->bundle(), $this->configuration['handler_settings']['target_bundles']); + } + return TRUE; + }); + } + + /** * Builds an EntityQuery to get referenceable entities. * * @param string|null $match diff --git a/core/lib/Drupal/Core/Entity/Plugin/Validation/Constraint/ValidReferenceConstraint.php b/core/lib/Drupal/Core/Entity/Plugin/Validation/Constraint/ValidReferenceConstraint.php index bf8658a..f27c22d 100644 --- a/core/lib/Drupal/Core/Entity/Plugin/Validation/Constraint/ValidReferenceConstraint.php +++ b/core/lib/Drupal/Core/Entity/Plugin/Validation/Constraint/ValidReferenceConstraint.php @@ -26,10 +26,24 @@ class ValidReferenceConstraint extends Constraint { * * @var string */ - public $message = 'The referenced entity (%type: %id) does not exist.'; + public $message = 'This entity (%type: %id) cannot be referenced.'; /** - * Validation message when the target_id is empty. + * Violation message when the entity does not exist. + * + * @var string + */ + public $nonExistingMessage = 'The referenced entity (%type: %id) does not exist.'; + + /** + * Violation message when a new entity ("autocreate") is invalid. + * + * @var string + */ + public $invalidAutocreateMessage = 'This entity (%type: %label) cannot be referenced.'; + + /** + * Violation message when the target_id is empty. * * @var string */ diff --git a/core/lib/Drupal/Core/Entity/Plugin/Validation/Constraint/ValidReferenceConstraintValidator.php b/core/lib/Drupal/Core/Entity/Plugin/Validation/Constraint/ValidReferenceConstraintValidator.php index 8f704c1..f5696cd 100644 --- a/core/lib/Drupal/Core/Entity/Plugin/Validation/Constraint/ValidReferenceConstraintValidator.php +++ b/core/lib/Drupal/Core/Entity/Plugin/Validation/Constraint/ValidReferenceConstraintValidator.php @@ -7,39 +7,142 @@ namespace Drupal\Core\Entity\Plugin\Validation\Constraint; +use Drupal\Core\DependencyInjection\ContainerInjectionInterface; +use Drupal\Core\Entity\EntityManagerInterface; +use Drupal\Core\Entity\EntityReferenceSelection\SelectionPluginManagerInterface; +use Drupal\Core\Entity\EntityReferenceSelection\SelectionWithAutocreateInterface; +use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\Validator\Constraint; use Symfony\Component\Validator\ConstraintValidator; /** * Checks if referenced entities are valid. */ -class ValidReferenceConstraintValidator extends ConstraintValidator { +class ValidReferenceConstraintValidator extends ConstraintValidator implements ContainerInjectionInterface { + + /** + * The selection plugin manager. + * + * @var \Drupal\Core\Entity\EntityReferenceSelection\SelectionPluginManagerInterface + */ + protected $selectionManager; + + /** + * The entity manager. + * + * @var \Drupal\Core\Entity\EntityManagerInterface + */ + protected $entityManager; + + /** + * Constructs a ValidReferenceConstraintValidator object. + * + * @param \Drupal\Core\Entity\EntityReferenceSelection\SelectionPluginManagerInterface $selection_manager + * The selection plugin manager. + * @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager + * The entity manager. + */ + public function __construct(SelectionPluginManagerInterface $selection_manager, EntityManagerInterface $entity_manager) { + $this->selectionManager = $selection_manager; + $this->entityManager = $entity_manager; + } + + /** + * {@inheritdoc} + */ + public static function create(ContainerInterface $container) { + return new static( + $container->get('plugin.manager.entity_reference_selection'), + $container->get('entity.manager') + ); + } /** * {@inheritdoc} */ public function validate($value, Constraint $constraint) { - /** @var \Drupal\Core\Field\FieldItemInterface $value */ + /** @var \Drupal\Core\Field\FieldItemListInterface $value */ /** @var ValidReferenceConstraint $constraint */ if (!isset($value)) { return; } - // We don't use a regular NotNull constraint for the target_id property as - // a NULL value is valid if the entity property contains an unsaved entity. - // @see \Drupal\Core\TypedData\DataReferenceTargetDefinition::getConstraints - if (!$value->isEmpty() && $value->target_id === NULL && !$value->entity->isNew()) { - $this->context->addViolation($constraint->nullMessage); - return; + + // Collect new entities and IDs of existing entities across the field items. + $new_entities = []; + $target_ids = []; + foreach ($value as $delta => $item) { + $target_id = $item->target_id; + // We don't use a regular NotNull constraint for the target_id property as + // NULL is allowed if the entity property contains an unsaved entity. + // @see \Drupal\Core\TypedData\DataReferenceTargetDefinition::getConstraints() + if (!$item->isEmpty() && $target_id === NULL) { + if (!$item->entity->isNew()) { + $this->context->buildViolation($constraint->nullMessage) + ->atPath((string) $delta) + ->addViolation(); + return; + } + $new_entities[$delta] = $item->entity; + } + + // '0' or NULL are considered valid empty references. + if (!empty($target_id)) { + $target_ids[$delta] = $target_id; + } } - $id = $value->get('target_id')->getValue(); - // '0' or NULL are considered valid empty references. - if (empty($id)) { + + // Early opt-out if nothing to validate. + if (!$new_entities && !$target_ids) { return; } - $referenced_entity = $value->get('entity')->getValue(); - if (!$referenced_entity) { - $type = $value->getFieldDefinition()->getSetting('target_type'); - $this->context->addViolation($constraint->message, array('%type' => $type, '%id' => $id)); + + /** @var \Drupal\Core\Entity\EntityReferenceSelection\SelectionInterface $handler * */ + $handler = $this->selectionManager->getSelectionHandler($value->getFieldDefinition()); + $target_type_id = $value->getFieldDefinition()->getSetting('target_type'); + + // Add violations on deltas with a new entity that is not valid. + if ($new_entities) { + if ($handler instanceof SelectionWithAutocreateInterface) { + $valid_new_entities = $handler->validateReferenceableNewEntities($new_entities); + $invalid_new_entities = array_diff_key($new_entities, $valid_new_entities); + } + else { + // If the selection handler does not support referencing newly created + // entities, all of them should be invalidated. + $invalid_new_entities = $new_entities; + } + + foreach ($invalid_new_entities as $delta => $entity) { + $this->context->buildViolation($constraint->invalidAutocreateMessage) + ->setParameter('%type', $target_type_id) + ->setParameter('%label', $entity->label()) + ->atPath((string) $delta . '.entity') + ->setInvalidValue($entity) + ->addViolation(); + } + } + + // Add violations on deltas with a target_id that is not valid. + if ($target_ids) { + $valid_target_ids = $handler->validateReferenceableEntities($target_ids); + if ($invalid_target_ids = array_diff($target_ids, $valid_target_ids)) { + // For accuracy of the error message, differentiate non-referenceable + // and non-existent entities. + $target_type = $this->entityManager->getDefinition($target_type_id); + $existing_ids = $this->entityManager->getStorage($target_type_id)->getQuery() + ->condition($target_type->getKey('id'), $invalid_target_ids, 'IN') + ->execute(); + foreach ($invalid_target_ids as $delta => $target_id) { + $message = in_array($target_id, $existing_ids) ? $constraint->message : $constraint->nonExistingMessage; + $this->context->buildViolation($message) + ->setParameter('%type', $target_type_id) + ->setParameter('%id', $target_id) + ->atPath((string) $delta . '.target_id') + ->setInvalidValue($target_id) + ->addViolation(); + } + } } } + } diff --git a/core/lib/Drupal/Core/Field/EntityReferenceFieldItemList.php b/core/lib/Drupal/Core/Field/EntityReferenceFieldItemList.php index 4217b2e..e558e58 100644 --- a/core/lib/Drupal/Core/Field/EntityReferenceFieldItemList.php +++ b/core/lib/Drupal/Core/Field/EntityReferenceFieldItemList.php @@ -18,6 +18,16 @@ class EntityReferenceFieldItemList extends FieldItemList implements EntityRefere /** * {@inheritdoc} */ + public function getConstraints() { + $constraints = parent::getConstraints(); + $constraint_manager = \Drupal::typedDataManager()->getValidationConstraintManager(); + $constraints[] = $constraint_manager->create('ValidReference', []); + return $constraints; + } + + /** + * {@inheritdoc} + */ public function referencedEntities() { if (empty($this->list)) { return array(); diff --git a/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/EntityReferenceItem.php b/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/EntityReferenceItem.php index 9e76afb..7553487 100644 --- a/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/EntityReferenceItem.php +++ b/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/EntityReferenceItem.php @@ -42,7 +42,6 @@ * list_class = "\Drupal\Core\Field\EntityReferenceFieldItemList", * default_widget = "entity_reference_autocomplete", * default_formatter = "entity_reference_label", - * constraints = {"ValidReference" = {}} * ) */ class EntityReferenceItem extends FieldItemBase implements OptionsProviderInterface, PreconfiguredFieldUiOptionsInterface { @@ -165,20 +164,6 @@ public function getConstraints() { unset($constraints[$key]); } } - list($current_handler) = explode(':', $this->getSetting('handler'), 2); - if ($current_handler === 'default') { - $handler_settings = $this->getSetting('handler_settings'); - if (isset($handler_settings['target_bundles'])) { - $constraint_manager = \Drupal::typedDataManager()->getValidationConstraintManager(); - $constraints[] = $constraint_manager->create('ComplexData', [ - 'entity' => [ - 'Bundle' => [ - 'bundle' => $handler_settings['target_bundles'], - ], - ], - ]); - } - } return $constraints; } diff --git a/core/modules/comment/src/Plugin/EntityReferenceSelection/CommentSelection.php b/core/modules/comment/src/Plugin/EntityReferenceSelection/CommentSelection.php index c8bc4a7..ea89c9e 100644 --- a/core/modules/comment/src/Plugin/EntityReferenceSelection/CommentSelection.php +++ b/core/modules/comment/src/Plugin/EntityReferenceSelection/CommentSelection.php @@ -42,6 +42,32 @@ protected function buildEntityQuery($match = NULL, $match_operator = 'CONTAINS') /** * {@inheritdoc} */ + public function createNewEntity($entity_type_id, $bundle, $label, $uid) { + $entity = parent::createNewEntity($entity_type_id, $bundle, $label, $uid); + + // In order to create a referenceable comment, it needs to published. + $entity->status->value = CommentInterface::PUBLISHED; + + return $entity; + } + + /** + * {@inheritdoc} + */ + public function validateReferenceableNewEntities(array $entities) { + $entities = parent::validateReferenceableNewEntities($entities); + // Mirror the conditions checked in buildEntityQuery(). + if (!$this->currentUser->hasPermission('administer comments')) { + $entities = array_filter($entities, function ($entity) { + return $entity->status->value === CommentInterface::PUBLISHED; + }); + } + return $entities; + } + + /** + * {@inheritdoc} + */ public function entityQueryAlter(SelectInterface $query) { $tables = $query->getTables(); $data_table = 'comment_field_data'; diff --git a/core/modules/comment/src/Tests/CommentValidationTest.php b/core/modules/comment/src/Tests/CommentValidationTest.php index 62acec0..5c30d89 100644 --- a/core/modules/comment/src/Tests/CommentValidationTest.php +++ b/core/modules/comment/src/Tests/CommentValidationTest.php @@ -39,7 +39,7 @@ protected function setUp() { */ public function testValidation() { // Add a user. - $user = User::create(array('name' => 'test')); + $user = User::create(array('name' => 'test', 'status' => TRUE)); $user->save(); // Add comment type. diff --git a/core/modules/file/src/Plugin/EntityReferenceSelection/FileSelection.php b/core/modules/file/src/Plugin/EntityReferenceSelection/FileSelection.php index e789154..abd06da 100644 --- a/core/modules/file/src/Plugin/EntityReferenceSelection/FileSelection.php +++ b/core/modules/file/src/Plugin/EntityReferenceSelection/FileSelection.php @@ -27,8 +27,39 @@ class FileSelection extends DefaultSelection { */ protected function buildEntityQuery($match = NULL, $match_operator = 'CONTAINS') { $query = parent::buildEntityQuery($match, $match_operator); - $query->condition('status', FILE_STATUS_PERMANENT); + // Allow referencing : + // - files with status "permanent" + // - or files uploaded by the current user (since newly uploaded files only + // become "permanent" after the containing entity gets validated and + // saved.) + $query->condition($query->orConditionGroup() + ->condition('status', FILE_STATUS_PERMANENT) + ->condition('uid', $this->currentUser->id())); return $query; } + /** + * {@inheritdoc} + */ + public function createNewEntity($entity_type_id, $bundle, $label, $uid) { + $entity = parent::createNewEntity($entity_type_id, $bundle, $label, $uid); + + // In order to create a referenceable file, it needs to have a "permanent" + // status. + $entity->status->value = FILE_STATUS_PERMANENT; + + return $entity; + } + + /** + * {@inheritdoc} + */ + public function validateReferenceableNewEntities(array $entities) { + $entities = parent::validateReferenceableNewEntities($entities); + $entities = array_filter($entities, function ($entity) { + return $entity->status->value === FILE_STATUS_PERMANENT || $entity->uid->target_id === $this->currentUser->id(); + }); + return $entities; + } + } diff --git a/core/modules/file/src/Plugin/Field/FieldType/FileItem.php b/core/modules/file/src/Plugin/Field/FieldType/FileItem.php index 1633147..8c37465 100644 --- a/core/modules/file/src/Plugin/Field/FieldType/FileItem.php +++ b/core/modules/file/src/Plugin/Field/FieldType/FileItem.php @@ -28,7 +28,7 @@ * default_widget = "file_generic", * default_formatter = "file_default", * list_class = "\Drupal\file\Plugin\Field\FieldType\FileFieldItemList", - * constraints = {"ValidReference" = {}, "ReferenceAccess" = {}} + * constraints = {"ReferenceAccess" = {}} * ) */ class FileItem extends EntityReferenceItem { diff --git a/core/modules/image/src/Plugin/Field/FieldType/ImageItem.php b/core/modules/image/src/Plugin/Field/FieldType/ImageItem.php index 442929f..0d7fe13 100644 --- a/core/modules/image/src/Plugin/Field/FieldType/ImageItem.php +++ b/core/modules/image/src/Plugin/Field/FieldType/ImageItem.php @@ -43,7 +43,7 @@ * }, * }, * list_class = "\Drupal\file\Plugin\Field\FieldType\FileFieldItemList", - * constraints = {"ValidReference" = {}, "ReferenceAccess" = {}} + * constraints = {"ReferenceAccess" = {}} * ) */ class ImageItem extends FileItem { @@ -346,7 +346,7 @@ public static function generateSampleValue(FieldDefinitionInterface $field_defin if ($path = $random->image(drupal_realpath($destination), $min_resolution, $max_resolution)) { $image = File::create(); $image->setFileUri($path); - // $image->setOwner($account); + $image->setOwnerId(\Drupal::currentUser()->id()); $image->setMimeType('image/' . pathinfo($path, PATHINFO_EXTENSION)); $image->setFileName(drupal_basename($path)); $destination_dir = $settings['uri_scheme'] . '://' . $settings['file_directory']; diff --git a/core/modules/node/src/Plugin/EntityReferenceSelection/NodeSelection.php b/core/modules/node/src/Plugin/EntityReferenceSelection/NodeSelection.php index 276c795..5d7954a 100644 --- a/core/modules/node/src/Plugin/EntityReferenceSelection/NodeSelection.php +++ b/core/modules/node/src/Plugin/EntityReferenceSelection/NodeSelection.php @@ -48,4 +48,30 @@ protected function buildEntityQuery($match = NULL, $match_operator = 'CONTAINS') return $query; } + /** + * {@inheritdoc} + */ + public function createNewEntity($entity_type_id, $bundle, $label, $uid) { + $entity = parent::createNewEntity($entity_type_id, $bundle, $label, $uid); + + // In order to create a referenceable node, it needs to published. + $entity->status->value = NODE_PUBLISHED; + + return $entity; + } + + /** + * {@inheritdoc} + */ + public function validateReferenceableNewEntities(array $entities) { + $entities = parent::validateReferenceableNewEntities($entities); + // Mirror the conditions checked in buildEntityQuery(). + if (!$this->currentUser->hasPermission('bypass node access') && !count($this->moduleHandler->getImplementations('node_grants'))) { + $entities = array_filter($entities, function ($entity) { + return $entity->status->value === NODE_PUBLISHED; + }); + } + return $entities; + } + } diff --git a/core/modules/system/src/Tests/Entity/Element/EntityAutocompleteElementFormTest.php b/core/modules/system/src/Tests/Entity/Element/EntityAutocompleteElementFormTest.php index 0fdd9af..3e0386c 100644 --- a/core/modules/system/src/Tests/Entity/Element/EntityAutocompleteElementFormTest.php +++ b/core/modules/system/src/Tests/Entity/Element/EntityAutocompleteElementFormTest.php @@ -137,6 +137,7 @@ public function buildForm(array $form, FormStateInterface $form_state) { $form['single_autocreate_no_validate'] = array( '#type' => 'entity_autocomplete', '#target_type' => 'entity_test', + '#validate_reference' => FALSE, '#autocreate' => array( 'bundle' => 'entity_test', ), diff --git a/core/modules/system/src/Tests/Entity/EntityFieldTest.php b/core/modules/system/src/Tests/Entity/EntityFieldTest.php index 6fae79b..5c9161e 100644 --- a/core/modules/system/src/Tests/Entity/EntityFieldTest.php +++ b/core/modules/system/src/Tests/Entity/EntityFieldTest.php @@ -691,8 +691,8 @@ public function testEntityConstraintValidation() { ->setSetting('target_type', 'node') ->setSetting('handler_settings', ['target_bundles' => ['article' => 'article']]); $reference_field = \Drupal::TypedDataManager()->create($definition); - $reference = $reference_field->appendItem(array('entity' => $node)); - $violations = $reference->validate(); + $reference_field->appendItem(array('entity' => $node)); + $violations = $reference_field->validate(); $this->assertEqual($violations->count(), 1); $node = entity_create('node', array( @@ -701,8 +701,8 @@ public function testEntityConstraintValidation() { 'title' => $this->randomString(), )); $node->save(); - $reference->setValue($node); - $violations = $reference->validate(); + $reference_field->entity = $node; + $violations = $reference_field->validate(); $this->assertEqual($violations->count(), 0); } diff --git a/core/modules/system/src/Tests/Entity/EntityReferenceFieldTest.php b/core/modules/system/src/Tests/Entity/EntityReferenceFieldTest.php index 8e64386..aa49b84 100644 --- a/core/modules/system/src/Tests/Entity/EntityReferenceFieldTest.php +++ b/core/modules/system/src/Tests/Entity/EntityReferenceFieldTest.php @@ -113,7 +113,7 @@ public function testEntityReferenceFieldValidation() { $entity->{$this->fieldName}->target_id = $referenced_entity->id(); $violations = $entity->{$this->fieldName}->validate(); $this->assertEqual($violations->count(), 1, 'Validation throws a violation.'); - $this->assertEqual($violations[0]->getMessage(), t('The entity must be of bundle %bundle.', array('%bundle' => $this->bundle))); + $this->assertEqual($violations[0]->getMessage(), t('This entity (%type: %id) cannot be referenced.', array('%type' => $this->referencedEntityType, '%id' => $referenced_entity->id()))); } /** diff --git a/core/modules/user/src/Plugin/EntityReferenceSelection/UserSelection.php b/core/modules/user/src/Plugin/EntityReferenceSelection/UserSelection.php index 160c50e..c830602 100644 --- a/core/modules/user/src/Plugin/EntityReferenceSelection/UserSelection.php +++ b/core/modules/user/src/Plugin/EntityReferenceSelection/UserSelection.php @@ -171,6 +171,25 @@ protected function buildEntityQuery($match = NULL, $match_operator = 'CONTAINS') /** * {@inheritdoc} */ + public function validateReferenceableNewEntities(array $entities) { + $entities = parent::validateReferenceableNewEntities($entities); + // Mirror the conditions checked in buildEntityQuery(). + if (!empty($this->configuration['handler_settings']['filter']['role'])) { + $entities = array_filter($entities, function ($entity) { + return !empty(array_intersect($entity->getRoles(), $this->configuration['handler_settings']['filter']['role'])); + }); + } + if (!$this->currentUser->hasPermission('administer users')) { + $entities = array_filter($entities, function ($entity) { + return $entity->status->value === 1; + }); + } + return $entities; + } + + /** + * {@inheritdoc} + */ public function entityQueryAlter(SelectInterface $query) { // Bail out early if we do not need to match the Anonymous user. $handler_settings = $this->configuration['handler_settings']; diff --git a/core/modules/user/src/Tests/UserValidationTest.php b/core/modules/user/src/Tests/UserValidationTest.php index 4891d5a..dfa8a21 100644 --- a/core/modules/user/src/Tests/UserValidationTest.php +++ b/core/modules/user/src/Tests/UserValidationTest.php @@ -176,7 +176,7 @@ function testValidation() { $user->roles[1]->target_id = 'unknown_role'; $violations = $user->validate(); $this->assertEqual(count($violations), 1); - $this->assertEqual($violations[0]->getPropertyPath(), 'roles.1'); + $this->assertEqual($violations[0]->getPropertyPath(), 'roles.1.target_id'); $this->assertEqual($violations[0]->getMessage(), t('The referenced entity (%entity_type: %name) does not exist.', array('%entity_type' => 'user_role', '%name' => 'unknown_role'))); }