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:
parent
1a0e9d9fac
commit
a6b049dd05
538 changed files with 5247 additions and 1594 deletions
|
|
@ -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()) {
|
||||
|
|
|
|||
|
|
@ -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');
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ namespace Drupal\views\Plugin\views\area;
|
|||
*
|
||||
* @ingroup views_area_handlers
|
||||
*
|
||||
* @PluginID("messages")
|
||||
* @ViewsArea("messages")
|
||||
*/
|
||||
class Messages extends AreaPluginBase {
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)) {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -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',
|
||||
|
|
|
|||
|
|
@ -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)) {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ class ResultRow {
|
|||
/**
|
||||
* An incremental number which represents the row in the entire result.
|
||||
*
|
||||
* @var integer
|
||||
* @var int
|
||||
*/
|
||||
public $index;
|
||||
|
||||
|
|
|
|||
44
core/modules/views/src/Tests/Handler/AreaMessagesTest.php
Normal file
44
core/modules/views/src/Tests/Handler/AreaMessagesTest.php
Normal 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.');
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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']);
|
||||
|
|
|
|||
|
|
@ -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',
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ class PluginBaseTest extends KernelTestBase {
|
|||
*/
|
||||
var $testPluginBase;
|
||||
|
||||
public function setUp() {
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
$this->testPluginBase = new TestPluginBase();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
||||
|
|
|
|||
|
|
@ -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',
|
||||
));
|
||||
|
|
|
|||
Reference in a new issue