commit 470072a07d99248a8aec4a7645a016fe427475d5
Author: Gergely Pap <gergely.pap.sp@lhsystems.com>
Date:   Tue Oct 24 17:10:35 2017 +0200

    Patch 2

diff --git a/core/config/schema/core.data_types.schema.yml b/core/config/schema/core.data_types.schema.yml
index 160b526..9ecfb70 100644
--- a/core/config/schema/core.data_types.schema.yml
+++ b/core/config/schema/core.data_types.schema.yml
@@ -822,6 +822,9 @@ entity_reference_selection.default:
     auto_create_bundle:
       type: string
       label: 'Bundle assigned to the auto-created entities.'
+    allow_self_reference:
+      type: boolean
+      label: 'Allow an entity to reference itself'
 
 # Schema for all entity reference 'default:*' selection handlers that are not
 # providing a specific schema.
diff --git a/core/lib/Drupal/Core/Entity/EntityAutocompleteMatcher.php b/core/lib/Drupal/Core/Entity/EntityAutocompleteMatcher.php
index 2cede4d..fd8923a 100644
--- a/core/lib/Drupal/Core/Entity/EntityAutocompleteMatcher.php
+++ b/core/lib/Drupal/Core/Entity/EntityAutocompleteMatcher.php
@@ -39,6 +39,8 @@ public function __construct(SelectionPluginManagerInterface $selection_manager)
    *   An array of settings that will be passed to the selection handler.
    * @param string $string
    *   (optional) The label of the entity to query by.
+   * @param \Drupal\Core\Entity\EntityInterface $host_entity
+   *   (optional) The referencing entity, if any. Defaults to NULL.
    *
    * @return array
    *   An array of matched entity labels, in the format required by the AJAX
@@ -49,12 +51,13 @@ public function __construct(SelectionPluginManagerInterface $selection_manager)
    *
    * @see \Drupal\system\Controller\EntityAutocompleteController
    */
-  public function getMatches($target_type, $selection_handler, $selection_settings, $string = '') {
+  public function getMatches($target_type, $selection_handler, $selection_settings, $string = '', EntityInterface $host_entity = NULL) {
     $matches = [];
 
     $options = $selection_settings + [
       'target_type' => $target_type,
       'handler' => $selection_handler,
+      'entity' => $host_entity,
     ];
     $handler = $this->selectionManager->getInstance($options);
 
diff --git a/core/lib/Drupal/Core/Entity/Plugin/EntityReferenceSelection/DefaultSelection.php b/core/lib/Drupal/Core/Entity/Plugin/EntityReferenceSelection/DefaultSelection.php
index 218131c..cc5a1be 100644
--- a/core/lib/Drupal/Core/Entity/Plugin/EntityReferenceSelection/DefaultSelection.php
+++ b/core/lib/Drupal/Core/Entity/Plugin/EntityReferenceSelection/DefaultSelection.php
@@ -68,6 +68,7 @@ public function defaultConfiguration() {
       ],
       'auto_create' => FALSE,
       'auto_create_bundle' => NULL,
+      'allow_self_reference' => TRUE,
     ] + parent::defaultConfiguration();
   }
 
@@ -197,6 +198,12 @@ public function buildConfigurationForm(array $form, FormStateInterface $form_sta
       ];
     }
 
+    $form['allow_self_reference'] = [
+      '#type' => 'checkbox',
+      '#title' => $this->t('Allow an entity to reference itself'),
+      '#default_value' => $selection_handler_settings['allow_self_reference'],
+    ];
+
     return $form;
   }
 
@@ -352,6 +359,11 @@ protected function buildEntityQuery($match = NULL, $match_operator = 'CONTAINS')
       $query->condition($label_key, $match, $match_operator);
     }
 
+    // Disallow self-references if possible.
+    if (isset($this->configuration['entity']) && $this->configuration['entity']->id() && isset($handler_settings['allow_self_reference']) && !$handler_settings['allow_self_reference']) {
+      $query->condition($entity_type->getKey('id'), $this->configuration['entity']->id(), '<>');
+    }
+
     // Add entity-access tag.
     $query->addTag($target_type . '_access');
 
