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