diff --git a/core/modules/layout/layouts/static/one-col/one-col.yml b/core/modules/layout/layouts/static/one-col/one-col.yml index deaa7f8eb463465d32cbe382842598abf44d02f7..ea550ca650b8da4c75b3c13398f9908d850b32cd 100644 --- a/core/modules/layout/layouts/static/one-col/one-col.yml +++ b/core/modules/layout/layouts/static/one-col/one-col.yml @@ -2,4 +2,6 @@ title: One column category: Columns: 1 template: one-col regions: - content: 'Content' + content: + label: Middle column + type: content \ No newline at end of file diff --git a/core/modules/layout/layouts/static/twocol/two-col.yml b/core/modules/layout/layouts/static/twocol/two-col.yml index 9df31fb0c582f731e4022958bc82de1721ed9435..e6c435e43b9d4a819b2376d18030e62c3e0412d2 100644 --- a/core/modules/layout/layouts/static/twocol/two-col.yml +++ b/core/modules/layout/layouts/static/twocol/two-col.yml @@ -4,5 +4,9 @@ template: two-col stylesheets: - two-col.css regions: - first: 'First column' - second: 'Second column' + first: + label: Left side + type: content + second: + label: Right side + type: aside diff --git a/core/modules/layout/lib/Drupal/layout/Config/BoundDisplayInterface.php b/core/modules/layout/lib/Drupal/layout/Config/BoundDisplayInterface.php new file mode 100644 index 0000000000000000000000000000000000000000..125c34eb08196156ed9b5727f5c2b6cf87b75e5e --- /dev/null +++ b/core/modules/layout/lib/Drupal/layout/Config/BoundDisplayInterface.php @@ -0,0 +1,88 @@ + array( + * 'region' => 'content', + * // store the region type name here so that we can do type conversion w/out + * // needing to have access to the original layout plugin + * 'region-type' => 'content', + * // increment by 100 so there is ALWAYS plenty of space for manual insertion + * 'weight' => -100, + * ), + * 'block2-configkey' => array( + * 'region' => 'sidebar_first', + * 'region-type' => 'aside', + * 'weight' => -100, + * ), + * 'block2-configkey' => array( + * 'region' => 'sidebar_first', + * 'region-type' => 'aside', + * 'weight' => 0, + * ), + * 'maincontent' => array( + * 'region' => 'content', + * 'region-type' => 'content', + * 'weight' => -200, + * ), + * ); + * @endcode + * + * @var array + */ + protected $blockInfo = array(); + + /** + * Implements DisplayInterface::getAllBlockInfo(). + */ + public function getAllBlockInfo() { + return $this->blockInfo; + } + + /** + * Implements DisplayInterface::mapBlocksToLayout(). + * + * @todo Decouple this implementation from this class, so that it could be + * more easily customized. + */ + public function mapBlocksToLayout(LayoutInterface $layout) { + $types = array(); + + $layout_regions = $layout->getRegions(); + $layout_regions_indexed = array_keys($layout_regions); + foreach ($layout_regions as $name => $info) { + $types[$info['type']][] = $name; + } + + $remapped_config = array(); + foreach ($this->blockInfo as $name => $info) { + // First, if there's a direct region name match, use that. + if (!empty($info['region']) && isset($layout_regions[$info['region']])) { + // No need to do anything. + } + // Then, try to remap using region types. + else if (!empty($types[$info['region-type']])) { + $info['region'] = reset($types[$info['region-type']]); + } + // Finally, fall back to dumping everything in the layout's first region. + else { + if (!isset($first_region)) { + reset($layout_regions); + $first_region = key($layout_regions); + } + $info['region'] = $first_region; + } + + $remapped_config[$name] = $info; + } + + return $remapped_config; + } + + /** + * Implements DisplayInterface::getAllRegionTypes(). + */ + public function getAllRegionTypes() { + $types = array(); + foreach ($this->blockInfo as $info) { + $types[] = $info['region-type']; + } + return array_unique($types); + } +} diff --git a/core/modules/layout/lib/Drupal/layout/Config/DisplayInterface.php b/core/modules/layout/lib/Drupal/layout/Config/DisplayInterface.php new file mode 100644 index 0000000000000000000000000000000000000000..871aadc858058930a7abcedcc09d9a5b094c9aef --- /dev/null +++ b/core/modules/layout/lib/Drupal/layout/Config/DisplayInterface.php @@ -0,0 +1,85 @@ +blocksInRegions === NULL) { + $this->sortBlocks(); + } + + if (!isset($this->blocksInRegions[$region])) { + throw new \Exception(sprintf("Region %region does not exist in layout %layout", array('%region' => $region, '%layout' => $this->getLayoutInstance()->name)), E_RECOVERABLE_ERROR); + } + + return $this->blocksInRegions[$region]; + } + + /** + * Implements BoundDisplayInterface::getAllSortedBlocks(). + */ + public function getAllSortedBlocks() { + if ($this->blocksInRegions === NULL) { + $this->sortBlocks(); + } + + return $this->blocksInRegions; + } + + /** + * Transform the stored blockConfig into a sorted, region-oriented array. + */ + protected function sortBlocks() { + $layout_instance = $this->getLayoutInstance(); + if ($this->layout !== $layout_instance->getPluginId()) { + $block_config = $this->mapBlocksToLayout($layout_instance); + } + else { + $block_config = $this->blockInfo; + } + + $this->blocksInRegions = array(); + + $regions = array_fill_keys(array_keys($layout_instance->getRegions()), array()); + foreach ($block_config as $config_name => $info) { + $regions[$info['region']][$config_name] = $info; + } + + foreach ($regions as $region_name => &$blocks) { + uasort($blocks, 'drupal_sort_weight'); + $this->blocksInRegions[$region_name] = array_keys($blocks); + } + } + + /** + * Implements BoundDisplayInterface::remapToLayout(). + */ + public function remapToLayout(LayoutInterface $layout) { + $this->blockInfo = $this->mapBlocksToLayout($layout); + $this->setLayout($layout->getPluginId()); + } + + /** + * Set the contained layout plugin. + * + * @param string $plugin_id + * The plugin id of the desired layout plugin. + */ + public function setLayout($plugin_id) { + // @todo verification? + $this->layout = $plugin_id; + $this->layoutInstance = NULL; + $this->blocksInRegions = NULL; + } + + /** + * Implements BoundDisplayInterface::generateUnboundDisplay(). + * + * @throws \Exception + */ + public function generateUnboundDisplay($id, $entity_type = 'unbound_display') { + $block_info = $this->getAllBlockInfo(); + foreach ($block_info as &$info) { + unset($info['region']); + } + + $values = array( + 'blockInfo' => $block_info, + 'id' => $id, + ); + + $entity = entity_create($entity_type, $values); + if (!$entity instanceof UnboundDisplayInterface) { + throw new \Exception(sprintf('Attempted to create an unbound display using an invalid entity type.'), E_RECOVERABLE_ERROR); + } + + return $entity; + } + + /** + * Returns the instantiated layout object. + * + * @throws \Exception + */ + public function getLayoutInstance() { + if ($this->layoutInstance === NULL) { + if (empty($this->layout)) { + throw new \Exception(sprintf('Display "%id" had no layout plugin attached.', array('%id' => $this->id())), E_RECOVERABLE_ERROR); + } + + $this->layoutInstance = layout_manager()->createInstance($this->layout, $this->layoutSettings); + // @todo add handling for remapping if the layout could not be found + } + + return $this->layoutInstance; + } +} diff --git a/core/modules/layout/lib/Drupal/layout/Plugin/Core/Entity/UnboundDisplay.php b/core/modules/layout/lib/Drupal/layout/Plugin/Core/Entity/UnboundDisplay.php new file mode 100644 index 0000000000000000000000000000000000000000..5450e2c2a3e1257b6e5e93def6f7481d2728f827 --- /dev/null +++ b/core/modules/layout/lib/Drupal/layout/Plugin/Core/Entity/UnboundDisplay.php @@ -0,0 +1,57 @@ + $layout->getPluginId(), + 'blockInfo' => $this->mapBlocksToLayout($layout), + 'id' => $id, + ); + + $entity = entity_create($entity_type, $values); + + if (!$entity instanceof BoundDisplayInterface) { + throw new \Exception(sprintf('Attempted to bind an unbound display but provided an invalid entity type.'), E_RECOVERABLE_ERROR); + } + + return $entity; + } +} diff --git a/core/modules/layout/lib/Drupal/layout/Plugin/LayoutInterface.php b/core/modules/layout/lib/Drupal/layout/Plugin/LayoutInterface.php index 5b874f6f4d44d5291c83b2356a65b006ae8ab617..7521c57f9c3f6821b25862cfc4b96cf26ea6162d 100644 --- a/core/modules/layout/lib/Drupal/layout/Plugin/LayoutInterface.php +++ b/core/modules/layout/lib/Drupal/layout/Plugin/LayoutInterface.php @@ -7,10 +7,12 @@ namespace Drupal\layout\Plugin; +use Drupal\Component\Plugin\PluginInspectionInterface; + /** * Defines the shared interface for all layout plugins. */ -interface LayoutInterface { +interface LayoutInterface extends PluginInspectionInterface { /** * Returns a list of regions. diff --git a/core/modules/layout/lib/Drupal/layout/Plugin/layout/layout/StaticLayout.php b/core/modules/layout/lib/Drupal/layout/Plugin/layout/layout/StaticLayout.php index 4819595a52186d6703a1841d407d5c7051bd9284..3ded37918d1ba9a9acbb0c1a8b58e6caadfb5636 100644 --- a/core/modules/layout/lib/Drupal/layout/Plugin/layout/layout/StaticLayout.php +++ b/core/modules/layout/lib/Drupal/layout/Plugin/layout/layout/StaticLayout.php @@ -88,11 +88,11 @@ public function renderLayout($admin = FALSE) { ); // Render all regions needed for this layout. - foreach ($this->getRegions() as $region => $title) { + foreach ($this->getRegions() as $region => $info) { // @todo This is just stub code to fill in regions with stuff for now. // When blocks are related to layouts and not themes, we can make this // really be filled in with blocks. - $build['#content'][$region] = '