diff --git a/core/modules/layout_builder/src/Entity/LayoutBuilderEntityViewDisplay.php b/core/modules/layout_builder/src/Entity/LayoutBuilderEntityViewDisplay.php index 11d089291c..813b64c8e0 100644 --- a/core/modules/layout_builder/src/Entity/LayoutBuilderEntityViewDisplay.php +++ b/core/modules/layout_builder/src/Entity/LayoutBuilderEntityViewDisplay.php @@ -392,6 +392,25 @@ protected function getRouteParameters() { return $route_parameters; } + /** + * {@inheritdoc} + */ + public function onDependencyRemoval(array $dependencies) { + $return = parent::onDependencyRemoval($dependencies); + foreach ($dependencies['config'] as $field_config) { + $id = 'field_block:' . $this->getTargetEntityTypeId() . ':' . $field_config->getName(); + foreach ($this->getSections() as $delta => $section) { + foreach ($section->getComponents() as $uuid => $component) { + if ($component->getPluginId() === $id) { + $section->removeComponent($uuid); + $return = TRUE; + } + } + } + } + return $return; + } + /** * {@inheritdoc} */ diff --git a/core/modules/layout_builder/src/Routing/LayoutBuilderRoutes.php b/core/modules/layout_builder/src/Routing/LayoutBuilderRoutes.php index ace3f93ca6..735538ccf7 100644 --- a/core/modules/layout_builder/src/Routing/LayoutBuilderRoutes.php +++ b/core/modules/layout_builder/src/Routing/LayoutBuilderRoutes.php @@ -2,6 +2,7 @@ namespace Drupal\layout_builder\Routing; +use Drupal\Component\Utility\NestedArray; use Drupal\Core\Entity\EntityFieldManagerInterface; use Drupal\Core\Entity\EntityTypeInterface; use Drupal\Core\Entity\EntityTypeManagerInterface; @@ -107,9 +108,10 @@ public function onAlterRoutes(RouteBuildEvent $event) { $requirements = []; $requirements['_field_ui_view_mode_access'] = 'administer ' . $entity_type_id . ' display'; - $options = $entity_route->getOptions(); $options['parameters']['section_storage']['layout_builder_tempstore'] = TRUE; $options['_admin_route'] = FALSE; + // Merge the entity route options in after Layout Builder's. + $options = NestedArray::mergeDeep($options, $entity_route->getOptions()); $routes = $this->buildRoute(LayoutBuilderEntityViewDisplay::class, 'entity.entity_view_display.' . $entity_type_id, $path, $defaults, $requirements, $options); foreach ($routes as $name => $route) { diff --git a/core/modules/layout_builder/src/Routing/SectionStorageDefaultsParamConverter.php b/core/modules/layout_builder/src/Routing/SectionStorageDefaultsParamConverter.php index c6435786bd..2f886102c3 100644 --- a/core/modules/layout_builder/src/Routing/SectionStorageDefaultsParamConverter.php +++ b/core/modules/layout_builder/src/Routing/SectionStorageDefaultsParamConverter.php @@ -31,7 +31,16 @@ public function convert($value, $definition, $name, array $defaults) { $value = $defaults['entity_type_id'] . '.' . $defaults['bundle'] . '.' . $defaults['view_mode_name']; } - return parent::convert($value, $definition, $name, $defaults); + if (!$display = parent::convert($value, $definition, $name, $defaults)) { + list($entity_type_id, $bundle, $view_mode) = explode('.', $value); + $display = $this->entityManager->getStorage('entity_view_display')->create([ + 'targetEntityType' => $entity_type_id, + 'bundle' => $bundle, + 'mode' => $view_mode, + 'status' => TRUE, + ]); + } + return $display; } /** diff --git a/core/modules/layout_builder/src/SectionComponent.php b/core/modules/layout_builder/src/SectionComponent.php index 1f31738d65..c7b46ef1c9 100644 --- a/core/modules/layout_builder/src/SectionComponent.php +++ b/core/modules/layout_builder/src/SectionComponent.php @@ -242,7 +242,7 @@ public function setConfiguration(array $configuration) { * @throws \Drupal\Component\Plugin\Exception\PluginException * Thrown if the plugin ID cannot be found. */ - protected function getPluginId() { + public function getPluginId() { if (empty($this->configuration['id'])) { throw new PluginException(sprintf('No plugin ID specified for component with "%s" UUID', $this->uuid)); } diff --git a/core/modules/layout_builder/tests/src/Functional/LayoutSectionTest.php b/core/modules/layout_builder/tests/src/Functional/LayoutSectionTest.php index 99ce2be7df..67e8a06e3f 100644 --- a/core/modules/layout_builder/tests/src/Functional/LayoutSectionTest.php +++ b/core/modules/layout_builder/tests/src/Functional/LayoutSectionTest.php @@ -18,7 +18,7 @@ class LayoutSectionTest extends BrowserTestBase { /** * {@inheritdoc} */ - public static $modules = ['layout_builder', 'node', 'block_test']; + public static $modules = ['field_ui', 'layout_builder', 'node', 'block_test']; /** * The name of the layout section field. @@ -46,6 +46,8 @@ protected function setUp() { $this->drupalLogin($this->drupalCreateUser([ 'configure any layout', + 'administer node display', + 'administer node fields', ], 'foobar')); } @@ -275,6 +277,27 @@ public function testLayoutUrlNoSectionField() { $this->assertSession()->statusCodeEquals(404); } + /** + * Tests that deleting a field removes it from the layout. + */ + public function testLayoutDeletingField() { + LayoutBuilderEntityViewDisplay::load('node.bundle_with_section_field.default') + ->setComponent('body', ['type' => 'text_default', 'region' => 'content']) + ->save(); + + $this->drupalGet('/admin/structure/types/manage/bundle_with_section_field/display-layout/default'); + $this->assertSession()->statusCodeEquals(200); + + // Delete the field from both bundles. + $this->drupalGet('/admin/structure/types/manage/bundle_with_section_field/fields/node.bundle_with_section_field.body/delete'); + $this->submitForm([], 'Delete'); + $this->drupalGet('/admin/structure/types/manage/bundle_without_section_field/fields/node.bundle_without_section_field.body/delete'); + $this->submitForm([], 'Delete'); + + $this->drupalGet('/admin/structure/types/manage/bundle_with_section_field/display-layout/default'); + $this->assertSession()->statusCodeEquals(200); + } + /** * Asserts the output of a layout section. * diff --git a/core/modules/layout_builder/tests/src/Unit/SectionStorageDefaultsParamConverterTest.php b/core/modules/layout_builder/tests/src/Unit/SectionStorageDefaultsParamConverterTest.php index df07c86cc6..8afde9a055 100644 --- a/core/modules/layout_builder/tests/src/Unit/SectionStorageDefaultsParamConverterTest.php +++ b/core/modules/layout_builder/tests/src/Unit/SectionStorageDefaultsParamConverterTest.php @@ -108,4 +108,27 @@ public function providerTestConvert() { return $data; } + /** + * @covers ::convert + */ + public function testConvertCreate() { + $expected = 'the_return_value'; + $value = 'foo.bar.baz'; + $expected_create_values = [ + 'targetEntityType' => 'foo', + 'bundle' => 'bar', + 'mode' => 'baz', + 'status' => TRUE, + ]; + $entity_storage = $this->prophesize(EntityStorageInterface::class); + $entity_storage->load($value)->willReturn(NULL); + $entity_storage->create($expected_create_values)->willReturn($expected); + + $this->entityManager->getDefinition('entity_view_display')->willReturn(new EntityType(['id' => 'entity_view_display'])); + $this->entityManager->getStorage('entity_view_display')->willReturn($entity_storage->reveal()); + + $result = $this->converter->convert($value, [], 'the_parameter_name', []); + $this->assertSame($expected, $result); + } + }