diff --git a/core/lib/Drupal/Core/Field/Plugin/Field/FieldWidget/EntityReferenceAutocompleteWidget.php b/core/lib/Drupal/Core/Field/Plugin/Field/FieldWidget/EntityReferenceAutocompleteWidget.php
index 11f048e..de317ab 100644
--- a/core/lib/Drupal/Core/Field/Plugin/Field/FieldWidget/EntityReferenceAutocompleteWidget.php
+++ b/core/lib/Drupal/Core/Field/Plugin/Field/FieldWidget/EntityReferenceAutocompleteWidget.php
@@ -88,7 +88,10 @@ public function formElement(FieldItemListInterface $items, $delta, array $elemen
     $referenced_entities = $items->referencedEntities();
 
     // Append the match operation to the selection settings.
-    $selection_settings = $this->getFieldSetting('handler_settings') + ['match_operator' => $this->getSetting('match_operator')];
+    $selection_settings = $this->getFieldSetting('handler_settings') + [
+      'match_operator' => $this->getSetting('match_operator'),
+      'entity' => $entity,
+    ];
 
     $element += [
       '#type' => 'entity_autocomplete',
diff --git a/core/modules/system/src/Controller/EntityAutocompleteController.php b/core/modules/system/src/Controller/EntityAutocompleteController.php
index 974c2de..dd25ff0 100644
--- a/core/modules/system/src/Controller/EntityAutocompleteController.php
+++ b/core/modules/system/src/Controller/EntityAutocompleteController.php
@@ -78,6 +78,7 @@ public static function create(ContainerInterface $container) {
    */
   public function handleAutocomplete(Request $request, $target_type, $selection_handler, $selection_settings_key) {
     $matches = [];
+
     // Get the typed string from the URL, if it exists.
     if ($input = $request->query->get('q')) {
       $typed_string = Tags::explode($input);
@@ -100,7 +101,12 @@ public function handleAutocomplete(Request $request, $target_type, $selection_ha
         throw new AccessDeniedHttpException();
       }
 
-      $matches = $this->matcher->getMatches($target_type, $selection_handler, $selection_settings, $typed_string);
+      // The host entity was not passed in the selection settings. Set to NULL.
+      if (empty($selection_settings['entity'])) {
+        $selection_settings['entity'] = NULL;
+      }
+
+      $matches = $this->matcher->getMatches($target_type, $selection_handler, $selection_settings, $typed_string, $selection_settings['entity']);
     }
 
     return new JsonResponse($matches);
diff --git a/core/modules/system/system.routing.yml b/core/modules/system/system.routing.yml
index 9cfe2ca..8b7932d 100644
--- a/core/modules/system/system.routing.yml
+++ b/core/modules/system/system.routing.yml
@@ -501,9 +501,10 @@ system.admin_content:
     _permission: 'access administration pages'
 
 system.entity_autocomplete:
-  path: '/entity_reference_autocomplete/{target_type}/{selection_handler}/{selection_settings_key}'
+  path: '/entity_reference_autocomplete/{target_type}/{selection_handler}/{selection_settings_key}/{host_entity_id}'
   defaults:
     _controller: '\Drupal\system\Controller\EntityAutocompleteController::handleAutocomplete'
+    host_entity_id: ''
   requirements:
     _access: 'TRUE'
 
diff --git a/core/modules/system/tests/src/Kernel/Entity/EntityReferenceSelectionReferenceableTest.php b/core/modules/system/tests/src/Kernel/Entity/EntityReferenceSelectionReferenceableTest.php
index f7fa5d8..fc0b5f6 100644
--- a/core/modules/system/tests/src/Kernel/Entity/EntityReferenceSelectionReferenceableTest.php
+++ b/core/modules/system/tests/src/Kernel/Entity/EntityReferenceSelectionReferenceableTest.php
@@ -4,6 +4,7 @@
 
 use Drupal\Component\Utility\Html;
 use Drupal\Component\Utility\Unicode;
+use Drupal\entity_test\Entity\EntityTest;
 use Drupal\field\Tests\EntityReference\EntityReferenceTestTrait;
 use Drupal\field\Entity\FieldConfig;
 use Drupal\node\Entity\NodeType;
@@ -50,6 +51,7 @@ class EntityReferenceSelectionReferenceableTest extends KernelTestBase {
   protected function setUp() {
     parent::setUp();
 
+    $this->installEntitySchema('entity_test');
     $this->installEntitySchema('entity_test_no_label');
 
     /** @var \Drupal\Core\Entity\EntityStorageInterface $storage */
@@ -83,6 +85,32 @@ protected function setUp() {
   }
 
   /**
+   * Tests the 'allow_self_reference' selection handler setting.
+   */
+  public function testAllowSelfReference() {
+    $field_name = 'field_test';
+    $this->createEntityReferenceField('entity_test', 'entity_test', $field_name, 'Test entity reference', 'entity_test');
+
+    // Create a test entity and check that it cannot reference itself.
+    $host_entity = EntityTest::create(['name' => $this->randomMachineName()]);
+    $host_entity->save();
+
+    $field_config = FieldConfig::loadByName('entity_test', 'entity_test', $field_name);
+    $this->selectionHandler = $this->container->get('plugin.manager.entity_reference_selection')->getSelectionHandler($field_config, $host_entity);
+
+    $referenceables = $this->selectionHandler->getReferenceableEntities();
+    $this->assertTrue(isset($referenceables['entity_test'][$host_entity->id()]));
+
+    $selection_setttings = $field_config->getSetting('handler_settings');
+    $selection_setttings['allow_self_reference'] = FALSE;
+    $field_config->setSetting('handler_settings', $selection_setttings)->save();
+
+    $this->selectionHandler = $this->container->get('plugin.manager.entity_reference_selection')->getSelectionHandler($field_config, $host_entity);
+    $referenceables = $this->selectionHandler->getReferenceableEntities();
+    $this->assertTrue(!isset($referenceables['entity_test'][$host_entity->id()]));
+  }
+
+  /**
    * Tests values returned by SelectionInterface::getReferenceableEntities()
    * when the target entity type has no 'label' key.
    *
