diff --git a/core/modules/block/lib/Drupal/block/Plugin/views/display/Block.php b/core/modules/block/lib/Drupal/block/Plugin/views/display/Block.php index 4319878..52f90ef 100644 --- a/core/modules/block/lib/Drupal/block/Plugin/views/display/Block.php +++ b/core/modules/block/lib/Drupal/block/Plugin/views/display/Block.php @@ -10,7 +10,6 @@ use Drupal\Component\Annotation\Plugin; use Drupal\Core\Annotation\Translation; -use Drupal\views\Plugin\Block\ViewsBlock; use Drupal\views\Plugin\views\display\DisplayPluginBase; /** @@ -46,6 +45,7 @@ protected function defineOptions() { $options['block_description'] = array('default' => '', 'translatable' => TRUE); $options['block_caching'] = array('default' => DRUPAL_NO_CACHE); + $options['block_hide_empty'] = array('default' => FALSE); $options['allow'] = array( 'contains' => array( @@ -80,11 +80,12 @@ public function execute() { // Prior to this being called, the $view should already be set to this // display, and arguments should be set on the view. $element = $this->view->render(); - if (!empty($this->view->result) || $this->getOption('empty') || !empty($this->view->style_plugin->definition['even empty'])) { + if ($this->outputIsEmpty() && $this->getOption('block_hide_empty') && empty($this->view->style_plugin->definition['even empty'])) { + return array(); + } + else { return $element; } - - return array(); } /** @@ -128,6 +129,12 @@ public function optionsSummary(&$categories, &$options) { 'title' => t('Block caching'), 'value' => $types[$this->getCacheType()], ); + + $options['block_hide_empty'] = array( + 'category' => 'other', + 'title' => t('Hide block if the view output is empty'), + 'value' => $this->getOption('block_hide_empty') ? t('Hide') : t('Show'), + ); } /** @@ -182,6 +189,16 @@ public function buildOptionsForm(&$form, &$form_state) { '#default_value' => $this->getCacheType(), ); break; + case 'block_hide_empty': + $form['#title'] .= t('Block empty settings'); + + $form['block_hide_empty'] = array( + '#title' => t('Hide block if no result/empty text'), + '#type' => 'checkbox', + '#description' => t('Hide the block if there is no result and no empty text and no header/footer which is shown on empty result'), + '#default_value' => $this->getOption('block_hide_empty'), + ); + break; case 'exposed_form_options': $this->view->initHandlers(); if (!$this->usesExposed() && parent::usesExposed()) { @@ -218,6 +235,7 @@ public function submitOptionsForm(&$form, &$form_state) { case 'block_description': case 'block_caching': case 'allow': + case 'block_hide_empty': $this->setOption($form_state['section'], $form_state['values'][$form_state['section']]); break; } diff --git a/core/modules/views/lib/Drupal/views/Plugin/views/area/AreaPluginBase.php b/core/modules/views/lib/Drupal/views/Plugin/views/area/AreaPluginBase.php index 056aeef..2aaef05 100644 --- a/core/modules/views/lib/Drupal/views/Plugin/views/area/AreaPluginBase.php +++ b/core/modules/views/lib/Drupal/views/Plugin/views/area/AreaPluginBase.php @@ -107,6 +107,19 @@ public function preRender(array $results) { public abstract function render($empty = FALSE); /** + * Is the area empty. + * + * This method should be overridden by more complex handlers where the output + * is not static and maybe itself be empty if it's rendered. + * + * @return bool + * Return TRUE if the area is empty, else FALSE. + */ + public function isEmpty() { + return empty($this->options['empty']); + } + + /** * Area handlers shouldn't have groupby. */ public function usesGroupBy() { diff --git a/core/modules/views/lib/Drupal/views/Plugin/views/area/View.php b/core/modules/views/lib/Drupal/views/Plugin/views/area/View.php index 103df0a..8b7f21c 100644 --- a/core/modules/views/lib/Drupal/views/Plugin/views/area/View.php +++ b/core/modules/views/lib/Drupal/views/Plugin/views/area/View.php @@ -18,6 +18,16 @@ */ class View extends AreaPluginBase { + /** + * Stores whether the embedded view is actually empty. + * + * @var bool + */ + protected $isEmpty; + + /** + * {@inheritdoc} + */ protected function defineOptions() { $options = parent::defineOptions(); @@ -77,14 +87,28 @@ public function render($empty = FALSE) { } else { if (!empty($this->options['inherit_arguments']) && !empty($this->view->args)) { - return $view->preview($display_id, $this->view->args); + $output = $view->preview($display_id, $this->view->args); } else { - return $view->preview($display_id); + $output = $view->preview($display_id); } + $this->isEmpty = $view->display_handler->outputIsEmpty(); + return $output; } } return array(); } + /** + * {@inheritdoc} + */ + public function isEmpty() { + if (isset($this->isEmpty)) { + return $this->isEmpty; + } + else { + return parent::isEmpty(); + } + } + } diff --git a/core/modules/views/lib/Drupal/views/Plugin/views/display/DisplayPluginBase.php b/core/modules/views/lib/Drupal/views/Plugin/views/display/DisplayPluginBase.php index 4d04243..21332fd 100644 --- a/core/modules/views/lib/Drupal/views/Plugin/views/display/DisplayPluginBase.php +++ b/core/modules/views/lib/Drupal/views/Plugin/views/display/DisplayPluginBase.php @@ -2699,6 +2699,31 @@ public function isIdentifierUnique($id, $identifier) { return TRUE; } + /** + * Does the view shows anything. + * + * If a view has no result and neither the empty, nor the footer nor the header + * does show anything return FALSE. + * + * @return bool + * Returns TRUE if the output is empty, else FALSE. + */ + public function outputIsEmpty() { + if (!empty($this->view->result)) { + return FALSE; + } + $empty = TRUE; + // Check whether any of the area handlers aren't empty. + $area_types = array('empty', 'footer', 'header'); + foreach ($area_types as $type) { + $handlers = $this->getHandlers($type); + foreach ($handlers as $handler) { + $empty &= $handler->isEmpty(); + } + } + return $empty; + } + /** * Provide the block system with any exposed widget blocks for this display. */ diff --git a/core/modules/views/lib/Drupal/views/Tests/Plugin/DisplayTest.php b/core/modules/views/lib/Drupal/views/Tests/Plugin/DisplayTest.php index 272868c..b52a35e 100644 --- a/core/modules/views/lib/Drupal/views/Tests/Plugin/DisplayTest.php +++ b/core/modules/views/lib/Drupal/views/Tests/Plugin/DisplayTest.php @@ -19,7 +19,7 @@ class DisplayTest extends PluginTestBase { * * @var array */ - public static $testViews = array('test_filter_groups', 'test_get_attach_displays', 'test_view', 'test_display_more', 'test_display_invalid'); + public static $testViews = array('test_filter_groups', 'test_get_attach_displays', 'test_view', 'test_display_more', 'test_display_invalid', 'test_display_empty'); /** * Modules to enable. @@ -273,4 +273,47 @@ public function testInvalidDisplayPlugins() { $this->assertNoBlockAppears($block); } + /** + * Tests the outputIsEmpty method on the display. + */ + public function testOutputIsEmpty() { + $view = views_get_view('test_display_empty'); + $this->executeView($view); + $this->assertTrue(count($view->result) > 0, 'Ensure the result of the view is not empty.'); + $this->assertFalse($view->display_handler->outputIsEmpty(), 'Ensure the view output is marked as not empty.'); + $view->destroy(); + + // Add a filter, so the view result is empty. + $view->setDisplay('default'); + $item = array( + 'table' => 'views_test_data', + 'field' => 'id', + 'id' => 'id', + 'value' => array('value' => 7297) + ); + $view->setItem('default', 'filter', 'id', $item); + $this->executeView($view); + $this->assertFalse(count($view->result), 'Ensure the result of the view is empty.'); + $this->assertFalse($view->display_handler->outputIsEmpty(), 'Ensure the view output is marked as not empty, because the empty text still appears.'); + $view->destroy(); + + // Remove the empty area, but mark the header area to still appear. + $view->removeItem('default', 'empty', 'area'); + $item = $view->getItem('default', 'header', 'area'); + $item['empty'] = TRUE; + $view->setItem('default', 'header', 'area', $item); + $this->executeView($view); + $this->assertFalse(count($view->result), 'Ensure the result of the view is empty.'); + $this->assertFalse($view->display_handler->outputIsEmpty(), 'Ensure the view output is marked as not empty, because the header text still appears.'); + $view->destroy(); + + // Hide the header on empty results. + $item = $view->getItem('default', 'header', 'area'); + $item['empty'] = FALSE; + $view->setItem('default', 'header', 'area', $item); + $this->executeView($view); + $this->assertFalse(count($view->result), 'Ensure the result of the view is empty.'); + $this->assertTrue($view->display_handler->outputIsEmpty(), 'Ensure the view output is marked as empty.'); + } + } diff --git a/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_display_empty.yml b/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_display_empty.yml new file mode 100644 index 0000000..eda6f84 --- /dev/null +++ b/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_display_empty.yml @@ -0,0 +1,44 @@ +base_table: views_test_data +core: '8' +description: '' +status: '1' +display: + default: + display_options: + defaults: + fields: '0' + pager: '0' + pager_options: '0' + sorts: '0' + fields: + id: + field: id + id: id + relationship: none + table: views_test_data + plugin_id: numeric + pager: + options: + offset: '0' + type: none + pager_options: { } + header: + area: + field: area + id: area + table: views + plugin_id: text + empty: + area: + field: area + id: area + table: views + plugin_id: text + display_plugin: default + display_title: Master + id: default + position: '0' +label: '' +langcode: en +id: test_display_empty +tag: ''