diff --git a/core/modules/layout_builder/src/Entity/LayoutBuilderEntityViewDisplay.php b/core/modules/layout_builder/src/Entity/LayoutBuilderEntityViewDisplay.php index 713ed9417f..96e2e055bf 100644 --- a/core/modules/layout_builder/src/Entity/LayoutBuilderEntityViewDisplay.php +++ b/core/modules/layout_builder/src/Entity/LayoutBuilderEntityViewDisplay.php @@ -10,6 +10,7 @@ use Drupal\Core\Plugin\Context\Context; use Drupal\Core\Plugin\Context\ContextDefinition; use Drupal\Core\Plugin\Context\EntityContext; +use Drupal\Core\Render\Element; use Drupal\Core\StringTranslation\TranslatableMarkup; use Drupal\field\Entity\FieldConfig; use Drupal\field\Entity\FieldStorageConfig; @@ -242,40 +243,57 @@ public function buildMultiple(array $entities) { return $build_list; } - /** @var \Drupal\Core\Entity\EntityInterface $entity */ foreach ($entities as $id => $entity) { - $build_list[$id]['_layout_builder'] = []; + $build_list[$id]['_layout_builder'] = $this->buildSections($entity); - $cacheability = new CacheableMetadata(); - $contexts = []; - $sections = $this->getRuntimeSections($entity, $cacheability, $contexts); - // The render array is built based on decisions made by @SectionStorage - // plugins and therefore it needs to depend on the accumulated - // cacheability of those decisions. - $cacheability->applyTo($build_list[$id]['_layout_builder']); - if ($sections) { + // If there are any sections, remove all display configurable fields from + // the existing build. + if (!Element::isEmpty($build_list[$id]['_layout_builder'])) { foreach ($build_list[$id] as $name => $build_part) { $field_definition = $this->getFieldDefinition($name); if ($field_definition && $field_definition->isDisplayConfigurable($this->displayContext)) { unset($build_list[$id][$name]); } } - - // @todo Remove in https://www.drupal.org/project/drupal/issues/3018782. - $label = new TranslatableMarkup('@entity being viewed', [ - '@entity' => $entity->getEntityType()->getSingularLabel(), - ]); - $contexts['layout_builder.entity'] = EntityContext::fromEntity($entity, $label); - - foreach ($sections as $delta => $section) { - $build_list[$id]['_layout_builder'][$delta] = $section->toRenderArray($contexts); - } } } return $build_list; } + /** + * Builds the render array for the sections of a given entity. + * + * @param \Drupal\Core\Entity\FieldableEntityInterface $entity + * The entity. + * + * @return array + * The render array representing the sections of the entity. + */ + private function buildSections(FieldableEntityInterface $entity) { + $contexts = $this->getContextsForEntity($entity); + // @todo Remove in https://www.drupal.org/project/drupal/issues/3018782. + $label = new TranslatableMarkup('@entity being viewed', [ + '@entity' => $entity->getEntityType()->getSingularLabel(), + ]); + $contexts['layout_builder.entity'] = EntityContext::fromEntity($entity, $label); + + $cacheability = new CacheableMetadata(); + $storage = $this->sectionStorageManager()->findByContext($contexts, $cacheability); + + $build = []; + if ($storage) { + foreach ($storage->getSections() as $delta => $section) { + $build[$delta] = $section->toRenderArray($contexts); + } + } + // The render array is built based on decisions made by @SectionStorage + // plugins and therefore it needs to depend on the accumulated + // cacheability of those decisions. + $cacheability->applyTo($build); + return $build; + } + /** * Gets the available contexts for a given entity. * @@ -308,9 +326,15 @@ protected function getContextsForEntity(FieldableEntityInterface $entity) { * @return \Drupal\layout_builder\Section[] * The sections. * - * @todo Deprecate this method in https://www.drupal.org/node/2986403. + * @deprecated in Drupal 8.7.0 and will be removed before Drupal 9.0.0. + * \Drupal\layout_builder\SectionStorage\SectionStorageManagerInterface::findByContext() + * should be used instead. See https://www.drupal.org/node/3022574. */ protected function getRuntimeSections(FieldableEntityInterface $entity, RefinableCacheableDependencyInterface &$cacheability = NULL, array &$contexts = []) { + @trigger_error('\Drupal\layout_builder\Entity\LayoutBuilderEntityViewDisplay::getRuntimeSections() is deprecated in Drupal 8.7.0 and will be removed before Drupal 9.0.0. \Drupal\layout_builder\SectionStorage\SectionStorageManagerInterface::findByContext() should be used instead. See https://www.drupal.org/node/3022574.', E_USER_DEPRECATED); + // For backwards compatibility mirror the functionality of ::buildSections() + // by constructing a cacheable metadata object and retrieving the + // entity-based contexts. if (!$cacheability) { $cacheability = new CacheableMetadata(); } diff --git a/core/modules/layout_builder/tests/src/Kernel/LayoutBuilderEntityViewDisplayTest.php b/core/modules/layout_builder/tests/src/Kernel/LayoutBuilderEntityViewDisplayTest.php index a554fb526f..7242839dda 100644 --- a/core/modules/layout_builder/tests/src/Kernel/LayoutBuilderEntityViewDisplayTest.php +++ b/core/modules/layout_builder/tests/src/Kernel/LayoutBuilderEntityViewDisplayTest.php @@ -2,7 +2,9 @@ namespace Drupal\Tests\layout_builder\Kernel; +use Drupal\Core\Cache\RefinableCacheableDependencyInterface; use Drupal\Core\Config\Schema\SchemaIncompleteException; +use Drupal\entity_test\Entity\EntityTest; use Drupal\layout_builder\Entity\LayoutBuilderEntityViewDisplay; /** @@ -40,4 +42,40 @@ public function testInvalidConfiguration() { $this->sectionStorage->save(); } + /** + * @covers ::getRuntimeSections + * @group legacy + * @expectedDeprecation \Drupal\layout_builder\Entity\LayoutBuilderEntityViewDisplay::getRuntimeSections() is deprecated in Drupal 8.7.0 and will be removed before Drupal 9.0.0. \Drupal\layout_builder\SectionStorage\SectionStorageManagerInterface::findByContext() should be used instead. See https://www.drupal.org/node/3022574. + */ + public function testGetRuntimeSections() { + $this->container->get('current_user')->setAccount($this->createUser()); + + $entity = EntityTest::create(); + $entity->save(); + \Drupal::setContainer($this->container); + + $reflection = new \ReflectionMethod($this->sectionStorage, 'getRuntimeSections'); + $reflection->setAccessible(TRUE); + + $cacheability = NULL; + $contexts = []; + $args = [$entity, &$cacheability, &$contexts]; + $result = $reflection->invokeArgs($this->sectionStorage, $args); + + $this->assertInstanceOf(RefinableCacheableDependencyInterface::class, $cacheability); + $this->assertSame([], $cacheability->getCacheContexts()); + $this->assertSame([], $cacheability->getCacheTags()); + $this->assertSame(-1, $cacheability->getCacheMaxAge()); + $expected_contexts = [ + 'view_mode' => $this->sectionStorage->getMode(), + 'entity' => $entity, + 'display' => $this->sectionStorage, + ]; + foreach ($expected_contexts as $key => $expected_context) { + $this->assertArrayHasKey($key, $contexts); + $this->assertEquals($expected_context, $contexts[$key]->getContextValue()); + } + $this->assertEquals($this->sectionStorage->getSections(), $result); + } + }