From 5e7fb73422f538b9429acd4a87db0bc5fd995808 Mon Sep 17 00:00:00 2001 From: Alex Pott <alex.a.pott@googlemail.com> Date: Fri, 5 Feb 2021 12:38:50 +0000 Subject: [PATCH] Issue #3115503 by clayfreeman, tim.plunkett, alexpott, andypost: Support context aware layout plugins --- core/config/schema/core.data_types.schema.yml | 5 ++ core/lib/Drupal/Core/Layout/LayoutDefault.php | 7 +++ .../Drupal/Core/Layout/LayoutDefinition.php | 15 +++++- .../Drupal/Core/Layout/LayoutInterface.php | 3 +- .../layout_builder.post_update.php | 33 ++++++++++++ .../Controller/ChooseSectionController.php | 4 +- .../src/Element/LayoutBuilder.php | 2 +- .../src/Form/ConfigureSectionForm.php | 12 +++++ .../layout_builder/src/Form/MoveBlockForm.php | 5 +- core/modules/layout_builder/src/Section.php | 23 ++++++-- .../update/layout-builder-context-mapping.php | 34 ++++++++++++ .../tests/fixtures/update/layout-builder.php | 54 +++++++++++++++++++ .../Plugin/Layout/TestContextAwareLayout.php | 32 +++++++++++ .../src/Functional/LayoutBuilderTest.php | 33 ++++++++++++ ...outBuilderContextMappingUpdatePathTest.php | 43 +++++++++++++++ .../tests/src/Unit/SectionTest.php | 40 ++++++++++++++ 16 files changed, 337 insertions(+), 8 deletions(-) create mode 100644 core/modules/layout_builder/tests/fixtures/update/layout-builder-context-mapping.php create mode 100644 core/modules/layout_builder/tests/fixtures/update/layout-builder.php create mode 100644 core/modules/layout_builder/tests/modules/layout_builder_test/src/Plugin/Layout/TestContextAwareLayout.php create mode 100644 core/modules/layout_builder/tests/src/Functional/Update/LayoutBuilderContextMappingUpdatePathTest.php diff --git a/core/config/schema/core.data_types.schema.yml b/core/config/schema/core.data_types.schema.yml index be92cd96bb99..f44ebc46850f 100644 --- a/core/config/schema/core.data_types.schema.yml +++ b/core/config/schema/core.data_types.schema.yml @@ -362,6 +362,11 @@ layout_plugin.settings: label: type: label label: 'Label' + context_mapping: + type: sequence + label: 'Context assignments' + sequence: + type: string layout_plugin.settings.*: type: layout_plugin.settings diff --git a/core/lib/Drupal/Core/Layout/LayoutDefault.php b/core/lib/Drupal/Core/Layout/LayoutDefault.php index 175844fe1e33..afeedb85d272 100644 --- a/core/lib/Drupal/Core/Layout/LayoutDefault.php +++ b/core/lib/Drupal/Core/Layout/LayoutDefault.php @@ -4,6 +4,8 @@ use Drupal\Component\Utility\NestedArray; use Drupal\Core\Form\FormStateInterface; +use Drupal\Core\Plugin\ContextAwarePluginAssignmentTrait; +use Drupal\Core\Plugin\ContextAwarePluginTrait; use Drupal\Core\Plugin\PluginBase; use Drupal\Core\Plugin\PluginFormInterface; @@ -12,6 +14,9 @@ */ class LayoutDefault extends PluginBase implements LayoutInterface, PluginFormInterface { + use ContextAwarePluginAssignmentTrait; + use ContextAwarePluginTrait; + /** * The layout definition. * @@ -95,6 +100,8 @@ public function buildConfigurationForm(array $form, FormStateInterface $form_sta '#title' => $this->t('Administrative label'), '#default_value' => $this->configuration['label'], ]; + $contexts = $form_state->getTemporaryValue('gathered_contexts') ?: []; + $form['context_mapping'] = $this->addContextAssignmentElement($this, $contexts); return $form; } diff --git a/core/lib/Drupal/Core/Layout/LayoutDefinition.php b/core/lib/Drupal/Core/Layout/LayoutDefinition.php index c87b618d113f..033175188a69 100644 --- a/core/lib/Drupal/Core/Layout/LayoutDefinition.php +++ b/core/lib/Drupal/Core/Layout/LayoutDefinition.php @@ -2,6 +2,8 @@ namespace Drupal\Core\Layout; +use Drupal\Component\Plugin\Definition\ContextAwarePluginDefinitionInterface; +use Drupal\Component\Plugin\Definition\ContextAwarePluginDefinitionTrait; use Drupal\Component\Plugin\Definition\DerivablePluginDefinitionInterface; use Drupal\Component\Plugin\Definition\PluginDefinitionInterface; use Drupal\Component\Plugin\Definition\PluginDefinition; @@ -11,8 +13,9 @@ /** * Provides an implementation of a layout definition and its metadata. */ -class LayoutDefinition extends PluginDefinition implements PluginDefinitionInterface, DerivablePluginDefinitionInterface, DependentPluginDefinitionInterface { +class LayoutDefinition extends PluginDefinition implements PluginDefinitionInterface, DerivablePluginDefinitionInterface, DependentPluginDefinitionInterface, ContextAwarePluginDefinitionInterface { + use ContextAwarePluginDefinitionTrait; use DependentPluginDefinitionTrait; /** @@ -129,6 +132,16 @@ class LayoutDefinition extends PluginDefinition implements PluginDefinitionInter * An array of values from the annotation. */ public function __construct(array $definition) { + // If there are context definitions in the plugin definition, they should + // be added to this object using ::addContextDefinition() so that they can + // be manipulated using other ContextAwarePluginDefinitionInterface methods. + if (isset($definition['context_definitions'])) { + foreach ($definition['context_definitions'] as $name => $context_definition) { + $this->addContextDefinition($name, $context_definition); + } + unset($definition['context_definitions']); + } + foreach ($definition as $property => $value) { $this->set($property, $value); } diff --git a/core/lib/Drupal/Core/Layout/LayoutInterface.php b/core/lib/Drupal/Core/Layout/LayoutInterface.php index 400a0d9af41f..33858a546d7f 100644 --- a/core/lib/Drupal/Core/Layout/LayoutInterface.php +++ b/core/lib/Drupal/Core/Layout/LayoutInterface.php @@ -6,11 +6,12 @@ use Drupal\Component\Plugin\PluginInspectionInterface; use Drupal\Component\Plugin\ConfigurableInterface; use Drupal\Component\Plugin\DependentPluginInterface; +use Drupal\Core\Plugin\ContextAwarePluginInterface; /** * Provides an interface for static Layout plugins. */ -interface LayoutInterface extends PluginInspectionInterface, DerivativeInspectionInterface, ConfigurableInterface, DependentPluginInterface { +interface LayoutInterface extends PluginInspectionInterface, DerivativeInspectionInterface, ConfigurableInterface, DependentPluginInterface, ContextAwarePluginInterface { /** * Build a render array for layout with regions. diff --git a/core/modules/layout_builder/layout_builder.post_update.php b/core/modules/layout_builder/layout_builder.post_update.php index 47d94aa52cbd..e40adb734298 100644 --- a/core/modules/layout_builder/layout_builder.post_update.php +++ b/core/modules/layout_builder/layout_builder.post_update.php @@ -5,6 +5,11 @@ * Post update functions for Layout Builder. */ +use Drupal\Core\Config\Entity\ConfigEntityUpdater; +use Drupal\Core\Entity\Display\EntityViewDisplayInterface; + +use Drupal\layout_builder\Entity\LayoutEntityDisplayInterface; + /** * Implements hook_removed_post_updates(). */ @@ -34,3 +39,31 @@ function layout_builder_removed_post_updates() { function layout_builder_post_update_override_entity_form_controller() { // Empty post-update hook. } + +/** + * Update view displays that use Layout Builder to add empty context mappings. + */ +function layout_builder_post_update_section_storage_context_mapping(&$sandbox = []) { + $config_entity_updater = \Drupal::classResolver(ConfigEntityUpdater::class); + + $callback = function (EntityViewDisplayInterface $display) { + $needs_update = FALSE; + + // Only update entity view displays where Layout Builder is enabled. + if ($display instanceof LayoutEntityDisplayInterface && $display->isLayoutBuilderEnabled()) { + foreach ($display->getSections() as $section) { + // Add an empty context mapping to each section where one doesn't exist. + $section->setLayoutSettings($section->getLayoutSettings() + [ + 'context_mapping' => [], + ]); + + // Flag this display as needing to be updated. + $needs_update = TRUE; + } + } + + return $needs_update; + }; + + $config_entity_updater->update($sandbox, 'entity_view_display', $callback); +} diff --git a/core/modules/layout_builder/src/Controller/ChooseSectionController.php b/core/modules/layout_builder/src/Controller/ChooseSectionController.php index 1eee96b1aa5d..7edcf0768c38 100644 --- a/core/modules/layout_builder/src/Controller/ChooseSectionController.php +++ b/core/modules/layout_builder/src/Controller/ChooseSectionController.php @@ -8,6 +8,7 @@ use Drupal\Core\Plugin\PluginFormInterface; use Drupal\Core\StringTranslation\StringTranslationTrait; use Drupal\Core\Url; +use Drupal\layout_builder\Context\LayoutBuilderContextTrait; use Drupal\layout_builder\LayoutBuilderHighlightTrait; use Drupal\layout_builder\SectionStorageInterface; use Symfony\Component\DependencyInjection\ContainerInterface; @@ -21,6 +22,7 @@ class ChooseSectionController implements ContainerInjectionInterface { use AjaxHelperTrait; + use LayoutBuilderContextTrait; use LayoutBuilderHighlightTrait; use StringTranslationTrait; @@ -63,7 +65,7 @@ public static function create(ContainerInterface $container) { */ public function build(SectionStorageInterface $section_storage, int $delta) { $items = []; - $definitions = $this->layoutManager->getFilteredDefinitions('layout_builder', [], ['section_storage' => $section_storage]); + $definitions = $this->layoutManager->getFilteredDefinitions('layout_builder', $this->getAvailableContexts($section_storage), ['section_storage' => $section_storage]); foreach ($definitions as $plugin_id => $definition) { $layout = $this->layoutManager->createInstance($plugin_id); $item = [ diff --git a/core/modules/layout_builder/src/Element/LayoutBuilder.php b/core/modules/layout_builder/src/Element/LayoutBuilder.php index 0814604bbcf7..e218e4e1cab2 100644 --- a/core/modules/layout_builder/src/Element/LayoutBuilder.php +++ b/core/modules/layout_builder/src/Element/LayoutBuilder.php @@ -233,7 +233,7 @@ protected function buildAdministrativeSection(SectionStorageInterface $section_s $storage_id = $section_storage->getStorageId(); $section = $section_storage->getSection($delta); - $layout = $section->getLayout(); + $layout = $section->getLayout($this->getAvailableContexts($section_storage)); $layout_settings = $section->getLayoutSettings(); $section_label = !empty($layout_settings['label']) ? $layout_settings['label'] : $this->t('Section @section', ['@section' => $delta + 1]); diff --git a/core/modules/layout_builder/src/Form/ConfigureSectionForm.php b/core/modules/layout_builder/src/Form/ConfigureSectionForm.php index 313910482bdf..c690d5eccc0c 100644 --- a/core/modules/layout_builder/src/Form/ConfigureSectionForm.php +++ b/core/modules/layout_builder/src/Form/ConfigureSectionForm.php @@ -8,9 +8,11 @@ use Drupal\Core\Form\FormStateInterface; use Drupal\Core\Form\SubformState; use Drupal\Core\Layout\LayoutInterface; +use Drupal\Core\Plugin\ContextAwarePluginInterface; use Drupal\Core\Plugin\PluginFormFactoryInterface; use Drupal\Core\Plugin\PluginFormInterface; use Drupal\Core\Plugin\PluginWithFormsInterface; +use Drupal\layout_builder\Context\LayoutBuilderContextTrait; use Drupal\layout_builder\Controller\LayoutRebuildTrait; use Drupal\layout_builder\LayoutBuilderHighlightTrait; use Drupal\layout_builder\LayoutTempstoreRepositoryInterface; @@ -27,6 +29,7 @@ class ConfigureSectionForm extends FormBase { use AjaxFormHelperTrait; + use LayoutBuilderContextTrait; use LayoutBuilderHighlightTrait; use LayoutRebuildTrait; @@ -119,8 +122,12 @@ public function buildForm(array $form, FormStateInterface $form_state, SectionSt else { $section = new Section($plugin_id); } + // Passing available contexts to the layout plugin here could result in an + // exception since the layout may not have a context mapping for a required + // context slot on creation. $this->layout = $section->getLayout(); + $form_state->setTemporaryValue('gathered_contexts', $this->getAvailableContexts($this->sectionStorage)); $form['#tree'] = TRUE; $form['layout_settings'] = []; $subform_state = SubformState::createForSubform($form['layout_settings'], $form, $form_state); @@ -167,6 +174,11 @@ public function submitForm(array &$form, FormStateInterface $form_state) { $subform_state = SubformState::createForSubform($form['layout_settings'], $form, $form_state); $this->getPluginForm($this->layout)->submitConfigurationForm($form['layout_settings'], $subform_state); + // If this layout is context-aware, set the context mapping. + if ($this->layout instanceof ContextAwarePluginInterface) { + $this->layout->setContextMapping($subform_state->getValue('context_mapping', [])); + } + $plugin_id = $this->layout->getPluginId(); $configuration = $this->layout->getConfiguration(); diff --git a/core/modules/layout_builder/src/Form/MoveBlockForm.php b/core/modules/layout_builder/src/Form/MoveBlockForm.php index b3fd9dcbf80c..ef0568ead027 100644 --- a/core/modules/layout_builder/src/Form/MoveBlockForm.php +++ b/core/modules/layout_builder/src/Form/MoveBlockForm.php @@ -5,6 +5,7 @@ use Drupal\Core\Ajax\AjaxFormHelperTrait; use Drupal\Core\Form\FormBase; use Drupal\Core\Form\FormStateInterface; +use Drupal\layout_builder\Context\LayoutBuilderContextTrait; use Drupal\layout_builder\Controller\LayoutRebuildTrait; use Drupal\layout_builder\LayoutBuilderHighlightTrait; use Drupal\layout_builder\LayoutTempstoreRepositoryInterface; @@ -20,6 +21,7 @@ class MoveBlockForm extends FormBase { use AjaxFormHelperTrait; + use LayoutBuilderContextTrait; use LayoutBuilderHighlightTrait; use LayoutRebuildTrait; @@ -119,9 +121,10 @@ public function buildForm(array $form, FormStateInterface $form_state, SectionSt $form['#attributes']['data-layout-builder-target-highlight-id'] = $this->blockUpdateHighlightId($uuid); $sections = $section_storage->getSections(); + $contexts = $this->getAvailableContexts($section_storage); $region_options = []; foreach ($sections as $section_delta => $section) { - $layout = $section->getLayout(); + $layout = $section->getLayout($contexts); $layout_definition = $layout->getPluginDefinition(); if (!($section_label = $section->getLayoutSettings()['label'])) { $section_label = $this->t('Section: @delta', ['@delta' => $section_delta + 1])->render(); diff --git a/core/modules/layout_builder/src/Section.php b/core/modules/layout_builder/src/Section.php index 41fe13c57e67..cd27437cb2f6 100644 --- a/core/modules/layout_builder/src/Section.php +++ b/core/modules/layout_builder/src/Section.php @@ -88,17 +88,24 @@ public function toRenderArray(array $contexts = [], $in_preview = FALSE) { } } - return $this->getLayout()->build($regions); + return $this->getLayout($contexts)->build($regions); } /** * Gets the layout plugin for this section. * + * @param \Drupal\Core\Plugin\Context\ContextInterface[] $contexts + * An array of available contexts. + * * @return \Drupal\Core\Layout\LayoutInterface * The layout plugin. */ - public function getLayout() { - return $this->layoutPluginManager()->createInstance($this->getLayoutId(), $this->layoutSettings); + public function getLayout(array $contexts = []) { + $layout = $this->layoutPluginManager()->createInstance($this->getLayoutId(), $this->layoutSettings); + if ($contexts) { + $this->contextHandler()->applyContextMapping($layout, $contexts); + } + return $layout; } /** @@ -422,4 +429,14 @@ public function getThirdPartyProviders() { return array_keys($this->thirdPartySettings); } + /** + * Wraps the context handler. + * + * @return \Drupal\Core\Plugin\Context\ContextHandlerInterface + * The context handler. + */ + protected function contextHandler() { + return \Drupal::service('context.handler'); + } + } diff --git a/core/modules/layout_builder/tests/fixtures/update/layout-builder-context-mapping.php b/core/modules/layout_builder/tests/fixtures/update/layout-builder-context-mapping.php new file mode 100644 index 000000000000..355c7ce5448c --- /dev/null +++ b/core/modules/layout_builder/tests/fixtures/update/layout-builder-context-mapping.php @@ -0,0 +1,34 @@ +<?php + +/** + * @file + * Test context mapping update path by adding a layout without a context map. + */ + +use Drupal\Core\Database\Database; + +$connection = Database::getConnection(); + +// Add a layout plugin to an existing entity view display. +$display = $connection->select('config') + ->fields('config', ['data']) + ->condition('collection', '') + ->condition('name', 'core.entity_view_display.node.article.teaser') + ->execute() + ->fetchField(); +$display = unserialize($display); +$display['dependencies']['module'][] = 'layout_builder'; +$display['dependencies']['module'][] = 'layout_discovery'; +$display['third_party_settings']['layout_builder']['allow_custom'] = FALSE; +$display['third_party_settings']['layout_builder']['enabled'] = TRUE; +$display['third_party_settings']['layout_builder']['sections'][] = [ + 'layout_id' => 'layout_onecol', + 'layout_settings' => ['label' => ''], + 'components' => [], + 'third_party_settings' => [], +]; +$connection->update('config') + ->fields(['data' => serialize($display)]) + ->condition('collection', '') + ->condition('name', 'core.entity_view_display.node.article.teaser') + ->execute(); diff --git a/core/modules/layout_builder/tests/fixtures/update/layout-builder.php b/core/modules/layout_builder/tests/fixtures/update/layout-builder.php new file mode 100644 index 000000000000..90e6a36bc45a --- /dev/null +++ b/core/modules/layout_builder/tests/fixtures/update/layout-builder.php @@ -0,0 +1,54 @@ +<?php + +/** + * @file + * Test fixture. + */ + +use Drupal\Core\Database\Database; + +$connection = Database::getConnection(); + +// Set the schema version. +$connection->merge('key_value') + ->fields(['value' => 'i:8602;']) + ->condition('collection', 'system.schema') + ->condition('name', 'layout_builder') + ->execute(); + +// Update core.extension. +$extensions = $connection->select('config') + ->fields('config', ['data']) + ->condition('collection', '') + ->condition('name', 'core.extension') + ->execute() + ->fetchField(); +$extensions = unserialize($extensions); +$extensions['module']['layout_builder'] = 0; +$extensions['module']['layout_discovery'] = 0; +$connection->update('config') + ->fields(['data' => serialize($extensions)]) + ->condition('collection', '') + ->condition('name', 'core.extension') + ->execute(); + +// Add all layout_builder_removed_post_updates() as existing updates. +require_once __DIR__ . '/../../../../layout_builder/layout_builder.post_update.php'; +require_once __DIR__ . '/../../../../layout_discovery/layout_discovery.post_update.php'; +$existing_updates = $connection->select('key_value') + ->fields('key_value', ['value']) + ->condition('collection', 'post_update') + ->condition('name', 'existing_updates') + ->execute() + ->fetchField(); +$existing_updates = unserialize($existing_updates); +$existing_updates = array_merge( + $existing_updates, + array_keys(layout_builder_removed_post_updates()), + array_keys(layout_discovery_removed_post_updates()) +); +$connection->update('key_value') + ->fields(['value' => serialize($existing_updates)]) + ->condition('collection', 'post_update') + ->condition('name', 'existing_updates') + ->execute(); diff --git a/core/modules/layout_builder/tests/modules/layout_builder_test/src/Plugin/Layout/TestContextAwareLayout.php b/core/modules/layout_builder/tests/modules/layout_builder_test/src/Plugin/Layout/TestContextAwareLayout.php new file mode 100644 index 000000000000..b53e954c8703 --- /dev/null +++ b/core/modules/layout_builder/tests/modules/layout_builder_test/src/Plugin/Layout/TestContextAwareLayout.php @@ -0,0 +1,32 @@ +<?php + +namespace Drupal\layout_builder_test\Plugin\Layout; + +use Drupal\Core\Layout\LayoutDefault; + +/** + * @Layout( + * id = "layout_builder_test_context_aware", + * label = @Translation("Layout Builder Test: Context Aware"), + * regions = { + * "main" = { + * "label" = @Translation("Main Region") + * } + * }, + * context_definitions = { + * "user" = @ContextDefinition("entity:user") + * } + * ) + */ +class TestContextAwareLayout extends LayoutDefault { + + /** + * {@inheritdoc} + */ + public function build(array $regions) { + $build = parent::build($regions); + $build['main']['#attributes']['class'][] = 'user--' . $this->getContextValue('user')->getAccountName(); + return $build; + } + +} diff --git a/core/modules/layout_builder/tests/src/Functional/LayoutBuilderTest.php b/core/modules/layout_builder/tests/src/Functional/LayoutBuilderTest.php index 443af8a73fb4..9a1dc75c6c15 100644 --- a/core/modules/layout_builder/tests/src/Functional/LayoutBuilderTest.php +++ b/core/modules/layout_builder/tests/src/Functional/LayoutBuilderTest.php @@ -1045,6 +1045,39 @@ public function testSectionLabels() { $assert_session->pageTextNotContains('My Cool Section'); } + /** + * Tests that layouts can be context-aware. + */ + public function testContextAwareLayouts() { + $assert_session = $this->assertSession(); + $page = $this->getSession()->getPage(); + + $account = $this->drupalCreateUser([ + 'configure any layout', + 'administer node display', + ]); + $this->drupalLogin($account); + + $this->drupalPostForm('admin/structure/types/manage/bundle_with_section_field/display/default', ['layout[enabled]' => TRUE], 'Save'); + $page->clickLink('Manage layout'); + $page->clickLink('Add section'); + $page->clickLink('Layout Builder Test: Context Aware'); + $page->pressButton('Add section'); + // See \Drupal\layout_builder_test\Plugin\Layout\TestContextAwareLayout::build(). + $assert_session->elementExists('css', '.user--' . $account->getAccountName()); + $page->clickLink('Configure Section 1'); + $page->fillField('layout_settings[label]', 'My section'); + $page->pressButton('Update'); + $assert_session->linkExists('Configure My section'); + $page->clickLink('Add block'); + $page->clickLink('Powered by Drupal'); + $page->pressButton('Add block'); + $page->pressButton('Save layout'); + $this->drupalGet('node/1'); + // See \Drupal\layout_builder_test\Plugin\Layout\TestContextAwareLayout::build(). + $assert_session->elementExists('css', '.user--' . $account->getAccountName()); + } + /** * Tests that sections can provide custom attributes. */ diff --git a/core/modules/layout_builder/tests/src/Functional/Update/LayoutBuilderContextMappingUpdatePathTest.php b/core/modules/layout_builder/tests/src/Functional/Update/LayoutBuilderContextMappingUpdatePathTest.php new file mode 100644 index 000000000000..20f0d067d962 --- /dev/null +++ b/core/modules/layout_builder/tests/src/Functional/Update/LayoutBuilderContextMappingUpdatePathTest.php @@ -0,0 +1,43 @@ +<?php + +namespace Drupal\Tests\layout_builder\Functional\Update; + +use Drupal\Core\Entity\Entity\EntityViewDisplay; +use Drupal\FunctionalTests\Update\UpdatePathTestBase; + +/** + * Tests the upgrade path for Layout Builder layout context mappings. + * + * @see layout_builder_post_update_section_storage_context_mapping() + * + * @group layout_builder + */ +class LayoutBuilderContextMappingUpdatePathTest extends UpdatePathTestBase { + + /** + * {@inheritdoc} + */ + protected function setDatabaseDumpFiles() { + $this->databaseDumpFiles = [ + __DIR__ . '/../../../../../system/tests/fixtures/update/drupal-9.0.0.bare.standard.php.gz', + __DIR__ . '/../../../fixtures/update/layout-builder.php', + __DIR__ . '/../../../fixtures/update/layout-builder-context-mapping.php', + ]; + } + + /** + * Tests the upgrade path for Layout Builder layout context mappings. + */ + public function testRunUpdates() { + $data = EntityViewDisplay::load('node.article.teaser')->toArray(); + $this->assertSame(TRUE, $data['third_party_settings']['layout_builder']['enabled']); + $this->assertArrayNotHasKey('context_mapping', $data['third_party_settings']['layout_builder']['sections'][0]->toArray()['layout_settings']); + + $this->runUpdates(); + + $data = EntityViewDisplay::load('node.article.teaser')->toArray(); + $this->assertSame(TRUE, $data['third_party_settings']['layout_builder']['enabled']); + $this->assertSame([], $data['third_party_settings']['layout_builder']['sections'][0]->toArray()['layout_settings']['context_mapping']); + } + +} diff --git a/core/modules/layout_builder/tests/src/Unit/SectionTest.php b/core/modules/layout_builder/tests/src/Unit/SectionTest.php index 1d3e7a24ff94..2e21947de9dd 100644 --- a/core/modules/layout_builder/tests/src/Unit/SectionTest.php +++ b/core/modules/layout_builder/tests/src/Unit/SectionTest.php @@ -2,6 +2,10 @@ namespace Drupal\Tests\layout_builder\Unit; +use Drupal\Core\DependencyInjection\ContainerBuilder; +use Drupal\Core\Layout\LayoutInterface; +use Drupal\Core\Layout\LayoutPluginManagerInterface; +use Drupal\Core\Plugin\Context\ContextHandlerInterface; use Drupal\layout_builder\Section; use Drupal\layout_builder\SectionComponent; use Drupal\Tests\UnitTestCase; @@ -362,4 +366,40 @@ public function testGetThirdPartyProviders() { $this->assertSame(['bad_judgement'], $this->section->getThirdPartyProviders()); } + /** + * @covers ::getLayout + * @dataProvider providerTestGetLayout + */ + public function testGetLayout(array $contexts, bool $should_context_apply) { + $layout = $this->prophesize(LayoutInterface::class); + $layout_plugin_manager = $this->prophesize(LayoutPluginManagerInterface::class); + $layout_plugin_manager->createInstance('layout_onecol', [])->willReturn($layout->reveal()); + + $context_handler = $this->prophesize(ContextHandlerInterface::class); + if ($should_context_apply) { + $context_handler->applyContextMapping($layout->reveal(), $contexts)->shouldBeCalled(); + } + else { + $context_handler->applyContextMapping($layout->reveal(), $contexts)->shouldNotBeCalled(); + } + + $container = new ContainerBuilder(); + $container->set('plugin.manager.core.layout', $layout_plugin_manager->reveal()); + $container->set('context.handler', $context_handler->reveal()); + \Drupal::setContainer($container); + + $output = $this->section->getLayout($contexts); + $this->assertSame($layout->reveal(), $output); + } + + /** + * Provides test data for ::testGetLayout(). + */ + public function providerTestGetLayout() { + $data = []; + $data['contexts'] = [['foo' => 'bar'], TRUE]; + $data['no contexts'] = [[], FALSE]; + return $data; + } + } -- GitLab