Commit 9b768d70 authored by webchick's avatar webchick

Issue #2443457 by Wim Leers, dawehner, Berdir, giancarlosotelo, Jaesin: Views...

Issue #2443457 by Wim Leers, dawehner, Berdir, giancarlosotelo, Jaesin: Views block displayed when no results returned
parent 445b4cd1
......@@ -63,6 +63,11 @@ public function access(AccountInterface $account, $return_as_object = FALSE);
/**
* Builds and returns the renderable array for this block plugin.
*
* If a block should not be rendered because it has no content, then this
* method must also ensure to return no content: it must then only return an
* empty array, or an empty array with #cache set (with cacheability metadata
* indicating the circumstances for it being empty).
*
* @return array
* A renderable array representing the content of the block.
*
......
......@@ -8,6 +8,8 @@
namespace Drupal\block\Tests\Views;
use Drupal\Component\Serialization\Json;
use Drupal\system\Tests\Cache\AssertPageCacheContextsAndTagsTrait;
use Drupal\views\Entity\View;
use Drupal\views\Views;
use Drupal\views\Tests\ViewTestBase;
use Drupal\views\Tests\ViewTestData;
......@@ -21,6 +23,8 @@
*/
class DisplayBlockTest extends ViewTestBase {
use AssertPageCacheContextsAndTagsTrait;
/**
* Modules to install.
*
......@@ -259,6 +263,87 @@ public function testBlockRendering() {
$this->drupalGet('');
$result = $this->xpath('//div[contains(@class, "region-sidebar-first")]/div[contains(@class, "block-views")]/h2');
$this->assertTrue(empty($result), 'The title is not visible.');
$this->assertCacheTags(array_merge($block->getCacheTags(), ['block_view', 'config:block_list', 'config:system.site', 'config:views.view.test_view_block' ,'rendered']));
}
/**
* Tests the various testcases of empty block rendering.
*/
public function testBlockEmptyRendering() {
// Remove all views_test_data entries.
\Drupal::database()->truncate('views_test_data')->execute();
/** @var \Drupal\views\ViewEntityInterface $view */
$view = View::load('test_view_block');
$view->invalidateCaches();
$block = $this->drupalPlaceBlock('views_block:test_view_block-block_1', array('label' => 'test_view_block-block_1:1', 'views_label' => 'Custom title'));
$this->drupalGet('');
$this->assertEqual(1, count($this->xpath('//div[contains(@class, "block-views-blocktest-view-block-block-1")]')));
$display = &$view->getDisplay('block_1');
$display['display_options']['block_hide_empty'] = TRUE;
$view->save();
$this->drupalGet('');
$this->assertEqual(0, count($this->xpath('//div[contains(@class, "block-views-blocktest-view-block-block-1")]')));
// Ensure that the view cachability metadata is propagated even, for an
// empty block.
$this->assertCacheTags(array_merge($block->getCacheTags(), ['block_view', 'config:block_list', 'config:system.site', 'config:views.view.test_view_block' ,'rendered']));
$this->assertCacheContexts(['url.query_args:_wrapper_format', 'user.roles:authenticated']);
// Add a header displayed on empty result.
$display = &$view->getDisplay('block_1');
$display['display_options']['defaults']['header'] = FALSE;
$display['display_options']['header']['example'] = [
'field' => 'area_text_custom',
'id' => 'area_text_custom',
'table' => 'views',
'plugin_id' => 'text_custom',
'content' => 'test header',
'empty' => TRUE,
];
$view->save();
$this->drupalGet('');
$this->assertEqual(1, count($this->xpath('//div[contains(@class, "block-views-blocktest-view-block-block-1")]')));
$this->assertCacheTags(array_merge($block->getCacheTags(), ['block_view', 'config:block_list', 'config:system.site', 'config:views.view.test_view_block' ,'rendered']));
$this->assertCacheContexts(['url.query_args:_wrapper_format', 'user.roles:authenticated']);
// Hide the header on empty results.
$display = &$view->getDisplay('block_1');
$display['display_options']['defaults']['header'] = FALSE;
$display['display_options']['header']['example'] = [
'field' => 'area_text_custom',
'id' => 'area_text_custom',
'table' => 'views',
'plugin_id' => 'text_custom',
'content' => 'test header',
'empty' => FALSE,
];
$view->save();
$this->drupalGet('');
$this->assertEqual(0, count($this->xpath('//div[contains(@class, "block-views-blocktest-view-block-block-1")]')));
$this->assertCacheTags(array_merge($block->getCacheTags(), ['block_view', 'config:block_list', 'config:system.site', 'config:views.view.test_view_block' ,'rendered']));
$this->assertCacheContexts(['url.query_args:_wrapper_format', 'user.roles:authenticated']);
// Add an empty text.
$display = &$view->getDisplay('block_1');
$display['display_options']['defaults']['empty'] = FALSE;
$display['display_options']['empty']['example'] = [
'field' => 'area_text_custom',
'id' => 'area_text_custom',
'table' => 'views',
'plugin_id' => 'text_custom',
'content' => 'test empty',
];
$view->save();
$this->drupalGet('');
$this->assertEqual(1, count($this->xpath('//div[contains(@class, "block-views-blocktest-view-block-block-1")]')));
$this->assertCacheTags(array_merge($block->getCacheTags(), ['block_view', 'config:block_list', 'config:system.site', 'config:views.view.test_view_block' ,'rendered']));
$this->assertCacheContexts(['url.query_args:_wrapper_format', 'user.roles:authenticated']);
}
/**
......
......@@ -38,6 +38,12 @@ public function getInfo() {
* View element pre render callback.
*/
public static function preRenderViewElement($element) {
// Allow specific Views displays to explicitly perform pre-rendering, for
// those displays that need to be able to know the fully built render array.
if (!empty($element['#pre_rendered'])) {
return $element;
}
if (!isset($element['#view'])) {
$view = Views::getView($element['#name']);
}
......
......@@ -10,6 +10,7 @@
use Drupal\Component\Utility\Xss;
use Drupal\Core\Config\Entity\Query\Query;
use Drupal\Core\Form\FormStateInterface;
use Drupal\views\Element\View;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
......@@ -38,6 +39,20 @@ public function build() {
// Before returning the block output, convert it to a renderable array
// with contextual links.
$this->addContextualLinks($output);
// Block module expects to get a final render array, without another
// top-level #pre_render callback. So, here we make sure that Views'
// #pre_render callback has already been applied.
$output = View::preRenderViewElement($output);
// When view_build is empty, the actual render array output for this View
// is going to be empty. In that case, return just #cache, so that the
// render system knows the reasons (cache contexts & tags) why this Views
// block is empty, and can cache it accordingly.
if (empty($output['view_build'])) {
$output = ['#cache' => $output['#cache']];
}
return $output;
}
......
......@@ -141,7 +141,7 @@ protected function setUp() {
*/
public function testBuild() {
$output = $this->randomMachineName(100);
$build = array('#markup' => $output, '#view_id' => 'test_view', '#view_display_plugin_class' => '\Drupal\views\Plugin\views\display\Block', '#view_display_show_admin_links' => FALSE, '#view_display_plugin_id' => 'block');
$build = array('view_build' => $output, '#view_id' => 'test_view', '#view_display_plugin_class' => '\Drupal\views\Plugin\views\display\Block', '#view_display_show_admin_links' => FALSE, '#view_display_plugin_id' => 'block', '#pre_rendered' => TRUE);
$this->executable->expects($this->once())
->method('buildRenderable')
->with('block_1', [])
......@@ -157,6 +157,28 @@ public function testBuild() {
$this->assertEquals($build, $plugin->build());
}
/**
* Tests the build method.
*
* @covers ::build
*/
public function testBuildEmpty() {
$build = ['view_build' => [], '#view_id' => 'test_view', '#view_display_plugin_class' => '\Drupal\views\Plugin\views\display\Block', '#view_display_show_admin_links' => FALSE, '#view_display_plugin_id' => 'block', '#pre_rendered' => TRUE, '#cache' => ['contexts' => ['user']]];
$this->executable->expects($this->once())
->method('buildRenderable')
->with('block_1', [])
->willReturn($build);
$block_id = 'views_block:test_view-block_1';
$config = [];
$definition = [];
$definition['provider'] = 'views';
$plugin = new ViewsBlock($config, $block_id, $definition, $this->executableFactory, $this->storage, $this->account);
$this->assertEquals(array_intersect_key($build, ['#cache' => TRUE]), $plugin->build());
}
/**
* Tests the build method with a failed execution.
*
......
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