Commit ffe035e6 authored by alexpott's avatar alexpott
Browse files

Issue #2363025 by Wim Leers, dawehner, larowlan: Push usage of...

Issue #2363025 by Wim Leers, dawehner, larowlan: Push usage of drupal_set_page_content() higher: out of blocks and page display variants.
parent faff6ffa
<?php
/**
* @file
* Contains \Drupal\Core\Block\MainContentBlockPluginInterface.
*/
namespace Drupal\Core\Block;
/**
* The interface for "main page content" blocks.
*
* A main page content block represents the content returns by the controller.
*
* @ingroup block_api
*/
interface MainContentBlockPluginInterface extends BlockPluginInterface {
/**
* Sets the main content render array.
*
* @param array $main_content
* The render array representing the main content.
*/
public function setMainContent(array $main_content);
}
......@@ -13,9 +13,7 @@
* Defines a display variant annotation object.
*
* Display variants are used to dictate the output of a given Display, which
* can be used to control the output of many parts of Drupal. For example, the
* FullPageVariant is used by the Block module to control regions and output
* block content placed in those regions.
* can be used to control the output of many parts of Drupal.
*
* Variants are usually chosen by some selection criteria, and are instantiated
* directly. Each variant must define its own approach to rendering, and can
......@@ -33,6 +31,7 @@
* @see \Drupal\Core\Display\VariantInterface
* @see \Drupal\Core\Display\VariantBase
* @see \Drupal\Core\Display\VariantManager
* @see \Drupal\Core\Display\PageVariantInterface
* @see plugin_api
*
* @Annotation
......
<?php
/**
* @file
* Contains \Drupal\Core\Display\Annotation\PageDisplayVariant.
*/
namespace Drupal\Core\Display\Annotation;
/**
* Defines a page display variant annotation object.
*
* Page display variants are a specific type of display variant, intended to
* render the main content of a page.
*
* @see \Drupal\Core\Display\VariantInterface
* @see \Drupal\Core\Display\PageVariantInterface
* @see \Drupal\Core\Display\VariantBase
* @see \Drupal\Core\Display\VariantManager
* @see plugin_api
*
* @Annotation
*/
class PageDisplayVariant extends DisplayVariant {
}
<?php
/**
* @file
* Contains \Drupal\Core\Display\PageVariantInterface.
*/
namespace Drupal\Core\Display;
/**
* Provides an interface for PageDisplayVariant plugins.
*
* Page display variants are a specific type of DisplayVariant, intended for
* "pages", which always have some main content to be rendered. Hence page
* display variants may choose to render that main content in a certain way:
* decorated in a certain way, laid out in a certain way, et cetera.
*
* For example, the \Drupal\block\Plugin\DisplayVariant\FullPageVariant page
* display variant is used by the Block module to control regions and output
* blocks placed in those regions.
*
* @see \Drupal\Core\Display\Annotation\DisplayVariant
* @see \Drupal\Core\Display\VariantBase
* @see \Drupal\Core\Display\VariantManager
* @see plugin_api
*/
interface PageVariantInterface extends VariantInterface {
/**
* Sets the main content for the page being rendered.
*
* @param array $main_content
* The render array representing the main content.
*
* @return $this
*/
public function setMainContent(array $main_content);
}
......@@ -76,6 +76,7 @@ function _block_page_build(&$page) {
// regions.
$page += \Drupal::service('plugin.manager.display_variant')
->createInstance('full_page')
->setMainContent(drupal_set_page_content())
->build();
}
else {
......
......@@ -7,6 +7,8 @@
namespace Drupal\block\Plugin\DisplayVariant;
use Drupal\Core\Block\MainContentBlockPluginInterface;
use Drupal\Core\Display\PageVariantInterface;
use Drupal\Core\Entity\EntityStorageInterface;
use Drupal\Core\Entity\EntityViewBuilderInterface;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
......@@ -18,12 +20,12 @@
/**
* Provides a display variant that represents the full page.
*
* @DisplayVariant(
* @PageDisplayVariant(
* id = "full_page",
* admin_label = @Translation("Full page")
* )
*/
class FullPageVariant extends VariantBase implements ContainerFactoryPluginInterface {
class FullPageVariant extends VariantBase implements PageVariantInterface, ContainerFactoryPluginInterface {
/**
* The block storage.
......@@ -60,6 +62,13 @@ class FullPageVariant extends VariantBase implements ContainerFactoryPluginInter
*/
protected $themeNegotiator;
/**
* The render array representing the main page content.
*
* @var array
*/
protected $mainContent;
/**
* Constructs a new FullPageVariant.
*
......@@ -101,6 +110,14 @@ public static function create(ContainerInterface $container, array $configuratio
);
}
/**
* {@inheritdoc}
*/
public function setMainContent(array $main_content) {
$this->mainContent = $main_content;
return $this;
}
/**
* Gets the current theme for this page.
*
......@@ -115,12 +132,20 @@ protected function getTheme() {
* {@inheritdoc}
*/
public function build() {
// Track whether a block that shows the main content is displayed or not.
$main_content_block_displayed = FALSE;
$build = array();
// Load all region content assigned via blocks.
foreach ($this->getRegionAssignments() as $region => $blocks) {
/** @var $blocks \Drupal\block\BlockInterface[] */
foreach ($blocks as $key => $block) {
if ($block->access('view')) {
$block_plugin = $block->getPlugin();
if ($block_plugin instanceof MainContentBlockPluginInterface) {
$block_plugin->setMainContent($this->mainContent);
$main_content_block_displayed = TRUE;
}
$build[$region][$key] = $this->blockViewBuilder->view($block);
}
}
......@@ -129,6 +154,14 @@ public function build() {
$build[$region]['#sorted'] = TRUE;
}
}
// If no block that shows the main content is displayed, still show the main
// content. Otherwise the end user will see all displayed blocks, but not
// the main content they came for.
if (!$main_content_block_displayed) {
$build['content']['system_main'] = $this->mainContent;
}
return $build;
}
......
......@@ -65,13 +65,78 @@ public function setUpDisplayVariant($configuration = array(), $definition = arra
->getMock();
}
public function providerBuild() {
$blocks_config = array(
'block1' => array(
TRUE, 'top', 0, FALSE,
),
// Test a block without access.
'block2' => array(
FALSE, 'bottom', 0, FALSE,
),
// Test two blocks in the same region with specific weight.
'block3' => array(
TRUE, 'bottom', 5, FALSE,
),
'block4' => array(
TRUE, 'bottom', -5, FALSE,
),
// Test a block implementing MainContentBlockPluginInterface.
'block5' => array(
TRUE, 'center', 0, TRUE,
),
);
$test_cases = [];
$test_cases[] = [$blocks_config, 4,
[
'top' => [
'block1' => [],
'#sorted' => TRUE,
],
// The main content was rendered via a block.
'center' => [
'block5' => [],
'#sorted' => TRUE,
],
'bottom' => [
'block4' => [],
'block3' => [],
'#sorted' => TRUE,
],
],
];
unset($blocks_config['block5']);
$test_cases[] = [$blocks_config, 3,
[
'top' => [
'block1' => [],
'#sorted' => TRUE,
],
'bottom' => [
'block4' => [],
'block3' => [],
'#sorted' => TRUE,
],
// The main content was rendered via the fallback in case there is no
// block rendering the main content.
'content' => [
'system_main' => ['#markup' => 'Hello kittens!'],
],
],
];
return $test_cases;
}
/**
* Tests the building of a full page variant.
*
* @covers ::build
* @covers ::getRegionAssignments
*
* @dataProvider providerBuild
*/
public function testBuild() {
public function testBuild(array $blocks_config, $visible_block_count, array $expected_render_array) {
$theme = $this->randomMachineName();
$display_variant = $this->setUpDisplayVariant();
$this->themeNegotiator->expects($this->any())
......@@ -82,26 +147,14 @@ public function testBuild() {
->method('getRegionNames')
->will($this->returnValue(array(
'top' => 'Top',
'center' => 'Center',
'bottom' => 'Bottom',
)));
$display_variant->setMainContent(['#markup' => 'Hello kittens!']);
$blocks_config = array(
'block1' => array(
TRUE, 'top', 0,
),
// Test a block without access.
'block2' => array(
FALSE, 'bottom', 0,
),
// Test two blocks in the same region with specific weight.
'block3' => array(
TRUE, 'bottom', 5,
),
'block4' => array(
TRUE, 'bottom', -5,
),
);
$blocks = array();
$block_plugin = $this->getMock('Drupal\Core\Block\BlockPluginInterface');
$main_content_block_plugin = $this->getMock('Drupal\Core\Block\MainContentBlockPluginInterface');
foreach ($blocks_config as $block_id => $block_config) {
$block = $this->getMock('Drupal\block\BlockInterface');
$block->expects($this->once())
......@@ -114,10 +167,13 @@ public function testBuild() {
array('weight', $block_config[2]),
array('status', TRUE),
)));
$block->expects($this->any())
->method('getPlugin')
->willReturn($block_config[3] ? $main_content_block_plugin : $block_plugin);
$blocks[$block_id] = $block;
}
$this->blockViewBuilder->expects($this->exactly(3))
$this->blockViewBuilder->expects($this->exactly($visible_block_count))
->method('view')
->will($this->returnValue(array()));
$this->blockStorage->expects($this->once())
......@@ -125,18 +181,7 @@ public function testBuild() {
->with(array('theme' => $theme))
->will($this->returnValue($blocks));
$expected = array(
'top' => array(
'block1' => array(),
'#sorted' => TRUE,
),
'bottom' => array(
'block4' => array(),
'block3' => array(),
'#sorted' => TRUE,
),
);
$this->assertSame($expected, $display_variant->build());
$this->assertSame($expected_render_array, $display_variant->build());
}
}
......@@ -8,6 +8,7 @@
namespace Drupal\system\Plugin\Block;
use Drupal\Core\Block\BlockBase;
use Drupal\Core\Block\MainContentBlockPluginInterface;
use Drupal\Core\Form\FormStateInterface;
/**
......@@ -18,15 +19,27 @@
* admin_label = @Translation("Main page content")
* )
*/
class SystemMainBlock extends BlockBase {
class SystemMainBlock extends BlockBase implements MainContentBlockPluginInterface {
/**
* The render array representing the main page content.
*
* @var array
*/
protected $mainContent;
/**
* {@inheritdoc}
*/
public function setMainContent(array $main_content) {
$this->mainContent = $main_content;
}
/**
* {@inheritdoc}
*/
public function build() {
return array(
drupal_set_page_content()
);
return $this->mainContent;
}
/**
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment