From c57b1901b839ee8160a0f43a56feaf728c4514d6 Mon Sep 17 00:00:00 2001
From: Lee Rowlands <lee.rowlands@previousnext.com.au>
Date: Fri, 16 Feb 2018 07:43:37 +1000
Subject: [PATCH] Issue #2942590 by tim.plunkett: Layout Builder defaults
 should work regardless of the ability to provide overrides

---
 .../layout_builder/layout_builder.module      |  6 --
 .../LayoutBuilderLocalTaskDeriver.php         | 23 ++++++--
 .../SectionStorage/DefaultsSectionStorage.php |  3 +-
 .../OverridesSectionStorage.php               |  4 +-
 .../src/Unit/DefaultsSectionStorageTest.php   | 57 ++++++++++++-------
 .../src/Unit/OverridesSectionStorageTest.php  | 45 ++++++++++-----
 6 files changed, 92 insertions(+), 46 deletions(-)

diff --git a/core/modules/layout_builder/layout_builder.module b/core/modules/layout_builder/layout_builder.module
index b1ecb5d594d0..2138a045f3f0 100644
--- a/core/modules/layout_builder/layout_builder.module
+++ b/core/modules/layout_builder/layout_builder.module
@@ -5,7 +5,6 @@
  * Provides hook implementations for Layout Builder.
  */
 
-use Drupal\Core\Entity\FieldableEntityInterface;
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Routing\RouteMatchInterface;
 use Drupal\Core\Url;
