Update to Drupal 8.0.2. For more information, see https://www.drupal.org/drupal-8.0.2-release-notes

This commit is contained in:
Pantheon Automation 2016-01-06 16:31:26 -08:00 committed by Greg Anderson
parent 1a0e9d9fac
commit a6b049dd05
538 changed files with 5247 additions and 1594 deletions

View file

@ -28,6 +28,9 @@ class ViewsBlock extends ViewsBlockBase {
public function build() {
$this->view->display_handler->preBlockBuild($this);
// We ask ViewExecutable::buildRenderable() to avoid creating a render cache
// entry for the view output by passing FALSE, because we're going to cache
// the whole block instead.
if ($output = $this->view->buildRenderable($this->displayID, [], FALSE)) {
// Override the label to the dynamic title configured in the view.
if (empty($this->configuration['views_label']) && $this->view->getTitle()) {

View file

@ -6,6 +6,7 @@
*/
namespace Drupal\views\Plugin\Block;
use Drupal\Core\Cache\Cache;
/**
* Provides a 'Views Exposed Filter' block.
@ -18,11 +19,20 @@ namespace Drupal\views\Plugin\Block;
*/
class ViewsExposedFilterBlock extends ViewsBlockBase {
/**
* {@inheritdoc}
*/
public function getCacheContexts() {
$contexts = $this->view->display_handler->getCacheMetadata()->getCacheContexts();
return Cache::mergeContexts(parent::getCacheContexts(), $contexts);
}
/**
* {@inheritdoc}
*/
public function build() {
$output = $this->view->display_handler->viewExposedFormBlocks();
// Before returning the block output, convert it to a renderable array with
// contextual links.
$this->addContextualLinks($output, 'exposed_filter');

View file

@ -12,7 +12,7 @@ namespace Drupal\views\Plugin\views\area;
*
* @ingroup views_area_handlers
*
* @PluginID("messages")
* @ViewsArea("messages")
*/
class Messages extends AreaPluginBase {

View file

@ -270,6 +270,10 @@ abstract class PathPluginBase extends DisplayPluginBase implements DisplayRouter
// that parameter conversion options is carried over.
$route->setOptions($route->getOptions() + $original_route->getOptions());
if ($original_route->hasDefault('_title_callback')) {
$route->setDefault('_title_callback', $original_route->getDefault('_title_callback'));
}
// Set the corrected path and the mapping to the route object.
$route->setOption('_view_argument_map', $argument_map);
$route->setPath($path);

View file

@ -359,6 +359,14 @@ abstract class ExposedFormPluginBase extends PluginBase implements CacheableDepe
}
}
// Merge in cache contexts for all exposed filters to prevent display of
// cached forms.
foreach ($this->displayHandler->getHandlers('filter') as $filter_hander) {
if ($filter_hander->isExposed()) {
$contexts = Cache::mergeContexts($contexts, $filter_hander->getCacheContexts());
}
}
return $contexts;
}

View file

@ -242,8 +242,11 @@ class Field extends FieldPluginBase implements CacheableDependencyInterface, Mul
// Go through the list and determine the actual column name from field api.
$fields = array();
$table_mapping = $this->getTableMapping();
$field_definition = $this->getFieldStorageDefinition();
foreach ($options as $column) {
$fields[$column] = $this->getTableMapping()->getFieldColumnName($this->getFieldStorageDefinition(), $column);
$fields[$column] = $table_mapping->getFieldColumnName($field_definition, $column);
}
$this->group_fields = $fields;

View file

@ -86,9 +86,11 @@ abstract class FieldPluginBase extends HandlerBase implements FieldHandlerInterf
public $original_value = NULL;
/**
* @var array
* Stores additional fields which get's added to the query.
* Stores additional fields that get added to the query.
*
* The generated aliases are stored in $aliases.
*
* @var array
*/
var $additional_fields = array();
@ -1384,7 +1386,7 @@ abstract class FieldPluginBase extends HandlerBase implements FieldHandlerInterf
// In that case the original path looks like
// internal:/admin/content/files/usage/{{ fid }}, which will be escaped by
// the toUriString() call above.
$path = preg_replace(['/(\%7B){2}(\%20)*/', '/(\%20)*(\%7D){2}/'], ['{{','}}'], $path);
$path = preg_replace(['/(\%7B){2}(\%20)*/', '/(\%20)*(\%7D){2}/'], ['{{', '}}'], $path);
// Use strip tags as there should never be HTML in the path.
// However, we need to preserve special characters like " that are escaped

View file

@ -138,7 +138,7 @@ class NumericField extends FieldPluginBase {
}
/**
* @inheritdoc
* {@inheritdoc}
*/
public function submitOptionsForm(&$form, FormStateInterface $form_state) {
// Merge plural format options into one string and drop the individual

View file

@ -7,6 +7,7 @@
namespace Drupal\views\Plugin\views\filter;
use Drupal\Core\Database\Query\Condition;
use Drupal\Core\Form\FormStateInterface;
use Drupal\views\Plugin\views\display\DisplayPluginBase;
use Drupal\views\ViewExecutable;
@ -31,6 +32,20 @@ use Drupal\views\ViewExecutable;
*/
class BooleanOperator extends FilterPluginBase {
/**
* The equal query operator.
*
* @var string
*/
const EQUAL = '=';
/**
* The non equal query operator.
*
* @var string
*/
const NOT_EQUAL = '<>';
// exposed filter options
protected $alwaysMultiple = TRUE;
// Don't display empty space where the operator would be.
@ -61,15 +76,17 @@ class BooleanOperator extends FilterPluginBase {
return array(
'=' => array(
'title' => $this->t('Is equal to'),
'method' => 'queryOpBoolean',
'method' => '_queryOperatorBoolean',
'short' => $this->t('='),
'values' => 1,
'query_operator' => static::EQUAL,
),
'!=' => array(
'title' => $this->t('Is not equal to'),
'method' => 'queryOpBoolean',
'method' => '_queryOperatorBoolean',
'short' => $this->t('!='),
'values' => 1,
'query_operator' => static::NOT_EQUAL,
),
);
}
@ -185,7 +202,7 @@ class BooleanOperator extends FilterPluginBase {
// human-readable label based on the current value. The valueOptions
// array is keyed with either 0 or 1, so if the current value is not
// empty, use the label for 1, and if it's empty, use the label for 0.
return $this->valueOptions[!empty($this->value)];
return $this->operator . ' ' . $this->valueOptions[!empty($this->value)];
}
public function defaultExposeOptions() {
@ -204,34 +221,64 @@ class BooleanOperator extends FilterPluginBase {
$info = $this->operators();
if (!empty($info[$this->operator]['method'])) {
call_user_func(array($this, $info[$this->operator]['method']), $field);
call_user_func(array($this, $info[$this->operator]['method']), $field, $info[$this->operator]['query_operator']);
}
}
/**
* Adds a where condition to the query for a boolean value. This function
* remains to prevent breaks in public-facing API's.
*
* @param string $field
* The field name to add the where condition for.
*/
protected function queryOpBoolean($field) {
$this->_queryOperatorBoolean($field, static::EQUAL);
}
/**
* Adds a where condition to the query for a boolean value.
*
* @param string $field
* The field name to add the where condition for.
* @param string $query_operator
* Either static::EQUAL or static::NOT_EQUAL.
*
* @internal
* This method will be removed in 8.1.0 and is here to maintain backwards-
* compatibility in 8.0.x releases.
*/
protected function queryOpBoolean($field) {
protected function _queryOperatorBoolean($field, $query_operator) {
if (empty($this->value)) {
if ($this->accept_null) {
$or = db_or()
->condition($field, 0, '=')
->condition($field, NULL, 'IS NULL');
$this->query->addWhere($this->options['group'], $or);
if ($query_operator == static::EQUAL) {
$condition = (new Condition('OR'))
->condition($field, 0, $query_operator)
->isNull($field);
}
else {
$condition = (new Condition('AND'))
->condition($field, 0, $query_operator)
->isNotNull($field);
}
$this->query->addWhere($this->options['group'], $condition);
}
else {
$this->query->addWhere($this->options['group'], $field, 0, '=');
$this->query->addWhere($this->options['group'], $field, 0, $query_operator);
}
}
else {
if (!empty($this->definition['use_equal'])) {
$this->query->addWhere($this->options['group'], $field, 1, '=');
// Forces an '=' operator instead of a '<>' for performance reasons.
if ($query_operator == static::EQUAL) {
$this->query->addWhere($this->options['group'], $field, 1, static::EQUAL);
}
else {
$this->query->addWhere($this->options['group'], $field, 0, static::EQUAL);
}
}
else {
$this->query->addWhere($this->options['group'], $field, 0, '<>');
$this->query->addWhere($this->options['group'], $field, 1, $query_operator);
}
}
}

View file

@ -38,7 +38,11 @@ class Combine extends StringFilter {
if ($this->view->style_plugin->usesFields()) {
$options = array();
foreach ($this->view->display_handler->getHandlers('field') as $name => $field) {
$options[$name] = $field->adminLabel(TRUE);
// Only allow clickSortable fields. Fields without clickSorting will
// probably break in the Combine filter.
if ($field->clickSortable()) {
$options[$name] = $field->adminLabel(TRUE);
}
}
if ($options) {
$form['fields'] = array(
@ -108,6 +112,13 @@ class Combine extends StringFilter {
$errors[] = $this->t('Field %field set in %filter is not set in this display.', array('%field' => $id, '%filter' => $this->adminLabel()));
break;
}
elseif (!$fields[$id]->clickSortable()) {
// Combined field filter only works with simple fields. If the field is
// not click sortable we can assume it is not a simple field.
// @todo change this check to isComputed. See
// https://www.drupal.org/node/2349465
$errors[] = $this->t('Field %field set in %filter is not usable for this filter type. Combined field filter only works for simple fields.', array('%field' => $fields[$id]->adminLabel(), '%filter' => $this->adminLabel()));
}
}
return $errors;
}

View file

@ -59,8 +59,8 @@ class InOperator extends FilterPluginBase {
* This can use a guard to be used to reduce database hits as much as
* possible.
*
* @return
* Return the stored values in $this->valueOptions if someone expects it.
* @return array|NULL
* The stored values from $this->valueOptions.
*/
public function getValueOptions() {
if (isset($this->valueOptions)) {

View file

@ -69,6 +69,7 @@ class LanguageFilter extends InOperator implements ContainerFactoryPluginInterfa
// lost when there are changes in the language configuration.
$this->valueOptions = $this->listLanguages(LanguageInterface::STATE_ALL | LanguageInterface::STATE_SITE_DEFAULT | PluginBase::INCLUDE_NEGOTIATED, array_keys($this->value));
}
return $this->valueOptions;
}
/**

View file

@ -199,9 +199,10 @@ class NumericFilter extends FilterPluginBase {
if ($which == 'all' || $which == 'minmax') {
$form['value']['min'] = array(
'#type' => 'textfield',
'#title' => !$exposed ? $this->t('Min') : '',
'#title' => !$exposed ? $this->t('Min') : $this->exposedInfo()['label'],
'#size' => 30,
'#default_value' => $this->value['min'],
'#description' => !$exposed ? '' : $this->exposedInfo()['description']
);
$form['value']['max'] = array(
'#type' => 'textfield',

View file

@ -134,6 +134,9 @@ abstract class StylePluginBase extends PluginBase {
}
/**
* {@inheritdoc}
*/
public function destroy() {
parent::destroy();
@ -255,6 +258,9 @@ abstract class StylePluginBase extends PluginBase {
return !empty($this->definition['even empty']);
}
/**
* {@inheritdoc}
*/
protected function defineOptions() {
$options = parent::defineOptions();
$options['grouping'] = array('default' => array());
@ -267,6 +273,9 @@ abstract class StylePluginBase extends PluginBase {
return $options;
}
/**
* {@inheritdoc}
*/
public function buildOptionsForm(&$form, FormStateInterface $form_state) {
parent::buildOptionsForm($form, $form_state);
// Only fields-based views can handle grouping. Style plugins can also exclude
@ -358,6 +367,9 @@ abstract class StylePluginBase extends PluginBase {
}
}
/**
* {@inheritdoc}
*/
public function validateOptionsForm(&$form, FormStateInterface $form_state) {
// Don't run validation on style plugins without the grouping setting.
if ($form_state->hasValue(array('style_options', 'grouping'))) {
@ -783,6 +795,9 @@ abstract class StylePluginBase extends PluginBase {
return $value;
}
/**
* {@inheritdoc}
*/
public function validate() {
$errors = parent::validate();
@ -801,6 +816,9 @@ abstract class StylePluginBase extends PluginBase {
return $errors;
}
/**
* {@inheritdoc}
*/
public function query() {
parent::query();
if (isset($this->view->rowPlugin)) {

View file

@ -1249,7 +1249,7 @@ abstract class WizardPluginBase extends PluginBase implements WizardInterface {
}
/**
* {@inheritDoc}
* {@inheritdoc}
*/
public function createView(array $form, FormStateInterface $form_state) {
$view = $this->retrieveValidatedView($form, $form_state);

View file

@ -29,7 +29,7 @@ class ResultRow {
/**
* An incremental number which represents the row in the entire result.
*
* @var integer
* @var int
*/
public $index;

View file

@ -0,0 +1,44 @@
<?php
/**
* @file
* Contains \Drupal\views\Tests\Handler\AreaMessagesTest.
*/
namespace Drupal\views\Tests\Handler;
use Drupal\views\Tests\ViewKernelTestBase;
use Drupal\views\Views;
/**
* Tests the messages area handler.
*
* @group views
* @see \Drupal\views\Plugin\views\area\Messages
*/
class AreaMessagesTest extends ViewKernelTestBase {
/**
* Views used by this test.
*
* @var array
*/
public static $testViews = array('test_area_messages');
/**
* Tests the messages area handler.
*/
public function testMessageText() {
drupal_set_message('My drupal set message.');
$view = Views::getView('test_area_messages');
$view->setDisplay('default');
$this->executeView($view);
$output = $view->render();
$output = \Drupal::service('renderer')->renderRoot($output);
$this->setRawContent($output);
$this->assertText('My drupal set message.');
}
}

View file

@ -32,7 +32,7 @@ class FieldDropButtonTest extends HandlerTestBase {
/**
* {@inheritdoc}
*/
public function setUp() {
protected function setUp() {
parent::setUp();
$admin_user = $this->drupalCreateUser(['access content overview', 'administer nodes', 'bypass node access']);

View file

@ -95,6 +95,30 @@ class FilterBooleanOperatorTest extends ViewKernelTestBase {
$this->assertEqual(3, count($view->result));
$this->assertIdenticalResultset($view, $expected_result, $this->columnMap);
$view->destroy();
$view->setDisplay();
// Testing the same scenario but using the reverse status and operation.
$view->displayHandlers->get('default')->overrideOption('filters', array(
'status' => array(
'id' => 'status',
'field' => 'status',
'table' => 'views_test_data',
'value' => 0,
'operator' => '!=',
),
));
$this->executeView($view);
$expected_result = array(
array('id' => 1),
array('id' => 3),
array('id' => 5),
);
$this->assertEqual(3, count($view->result));
$this->assertIdenticalResultset($view, $expected_result, $this->columnMap);
}
/**
@ -133,6 +157,24 @@ class FilterBooleanOperatorTest extends ViewKernelTestBase {
$this->assertEqual(2, count($view->result));
$this->assertIdenticalResultset($view, $expected_result, $this->columnMap);
$view->destroy();
// Expecting the same results as for ['status' => 1].
$view->setExposedInput(['status' => 3]);
$view->setDisplay();
$view->displayHandlers->get('default')->overrideOption('filters', $filters);
$this->executeView($view);
$expected_result = array(
array('id' => 1),
array('id' => 3),
array('id' => 5),
);
$this->assertEqual(3, count($view->result));
$this->assertIdenticalResultset($view, $expected_result, $this->columnMap);
}
/**
@ -169,6 +211,13 @@ class FilterBooleanOperatorTest extends ViewKernelTestBase {
'operator' => '=',
'value' => '0',
),
// This group should return the same results as group 1, because it
// is the negation of group 2.
3 => array(
'title' => 'Active (reverse)',
'operator' => '!=',
'value' => '0',
),
),
),
),

View file

@ -151,6 +151,7 @@ class ExposedFormTest extends ViewTestBase {
* Tests the exposed block functionality.
*/
public function testExposedBlock() {
$this->drupalCreateContentType(['type' => 'page']);
$view = Views::getView('test_exposed_block');
$view->setDisplay('page_1');
$block = $this->drupalPlaceBlock('views_exposed_filter_block:test_exposed_block-page_1');
@ -167,6 +168,15 @@ class ExposedFormTest extends ViewTestBase {
// Test there is only one views exposed form on the page.
$elements = $this->xpath('//form[@id=:id]', array(':id' => $this->getExpectedExposedFormId($view)));
$this->assertEqual(count($elements), 1, 'One exposed form block found.');
// Test that the correct option is selected after form submission.
$this->assertCacheContext('url');
$this->assertOptionSelected('edit-type', 'All');
foreach (['All', 'article', 'page'] as $argument) {
$this->drupalGet('test_exposed_block', ['query' => ['type' => $argument]]);
$this->assertCacheContext('url');
$this->assertOptionSelected('edit-type', $argument);
}
}
/**

View file

@ -24,7 +24,7 @@ class PluginBaseTest extends KernelTestBase {
*/
var $testPluginBase;
public function setUp() {
protected function setUp() {
parent::setUp();
$this->testPluginBase = new TestPluginBase();
}

View file

@ -136,4 +136,99 @@ class StyleTableTest extends PluginTestBase {
$this->assertTrue(count($result), 'Ensure that the baby\'s age is shown');
}
/**
* Test that empty columns are hidden when empty_column is set.
*/
public function testEmptyColumn() {
// Empty the 'job' data.
\Drupal::database()->update('views_test_data')
->fields(['job' => ''])
->execute();
$this->drupalGet('test-table');
// Test that only one of the job columns still shows.
$result = $this->xpath('//thead/tr/th/a[text()="Job"]');
$this->assertEqual(count($result), 1, 'Ensure that empty column header is hidden.');
$result = $this->xpath('//tbody/tr/td[contains(concat(" ", @class, " "), " views-field-job-1 ")]');
$this->assertEqual(count($result), 0, 'Ensure the empty table cells are hidden.');
}
/**
* Tests grouping by a field.
*/
public function testGrouping() {
/** @var \Drupal\views\ViewEntityInterface $view */
$view = \Drupal::entityTypeManager()->getStorage('view')->load('test_table');
// Get a reference to the display configuration so we can alter some
// specific style options.
$display = &$view->getDisplay('default');
// Set job as the grouping field.
$display['display_options']['style']['options']['grouping'][0] = array(
'field' => 'job',
'rendered' => TRUE,
'rendered_strip' => FALSE,
);
// Clear the caption text, the rendered job field will be used as a caption.
$display['display_options']['style']['options']['caption'] = '';
$display['display_options']['style']['options']['summary'] = '';
$display['display_options']['style']['options']['description'] = '';
$view->save();
// Add a record containing unsafe markup to be sure it's filtered out.
$unsafe_markup = '<script>alert("Rapper");</script>';
$unsafe_markup_data = array(
'name' => 'Marshall',
'age' => 42,
'job' => $unsafe_markup,
'created' => gmmktime(0, 0, 0, 2, 15, 2001),
'status' => 1,
);
$database = $this->container->get('database');
$database->insert('views_test_data')
->fields(array_keys($unsafe_markup_data))
->values($unsafe_markup_data)
->execute();
$this->drupalGet('test-table');
$expected_captions = array(
'Job: Speaker',
'Job: Songwriter',
'Job: Drummer',
'Job: Singer',
'Job: ' . $unsafe_markup,
);
// Ensure that we don't find the caption containing unsafe markup.
$this->assertNoRaw($unsafe_markup, "Didn't find caption containing unsafe markup.");
// Ensure that all expected captions are found.
foreach ($expected_captions as $raw_caption) {
$this->assertEscaped($raw_caption);
}
$display = &$view->getDisplay('default');
// Remove the label from the grouping field.
$display['display_options']['fields']['job']['label'] = '';
$view->save();
$this->drupalGet('test-table');
$expected_captions = array(
'Speaker',
'Songwriter',
'Drummer',
'Singer',
$unsafe_markup,
);
// Ensure that we don't find the caption containing unsafe markup.
$this->assertNoRaw($unsafe_markup, "Didn't find caption containing unsafe markup.");
// Ensure that all expected captions are found.
foreach ($expected_captions as $raw_caption) {
$this->assertEscaped($raw_caption);
}
}
}

View file

@ -130,7 +130,7 @@ trait ViewResultAssertionTrait {
$this->verbose('<pre style="white-space: pre-wrap;">'
. "\n\nQuery:\n" . $view->build_info['query']
. "\n\nQuery arguments:\n" . var_export($view->build_info['query_args'], TRUE)
. "\n\nQuery arguments:\n" . var_export($view->build_info['query']->getArguments(), TRUE)
. "\n\nActual result:\n" . var_export($result, TRUE)
. "\n\nExpected result:\n" . var_export($expected_result, TRUE));

View file

@ -77,7 +77,7 @@ class TaggedWithTest extends WizardTestBase {
$this->nodeTypeWithoutTags = $this->drupalCreateContentType();
// Create the vocabulary for the tag field.
$this->tagVocabulary = entity_create('taxonomy_vocabulary', array(
$this->tagVocabulary = entity_create('taxonomy_vocabulary', array(
'name' => 'Views testing tags',
'vid' => 'views_testing_tags',
));

View file

@ -0,0 +1,58 @@
langcode: en
status: true
dependencies: { }
id: test_area_messages
label: ''
module: views
description: ''
tag: ''
base_table: views_test_data
base_field: nid
core: '8'
display:
default:
display_options:
defaults:
fields: false
pager: false
sorts: false
fields:
id:
field: id
id: id
relationship: none
table: views_test_data
plugin_id: numeric
pager:
options:
offset: 0
type: none
sorts:
id:
field: id
id: id
order: ASC
relationship: none
table: views_test_data
plugin_id: numeric
empty:
title:
field: title
id: title
table: views
plugin_id: title
title: test_title_empty
header:
messages:
id: messages
table: views
field: messages
relationship: none
group_type: group
admin_label: ''
empty: true
plugin_id: messages
display_plugin: default
display_title: Master
id: default
position: 0

View file

@ -0,0 +1,23 @@
langcode: en
status: true
dependencies:
module:
- user
id: test_preview_error
label: test_preview_error
module: views
description: ''
tag: ''
base_table: views_test_data
base_field: id
core: 8.x
display:
default:
display_plugin: default
id: default
display_title: Master
position: null
display_options:
row:
type: fields
fields: { }

View file

@ -108,7 +108,7 @@ display:
default_sort_order: asc
align: ''
separator: ''
empty_column: false
empty_column: true
responsive: ''
default: id
empty_table: true

View file

@ -135,7 +135,7 @@ class ResultTest extends UnitTestCase {
$this->view->pager = $pager;
$this->view->style_plugin = new \stdClass();
$this->view->total_rows = 100;
$this->view->result = array(1,2,3,4,5);
$this->view->result = array(1, 2, 3, 4, 5);
}
}

View file

@ -260,6 +260,44 @@ class PathPluginBaseTest extends UnitTestCase {
$this->assertSame($collection->get('test_route_2'), $route_2);
}
/**
* Tests the alter route method with preexisting title callback.
*/
public function testAlterRouteWithAlterCallback() {
$collection = new RouteCollection();
$collection->add('test_route', new Route('test_route', array('_controller' => 'Drupal\Tests\Core\Controller\TestController::content', '_title_callback' => '\Drupal\Tests\views\Unit\Plugin\display\TestController::testTitle')));
$route_2 = new Route('test_route/example', array('_controller' => 'Drupal\Tests\Core\Controller\TestController::content'));
$collection->add('test_route_2', $route_2);
list($view) = $this->setupViewExecutableAccessPlugin();
$display = array();
$display['display_plugin'] = 'page';
$display['id'] = 'page_1';
$display['display_options'] = array(
'path' => 'test_route',
);
$this->pathPlugin->initDisplay($view, $display);
$view_route_names = $this->pathPlugin->alterRoutes($collection);
$this->assertEquals(array('test_id.page_1' => 'test_route'), $view_route_names);
// Ensure that the test_route is overridden.
$route = $collection->get('test_route');
$this->assertTrue($route instanceof Route);
$this->assertEquals('test_id', $route->getDefault('view_id'));
$this->assertEquals('\Drupal\Tests\views\Unit\Plugin\display\TestController::testTitle', $route->getDefault('_title_callback'));
$this->assertEquals('page_1', $route->getDefault('display_id'));
$this->assertEquals('my views title', $route->getDefault('_title'));
// Ensure that the test_route_2 is not overridden.
$route = $collection->get('test_route_2');
$this->assertTrue($route instanceof Route);
$this->assertFalse($route->hasDefault('view_id'));
$this->assertFalse($route->hasDefault('display_id'));
$this->assertSame($collection->get('test_route_2'), $route_2);
}
/**
* Tests the collectRoutes method with a path containing named parameters.
*
@ -457,3 +495,20 @@ class PathPluginBaseTest extends UnitTestCase {
}
}
/**
* A page controller for use by tests in this file.
*/
class TestController {
/**
* A page title callback.
*
* @return string
* The page title.
*/
public function testTitle() {
return 'Test title';
}
}

View file

@ -43,7 +43,7 @@ class EntityOperationsUnitTest extends UnitTestCase {
*
* @covers ::__construct
*/
public function setUp() {
protected function setUp() {
$this->entityManager = $this->getMock('\Drupal\Core\Entity\EntityManagerInterface');
$this->languageManager = $this->getMock('\Drupal\Core\Language\LanguageManagerInterface');

View file

@ -46,7 +46,7 @@ class ViewsHandlerManagerTest extends UnitTestCase {
/**
* {@inheritdoc}
*/
public function setUp() {
protected function setUp() {
$this->viewsData = $this->getMockBuilder('Drupal\views\ViewsData')
->disableOriginalConstructor()
->getMock();

View file

@ -8,6 +8,7 @@
use Drupal\Component\Utility\Html;
use Drupal\Component\Utility\SafeMarkup;
use Drupal\Core\Database\Query\AlterableInterface;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Render\Element;
use Drupal\Core\Routing\RouteMatchInterface;
@ -804,3 +805,18 @@ function views_local_tasks_alter(&$local_tasks) {
$local_task = ViewsLocalTask::create($container, 'views_view');
$local_task->alterLocalTasks($local_tasks);
}
/**
* Implements hook_ENTITY_TYPE_delete().
*/
function views_view_delete(EntityInterface $entity) {
// Rebuild the routes in case there is a routed display.
$executable = Views::executableFactory()->get($entity);
$executable->initDisplay();
foreach ($executable->displayHandlers as $display) {
if ($display->getRoutedDisplay()) {
\Drupal::service('router.builder')->setRebuildNeeded();
break;
}
}
}

View file

@ -547,18 +547,18 @@ function template_preprocess_views_view_table(&$variables) {
$column_reference['attributes'] = new Attribute($column_reference['attributes']);
}
// Remove columns if the option is hide empty column is checked and the
// field is not empty.
// Remove columns if the "empty_column" option is checked and the
// field is empty.
if (!empty($options['info'][$field]['empty_column'])) {
$empty = TRUE;
foreach ($variables['rows'] as $columns) {
$empty &= empty($columns[$column]);
$empty &= empty($columns['columns'][$column]['content']);
}
if ($empty) {
foreach ($variables['rows'] as &$column_items) {
unset($column_items[$column]);
unset($variables['header'][$column]);
unset($column_items['columns'][$column]);
}
unset($variables['header'][$column]);
}
}
}
@ -598,6 +598,10 @@ function template_preprocess_views_view_table(&$variables) {
$variables['caption'] = ['#markup' => $handler->options['caption']];
$variables['caption_needed'] = TRUE;
}
elseif (!empty($variables['title'])) {
$variables['caption'] = ['#markup' => $variables['title']];
$variables['caption_needed'] = TRUE;
}
else {
$variables['caption'] = '';
$variables['caption_needed'] = FALSE;