From 6d3b05c2081a8466c92d8d31941f394139807631 Mon Sep 17 00:00:00 2001
From: Lee Rowlands <lee.rowlands@previousnext.com.au>
Date: Fri, 16 Aug 2019 17:56:19 +1000
Subject: [PATCH] Issue #3061610 by gabesullice, Wim Leers, tedbow, larowlan:
 Typed Data's EntityDeriver does not derive bundle-level data types when a
 bundle has the same name as its entity type (f.e. entity:comment:comment)

---
 .../Plugin/DataType/Deriver/EntityDeriver.php |  7 +-
 .../Core/Entity/EntityDeriverTest.php         | 95 +++++++++++++++++++
 .../Entity/EntityTypedDataDefinitionTest.php  |  1 +
 3 files changed, 100 insertions(+), 3 deletions(-)
 create mode 100644 core/tests/Drupal/KernelTests/Core/Entity/EntityDeriverTest.php

diff --git a/core/lib/Drupal/Core/Entity/Plugin/DataType/Deriver/EntityDeriver.php b/core/lib/Drupal/Core/Entity/Plugin/DataType/Deriver/EntityDeriver.php
index 3b2a52cd793a..8320bb4558c1 100644
--- a/core/lib/Drupal/Core/Entity/Plugin/DataType/Deriver/EntityDeriver.php
+++ b/core/lib/Drupal/Core/Entity/Plugin/DataType/Deriver/EntityDeriver.php
@@ -105,11 +105,12 @@ public function getDerivativeDefinitions($base_plugin_definition) {
       ] + $base_plugin_definition;
 
       // Incorporate the bundles as entity:$entity_type:$bundle, if any.
-      foreach ($this->bundleInfoService->getBundleInfo($entity_type_id) as $bundle => $bundle_info) {
-        if ($bundle !== $entity_type_id) {
+      $bundle_info = $this->bundleInfoService->getBundleInfo($entity_type_id);
+      if (count($bundle_info) > 1 || $entity_type->getKey('bundle')) {
+        foreach ($bundle_info as $bundle => $info) {
           $this->derivatives[$entity_type_id . ':' . $bundle] = [
             'class' => $class,
-            'label' => $bundle_info['label'],
+            'label' => $info['label'],
             'constraints' => $this->derivatives[$entity_type_id]['constraints'],
           ] + $base_plugin_definition;
         }
diff --git a/core/tests/Drupal/KernelTests/Core/Entity/EntityDeriverTest.php b/core/tests/Drupal/KernelTests/Core/Entity/EntityDeriverTest.php
new file mode 100644
index 000000000000..bbe8af0706b7
--- /dev/null
+++ b/core/tests/Drupal/KernelTests/Core/Entity/EntityDeriverTest.php
@@ -0,0 +1,95 @@
+<?php
+
+namespace Drupal\KernelTests\Core\Entity;
+
+use Drupal\comment\Entity\CommentType;
+use Drupal\Component\Plugin\Exception\PluginNotFoundException;
+use Drupal\KernelTests\KernelTestBase;
+use Drupal\node\Entity\NodeType;
+
+/**
+ * Tests EntityDeriver functionality.
+ *
+ * @coversDefaultClass \Drupal\Core\Entity\Plugin\DataType\Deriver\EntityDeriver
+ *
+ * @group Entity
+ */
+class EntityDeriverTest extends KernelTestBase {
+
+  /**
+   * The typed data manager to use.
+   *
+   * @var \Drupal\Core\TypedData\TypedDataManagerInterface
+   */
+  protected $typedDataManager;
+
+  /**
+   * {@inheritdoc}
+   */
+  public static $modules = [
+    'system',
+    'field',
+    'user',
+    'node',
+    'comment',
+    'entity_test',
+  ];
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp() {
+    parent::setup();
+
+    $this->installEntitySchema('comment');
+    NodeType::create(['type' => 'article', 'name' => 'Article'])->save();
+    CommentType::create([
+      'id' => 'comment',
+      'name' => 'Default comment',
+      'target_entity_type_id' => 'node',
+    ])->save();
+    entity_test_create_bundle('foo', NULL, 'entity_test_no_bundle');
+    entity_test_create_bundle('entity_test_no_bundle', NULL, 'entity_test_no_bundle');
+    $this->typedDataManager = $this->container->get('typed_data_manager');
+  }
+
+  /**
+   * Tests that types are derived for entity types with and without bundles.
+   *
+   * @dataProvider derivativesProvider
+   */
+  public function testDerivatives($data_type, $expect_exception) {
+    if ($expect_exception) {
+      $this->expectException(PluginNotFoundException::class);
+    }
+    $this->typedDataManager->createDataDefinition($data_type);
+  }
+
+  /**
+   * Provides test data for ::testDerivatives().
+   */
+  public function derivativesProvider() {
+    return [
+      'unbundleable entity type with no bundle type' => ['entity:user', FALSE],
+      'unbundleable entity type with bundle type' => ['entity:user:user', TRUE],
+      'bundleable entity type with no bundle type' => ['entity:node', FALSE],
+      'bundleable entity type with bundle type' => [
+        'entity:node:article',
+        FALSE,
+      ],
+      'bundleable entity type with bundle type with matching name' => [
+        'entity:comment:comment',
+        FALSE,
+      ],
+      'unbundleable entity type with entity_test_entity_bundle_info()-generated bundle type' => [
+        'entity:entity_test_no_bundle:foo',
+        FALSE,
+      ],
+      'unbundleable entity type with entity_test_entity_bundle_info()-generated bundle type with matching name' => [
+        'entity:entity_test_no_bundle:entity_test_no_bundle',
+        FALSE,
+      ],
+    ];
+  }
+
+}
diff --git a/core/tests/Drupal/KernelTests/Core/Entity/EntityTypedDataDefinitionTest.php b/core/tests/Drupal/KernelTests/Core/Entity/EntityTypedDataDefinitionTest.php
index b4d97bf910fd..dcfe664a6d5e 100644
--- a/core/tests/Drupal/KernelTests/Core/Entity/EntityTypedDataDefinitionTest.php
+++ b/core/tests/Drupal/KernelTests/Core/Entity/EntityTypedDataDefinitionTest.php
@@ -151,6 +151,7 @@ public function testEntityDefinitionIsInternal($internal, $expected) {
 
     $entity_type = $this->prophesize(EntityTypeInterface::class);
     $entity_type->entityClassImplements(ConfigEntityInterface::class)->willReturn(FALSE);
+    $entity_type->getKey('bundle')->willReturn(FALSE);
     $entity_type->getLabel()->willReturn($this->randomString());
     $entity_type->getConstraints()->willReturn([]);
     $entity_type->isInternal()->willReturn($internal);
-- 
GitLab