@@ -44,11 +43,6 @@ function layout_builder_help($route_name, RouteMatchInterface $route_match) {
  */
 function layout_builder_entity_type_alter(array &$entity_types) {
   /** @var \Drupal\Core\Entity\EntityTypeInterface[] $entity_types */
-  foreach ($entity_types as $entity_type) {
-    if ($entity_type->entityClassImplements(FieldableEntityInterface::class) && $entity_type->hasLinkTemplate('canonical') && $entity_type->hasViewBuilderClass()) {
-      $entity_type->setLinkTemplate('layout-builder', $entity_type->getLinkTemplate('canonical') . '/layout');
-    }
-  }
   $entity_types['entity_view_display']
     ->setClass(LayoutBuilderEntityViewDisplay::class)
     ->setStorageClass(LayoutBuilderEntityViewDisplayStorage::class)
diff --git a/core/modules/layout_builder/src/Plugin/Derivative/LayoutBuilderLocalTaskDeriver.php b/core/modules/layout_builder/src/Plugin/Derivative/LayoutBuilderLocalTaskDeriver.php
index c2046c0fd407..e2053f342eeb 100644
--- a/core/modules/layout_builder/src/Plugin/Derivative/LayoutBuilderLocalTaskDeriver.php
+++ b/core/modules/layout_builder/src/Plugin/Derivative/LayoutBuilderLocalTaskDeriver.php
@@ -5,6 +5,7 @@
 use Drupal\Component\Plugin\Derivative\DeriverBase;
 use Drupal\Core\Entity\EntityTypeInterface;
 use Drupal\Core\Entity\EntityTypeManagerInterface;
+use Drupal\Core\Entity\FieldableEntityInterface;
 use Drupal\Core\Plugin\Discovery\ContainerDeriverInterface;
 use Drupal\Core\StringTranslation\StringTranslationTrait;
 use Symfony\Component\DependencyInjection\ContainerInterface;
@@ -50,7 +51,7 @@ public static function create(ContainerInterface $container, $base_plugin_id) {
    * {@inheritdoc}
    */
   public function getDerivativeDefinitions($base_plugin_definition) {
-    foreach ($this->getEntityTypes() as $entity_type_id => $entity_type) {
+    foreach ($this->getEntityTypesForOverrides() as $entity_type_id => $entity_type) {
       // Overrides.
       $this->derivatives["layout_builder.overrides.$entity_type_id.view"] = $base_plugin_definition + [
         'route_name' => "layout_builder.overrides.$entity_type_id.view",
@@ -81,7 +82,9 @@ public function getDerivativeDefinitions($base_plugin_definition) {
         'weight' => 10,
         'cache_contexts' => ['layout_builder_is_active:' . $entity_type_id],
       ];
+    }
 
+    foreach ($this->getEntityTypesForDefaults() as $entity_type_id => $entity_type) {
       // Defaults.
       $this->derivatives["layout_builder.defaults.$entity_type_id.view"] = $base_plugin_definition + [
         'route_name' => "layout_builder.defaults.$entity_type_id.view",
@@ -105,14 +108,26 @@ public function getDerivativeDefinitions($base_plugin_definition) {
   }
 
   /**
-   * Returns an array of relevant entity types.
+   * Returns an array of entity types relevant for defaults.
+   *
+   * @return \Drupal\Core\Entity\EntityTypeInterface[]
+   *   An array of entity types.
+   */
+  protected function getEntityTypesForDefaults() {
+    return array_filter($this->entityTypeManager->getDefinitions(), function (EntityTypeInterface $entity_type) {
+      return $entity_type->entityClassImplements(FieldableEntityInterface::class) && $entity_type->hasViewBuilderClass() && $entity_type->get('field_ui_base_route');
+    });
+  }
+
+  /**
+   * Returns an array of entity types relevant for overrides.
    *
    * @return \Drupal\Core\Entity\EntityTypeInterface[]
    *   An array of entity types.
    */
-  protected function getEntityTypes() {
+  protected function getEntityTypesForOverrides() {
     return array_filter($this->entityTypeManager->getDefinitions(), function (EntityTypeInterface $entity_type) {
-      return $entity_type->hasLinkTemplate('layout-builder');
+      return $entity_type->entityClassImplements(FieldableEntityInterface::class) && $entity_type->hasViewBuilderClass() && $entity_type->hasLinkTemplate('canonical');
     });
   }
 
diff --git a/core/modules/layout_builder/src/Plugin/SectionStorage/DefaultsSectionStorage.php b/core/modules/layout_builder/src/Plugin/SectionStorage/DefaultsSectionStorage.php
index a83ca049f54d..c6ca9c663093 100644
--- a/core/modules/layout_builder/src/Plugin/SectionStorage/DefaultsSectionStorage.php
+++ b/core/modules/layout_builder/src/Plugin/SectionStorage/DefaultsSectionStorage.php
@@ -6,6 +6,7 @@
 use Drupal\Core\Entity\EntityTypeBundleInfoInterface;
 use Drupal\Core\Entity\EntityTypeInterface;
 use Drupal\Core\Entity\EntityTypeManagerInterface;
+use Drupal\Core\Entity\FieldableEntityInterface;
 use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
 use Drupal\Core\Plugin\Context\Context;
 use Drupal\Core\Plugin\Context\ContextDefinition;
@@ -203,7 +204,7 @@ public function buildRoutes(RouteCollection $collection) {
    */
   protected function getEntityTypes() {
     return array_filter($this->entityTypeManager->getDefinitions(), function (EntityTypeInterface $entity_type) {
-      return $entity_type->hasLinkTemplate('layout-builder') && $entity_type->get('field_ui_base_route');
+      return $entity_type->entityClassImplements(FieldableEntityInterface::class) && $entity_type->hasViewBuilderClass() && $entity_type->get('field_ui_base_route');
     });
   }
 
diff --git a/core/modules/layout_builder/src/Plugin/SectionStorage/OverridesSectionStorage.php b/core/modules/layout_builder/src/Plugin/SectionStorage/OverridesSectionStorage.php
index 58adb5503d25..ef154f1b2b2e 100644
--- a/core/modules/layout_builder/src/Plugin/SectionStorage/OverridesSectionStorage.php
+++ b/core/modules/layout_builder/src/Plugin/SectionStorage/OverridesSectionStorage.php
@@ -152,7 +152,7 @@ public function buildRoutes(RouteCollection $collection) {
       $options['parameters']['section_storage'] = [];
       $options['parameters'][$entity_type_id]['type'] = 'entity:' . $entity_type_id;
 
-      $template = $entity_type->getLinkTemplate('layout-builder');
+      $template = $entity_type->getLinkTemplate('canonical') . '/layout';
       $this->buildLayoutRoutes($collection, $this->getPluginDefinition(), $template, $defaults, $requirements, $options, $entity_type_id);
     }
   }
@@ -179,7 +179,7 @@ protected function hasIntegerId(EntityTypeInterface $entity_type) {
    */
   protected function getEntityTypes() {
     return array_filter($this->entityTypeManager->getDefinitions(), function (EntityTypeInterface $entity_type) {
-      return $entity_type->hasLinkTemplate('layout-builder');
+      return $entity_type->entityClassImplements(FieldableEntityInterface::class) && $entity_type->hasViewBuilderClass() && $entity_type->hasLinkTemplate('canonical');
     });
   }
 
diff --git a/core/modules/layout_builder/tests/src/Unit/DefaultsSectionStorageTest.php b/core/modules/layout_builder/tests/src/Unit/DefaultsSectionStorageTest.php
index 1aa1c16cf4ab..995483fff9b6 100644
--- a/core/modules/layout_builder/tests/src/Unit/DefaultsSectionStorageTest.php
+++ b/core/modules/layout_builder/tests/src/Unit/DefaultsSectionStorageTest.php
@@ -5,7 +5,9 @@
 use Drupal\Core\Entity\EntityStorageInterface;
 use Drupal\Core\Entity\EntityType;
 use Drupal\Core\Entity\EntityTypeBundleInfoInterface;
+use Drupal\Core\Entity\EntityTypeInterface;
 use Drupal\Core\Entity\EntityTypeManagerInterface;
+use Drupal\Core\Entity\FieldableEntityInterface;
 use Drupal\layout_builder\Entity\LayoutBuilderSampleEntityGenerator;
 use Drupal\layout_builder\Plugin\SectionStorage\DefaultsSectionStorage;
 use Drupal\layout_builder\SectionStorage\SectionStorageDefinition;
@@ -173,26 +175,41 @@ public function testGetSectionListFromIdCreate() {
    */
   public function testBuildRoutes() {
     $entity_types = [];
-    $entity_types['no_link_template'] = new EntityType(['id' => 'no_link_template']);
-    $entity_types['unknown_field_ui_route'] = new EntityType([
-      'id' => 'unknown_field_ui_route',
-      'links' => ['layout-builder' => '/entity/{entity}/layout'],
-      'entity_keys' => ['id' => 'id'],
-      'field_ui_base_route' => 'unknown',
-    ]);
-    $entity_types['with_bundle_key'] = new EntityType([
-      'id' => 'with_bundle_key',
-      'links' => ['layout-builder' => '/entity/{entity}/layout'],
-      'entity_keys' => ['id' => 'id', 'bundle' => 'bundle'],
-      'bundle_entity_type' => 'my_bundle_type',
-      'field_ui_base_route' => 'known',
-    ]);
-    $entity_types['with_bundle_parameter'] = new EntityType([
-      'id' => 'with_bundle_parameter',
-      'links' => ['layout-builder' => '/entity/{entity}/layout'],
-      'entity_keys' => ['id' => 'id'],
-      'field_ui_base_route' => 'with_bundle',
-    ]);
+
+    $not_fieldable = $this->prophesize(EntityTypeInterface::class);
+    $not_fieldable->entityClassImplements(FieldableEntityInterface::class)->willReturn(FALSE);
+    $entity_types['not_fieldable'] = $not_fieldable->reveal();
+
+    $no_view_builder = $this->prophesize(EntityTypeInterface::class);
+    $no_view_builder->entityClassImplements(FieldableEntityInterface::class)->willReturn(TRUE);
+    $no_view_builder->hasViewBuilderClass()->willReturn(FALSE);
+    $entity_types['no_view_builder'] = $no_view_builder->reveal();
+
+    $no_field_ui_route = $this->prophesize(EntityTypeInterface::class);
+    $no_field_ui_route->entityClassImplements(FieldableEntityInterface::class)->willReturn(TRUE);
+    $no_field_ui_route->hasViewBuilderClass()->willReturn(TRUE);
+    $no_field_ui_route->get('field_ui_base_route')->willReturn(NULL);
+    $entity_types['no_field_ui_route'] = $no_field_ui_route->reveal();
+
+    $unknown_field_ui_route = $this->prophesize(EntityTypeInterface::class);
+    $unknown_field_ui_route->entityClassImplements(FieldableEntityInterface::class)->willReturn(TRUE);
+    $unknown_field_ui_route->hasViewBuilderClass()->willReturn(TRUE);
+    $unknown_field_ui_route->get('field_ui_base_route')->willReturn('unknown');
+    $entity_types['unknown_field_ui_route'] = $unknown_field_ui_route->reveal();
+
+    $with_bundle_key = $this->prophesize(EntityTypeInterface::class);
+    $with_bundle_key->entityClassImplements(FieldableEntityInterface::class)->willReturn(TRUE);
+    $with_bundle_key->hasViewBuilderClass()->willReturn(TRUE);
+    $with_bundle_key->get('field_ui_base_route')->willReturn('known');
+    $with_bundle_key->hasKey('bundle')->willReturn(TRUE);
+    $with_bundle_key->getBundleEntityType()->willReturn('my_bundle_type');
+    $entity_types['with_bundle_key'] = $with_bundle_key->reveal();
+
+    $with_bundle_parameter = $this->prophesize(EntityTypeInterface::class);
+    $with_bundle_parameter->entityClassImplements(FieldableEntityInterface::class)->willReturn(TRUE);
+    $with_bundle_parameter->hasViewBuilderClass()->willReturn(TRUE);
+    $with_bundle_parameter->get('field_ui_base_route')->willReturn('with_bundle');
+    $entity_types['with_bundle_parameter'] = $with_bundle_parameter->reveal();
     $this->entityTypeManager->getDefinitions()->willReturn($entity_types);
 
     $expected = [
diff --git a/core/modules/layout_builder/tests/src/Unit/OverridesSectionStorageTest.php b/core/modules/layout_builder/tests/src/Unit/OverridesSectionStorageTest.php
index 711ce5d40b47..bbeb049a6172 100644
--- a/core/modules/layout_builder/tests/src/Unit/OverridesSectionStorageTest.php
+++ b/core/modules/layout_builder/tests/src/Unit/OverridesSectionStorageTest.php
@@ -4,7 +4,7 @@
 
 use Drupal\Core\Entity\EntityFieldManagerInterface;
 use Drupal\Core\Entity\EntityStorageInterface;
-use Drupal\Core\Entity\EntityType;
+use Drupal\Core\Entity\EntityTypeInterface;
 use Drupal\Core\Entity\EntityTypeManagerInterface;
 use Drupal\Core\Entity\FieldableEntityInterface;
 use Drupal\Core\Field\FieldStorageDefinitionInterface;
@@ -168,23 +168,42 @@ public function providerTestGetSectionListFromId() {
   public function testBuildRoutes() {
     $entity_types = [];
 
-    $entity_types['no_link_template'] = new EntityType(['id' => 'no_link_template']);
-    $this->entityFieldManager->getFieldStorageDefinitions('no_link_template')->shouldNotBeCalled();
+    $not_fieldable = $this->prophesize(EntityTypeInterface::class);
+    $not_fieldable->entityClassImplements(FieldableEntityInterface::class)->willReturn(FALSE);
+    $entity_types['not_fieldable'] = $not_fieldable->reveal();
 
-    $entity_types['with_string_id'] = new EntityType([
-      'id' => 'with_string_id',
-      'links' => ['layout-builder' => '/entity/{entity}/layout'],
-      'entity_keys' => ['id' => 'id'],
-    ]);
+    $no_view_builder = $this->prophesize(EntityTypeInterface::class);
+    $no_view_builder->entityClassImplements(FieldableEntityInterface::class)->willReturn(TRUE);
+    $no_view_builder->hasViewBuilderClass()->willReturn(FALSE);
+    $entity_types['no_view_builder'] = $no_view_builder->reveal();
+
+    $no_canonical_link = $this->prophesize(EntityTypeInterface::class);
+    $no_canonical_link->entityClassImplements(FieldableEntityInterface::class)->willReturn(TRUE);
+    $no_canonical_link->hasViewBuilderClass()->willReturn(TRUE);
+    $no_canonical_link->hasLinkTemplate('canonical')->willReturn(FALSE);
+    $entity_types['no_canonical_link'] = $no_canonical_link->reveal();
+    $this->entityFieldManager->getFieldStorageDefinitions('no_canonical_link')->shouldNotBeCalled();
+
+    $with_string_id = $this->prophesize(EntityTypeInterface::class);
+    $with_string_id->entityClassImplements(FieldableEntityInterface::class)->willReturn(TRUE);
+    $with_string_id->hasViewBuilderClass()->willReturn(TRUE);
+    $with_string_id->hasLinkTemplate('canonical')->willReturn(TRUE);
+    $with_string_id->getLinkTemplate('canonical')->willReturn('/entity/{entity}');
+    $with_string_id->id()->willReturn('with_string_id');
+    $with_string_id->getKey('id')->willReturn('id');
+    $entity_types['with_string_id'] = $with_string_id->reveal();
     $string_id = $this->prophesize(FieldStorageDefinitionInterface::class);
     $string_id->getType()->willReturn('string');
     $this->entityFieldManager->getFieldStorageDefinitions('with_string_id')->willReturn(['id' => $string_id->reveal()]);
 
-    $entity_types['with_integer_id'] = new EntityType([
-      'id' => 'with_integer_id',
-      'links' => ['layout-builder' => '/entity/{entity}/layout'],
-      'entity_keys' => ['id' => 'id'],
-    ]);
+    $with_integer_id = $this->prophesize(EntityTypeInterface::class);
+    $with_integer_id->entityClassImplements(FieldableEntityInterface::class)->willReturn(TRUE);
+    $with_integer_id->hasViewBuilderClass()->willReturn(TRUE);
+    $with_integer_id->hasLinkTemplate('canonical')->willReturn(TRUE);
+    $with_integer_id->getLinkTemplate('canonical')->willReturn('/entity/{entity}');
+    $with_integer_id->id()->willReturn('with_integer_id');
+    $with_integer_id->getKey('id')->willReturn('id');
+    $entity_types['with_integer_id'] = $with_integer_id->reveal();
     $integer_id = $this->prophesize(FieldStorageDefinitionInterface::class);
     $integer_id->getType()->willReturn('integer');
     $this->entityFieldManager->getFieldStorageDefinitions('with_integer_id')->willReturn(['id' => $integer_id->reveal()]);
-- 
GitLab