diff --git a/core/modules/layout_builder/layout_builder.info.yml b/core/modules/layout_builder/layout_builder.info.yml new file mode 100644 index 0000000..50a51d0 --- /dev/null +++ b/core/modules/layout_builder/layout_builder.info.yml @@ -0,0 +1,8 @@ +name: 'Layout Builder' +type: module +description: 'Provides layout building utility.' +package: Core (Experimental) +version: VERSION +core: 8.x +dependencies: + - layout_discovery diff --git a/core/modules/layout_builder/src/LayoutSectionItemInterface.php b/core/modules/layout_builder/src/LayoutSectionItemInterface.php new file mode 100644 index 0000000..1a39cde --- /dev/null +++ b/core/modules/layout_builder/src/LayoutSectionItemInterface.php @@ -0,0 +1,15 @@ +account = $account; + $this->layoutPluginManager = $layoutPluginManager; + $this->blockManager = $blockManager; + parent::__construct($plugin_id, $plugin_definition, $field_definition, $settings, $label, $view_mode, $third_party_settings); + } + + /** + * {@inheritdoc} + */ + public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) { + return new static( + $container->get('current_user'), + $container->get('plugin.manager.core.layout'), + $container->get('plugin.manager.block'), + $plugin_id, + $plugin_definition, + $configuration['field_definition'], + $configuration['settings'], + $configuration['label'], + $configuration['view_mode'], + $configuration['third_party_settings'] + ); + } + + /** + * {@inheritdoc} + */ + public function viewElements(FieldItemListInterface $items, $langcode) { + $elements = []; + + foreach ($items as $delta => $item) { + $elements[$delta] = $this->buildSection($item); + } + + return $elements; + } + + /** + * Builds the render array for the layout section. + * + * @param \Drupal\layout_builder\LayoutSectionItemInterface $item + * The layout section item. + * + * @return array + * A render array for the field item. + */ + protected function buildSection(LayoutSectionItemInterface $item) { + /** @var \Drupal\Core\Layout\LayoutInterface $layout */ + $layout = $this->layoutPluginManager->createInstance($item->layout); + $regions = []; + foreach ($item->section as $region => $blocks) { + foreach ($blocks as $uuid => $configuration) { + /** @var \Drupal\Core\Block\BlockPluginInterface $block */ + $block = $this->blockManager->createInstance($configuration['plugin_id'], $configuration); + $access = $block->access($this->account, TRUE); + if ($access->isAllowed()) { + $regions[$region][$uuid] = $block->build(); + } + } + } + return $layout->build($regions); + } + +} diff --git a/core/modules/layout_builder/src/Plugin/Field/FieldType/LayoutSectionItem.php b/core/modules/layout_builder/src/Plugin/Field/FieldType/LayoutSectionItem.php new file mode 100644 index 0000000..8cf547d --- /dev/null +++ b/core/modules/layout_builder/src/Plugin/Field/FieldType/LayoutSectionItem.php @@ -0,0 +1,87 @@ +setLabel(new TranslatableMarkup('Layout')) + ->setSetting('case_sensitive', FALSE) + ->setRequired(TRUE); + $properties[static::mainPropertyName()] = MapDataDefinition::create('map') + ->setLabel(new TranslatableMarkup('Layout Section')) + ->setRequired(FALSE); + + return $properties; + } + + /** + * {@inheritdoc} + */ + public static function mainPropertyName() { + return 'section'; + } + + /** + * {@inheritdoc} + */ + public static function schema(FieldStorageDefinitionInterface $field_definition) { + $schema = [ + 'columns' => [ + 'layout' => [ + 'type' => 'varchar', + 'length' => '255', + 'binary' => FALSE, + ], + static::mainPropertyName() => [ + 'type' => 'blob', + 'size' => 'normal', + 'serialize' => TRUE, + ], + ], + ]; + + return $schema; + } + + /** + * {@inheritdoc} + */ + public static function generateSampleValue(FieldDefinitionInterface $field_definition) { + $values['layout'] = 'layout_onecol'; + $values[static::mainPropertyName()] = []; + return $values; + } + + /** + * {@inheritdoc} + */ + public function isEmpty() { + $sections = $this->get(static::mainPropertyName())->getValue(); + return empty($sections); + } + +} diff --git a/core/modules/layout_builder/tests/src/Kernel/LayoutSectionFormatterTest.php b/core/modules/layout_builder/tests/src/Kernel/LayoutSectionFormatterTest.php new file mode 100644 index 0000000..fe540d0 --- /dev/null +++ b/core/modules/layout_builder/tests/src/Kernel/LayoutSectionFormatterTest.php @@ -0,0 +1,120 @@ +installConfig(['field']); + $this->installEntitySchema('entity_test'); + + $entity_type = 'entity_test'; + $bundle = $entity_type; + $this->fieldName = Unicode::strtolower($this->randomMachineName()); + + $field_storage = FieldStorageConfig::create([ + 'field_name' => $this->fieldName, + 'entity_type' => $entity_type, + 'type' => 'layout_section', + ]); + $field_storage->save(); + + $instance = FieldConfig::create([ + 'field_storage' => $field_storage, + 'bundle' => $bundle, + 'label' => $this->randomMachineName(), + ]); + $instance->save(); + + $this->display = EntityViewDisplay::create([ + 'targetEntityType' => $entity_type, + 'bundle' => $bundle, + 'mode' => 'default', + 'status' => TRUE, + ]); + $this->display->setComponent($this->fieldName, [ + 'type' => 'layout_section', + 'settings' => [], + ]); + $this->display->save(); + } + + /** + * Tests layout_section formatter output. + * + * @dataProvider providerTestLayoutSectionFormatter + */ + public function testLayoutSectionFormatter($layout, $section, $expected_selector, $expected_content) { + $entity = EntityTest::create([]); + $entity->{$this->fieldName}->layout = $layout; + $entity->{$this->fieldName}->section = $section; + + // Build and render the content. + $content = $this->display->build($entity); + $this->render($content); + + // Find the given selector. + $element = $this->cssSelect($expected_selector); + $this->assertNotEmpty($element); + + // Find the given content. + $this->assertRaw($expected_content); + } + + /** + * Provides test data to ::testLayoutSectionFormatter(). + */ + public function providerTestLayoutSectionFormatter() { + $data = []; + $data[] = [ + 'layout_onecol', + [ + 'content' => [ + 'this_should_be_a_UUID' => [ + 'plugin_id' => 'system_powered_by_block', + ], + ], + ], + '.layout--onecol', + 'Powered by', + ]; + return $data; + } + +}