Update to Drupal 8.2.0. For more information, see https://www.drupal.org/project/drupal/releases/8.2.0

This commit is contained in:
Pantheon Automation 2016-10-06 15:16:20 -07:00 committed by Greg Anderson
parent 2f563ab520
commit f1c8716f57
1732 changed files with 52334 additions and 11780 deletions

View file

@ -123,7 +123,7 @@ views.filter.group_item.numeric:
# Schema for the views filter value.
views.filter_value.boolean:
type: boolean
type: string
views.filter_value.combine:
type: string

View file

@ -5,6 +5,7 @@ namespace Drupal\views\Annotation;
/**
* Defines a Plugin annotation object for views exposed form plugins.
*
* @see \Drupal\views\Plugin\views\exposed_form\ExposedFormPluginInterface
* @see \Drupal\views\Plugin\views\exposed_form\ExposedFormPluginBase
*
* @ingroup views_exposed_form_plugins

View file

@ -26,7 +26,7 @@ class DisplayPluginCollection extends DefaultLazyPluginCollection {
/**
* Constructs a DisplayPluginCollection object.
*
* @param \Drupal\views\ViewExecutable
* @param \Drupal\views\ViewExecutable $view
* The view which has this displays attached.
* @param \Drupal\Component\Plugin\PluginManagerInterface $manager
* The manager to be used for instantiating plugins.

View file

@ -5,6 +5,7 @@ namespace Drupal\views\Form;
use Drupal\Component\Utility\Html;
use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Render\Element\Checkboxes;
use Drupal\Core\Url;
use Drupal\views\ExposedFormCache;
use Symfony\Component\DependencyInjection\ContainerInterface;
@ -114,7 +115,7 @@ class ViewsExposedForm extends FormBase {
$form['#theme'] = $view->buildThemeFunctions('views_exposed_form');
$form['#id'] = Html::cleanCssIdentifier('views_exposed_form-' . $view->storage->id() . '-' . $display['id']);
/** @var \Drupal\views\Plugin\views\exposed_form\ExposedFormPluginBase $exposed_form_plugin */
/** @var \Drupal\views\Plugin\views\exposed_form\ExposedFormPluginInterface $exposed_form_plugin */
$exposed_form_plugin = $view->display_handler->getPlugin('exposed_form');
$exposed_form_plugin->exposedFormAlter($form, $form_state);
@ -137,7 +138,7 @@ class ViewsExposedForm extends FormBase {
$handlers[$key]->validateExposed($form, $form_state);
}
}
/** @var \Drupal\views\Plugin\views\exposed_form\ExposedFormPluginBase $exposed_form_plugin */
/** @var \Drupal\views\Plugin\views\exposed_form\ExposedFormPluginInterface $exposed_form_plugin */
$exposed_form_plugin = $view->display_handler->getPlugin('exposed_form');
$exposed_form_plugin->exposedFormValidate($form, $form_state);
}
@ -146,26 +147,46 @@ class ViewsExposedForm extends FormBase {
* {@inheritdoc}
*/
public function submitForm(array &$form, FormStateInterface $form_state) {
// Form input keys that will not be included in $view->exposed_raw_data.
$exclude = array('submit', 'form_build_id', 'form_id', 'form_token', 'exposed_form_plugin', 'reset');
$values = $form_state->getValues();
foreach (array('field', 'filter') as $type) {
/** @var \Drupal\views\Plugin\views\ViewsHandlerInterface[] $handlers */
$handlers = &$form_state->get('view')->$type;
foreach ($handlers as $key => $info) {
$handlers[$key]->submitExposed($form, $form_state);
if ($handlers[$key]->acceptExposedInput($values)) {
$handlers[$key]->submitExposed($form, $form_state);
}
else {
// The input from the form did not validate, exclude it from the
// stored raw data.
$exclude[] = $key;
}
}
}
$view = $form_state->get('view');
$view->exposed_data = $form_state->getValues();
$view->exposed_data = $values;
$view->exposed_raw_input = [];
$exclude = array('submit', 'form_build_id', 'form_id', 'form_token', 'exposed_form_plugin', 'reset');
/** @var \Drupal\views\Plugin\views\exposed_form\ExposedFormPluginBase $exposed_form_plugin */
$exposed_form_plugin = $view->display_handler->getPlugin('exposed_form');
$exposed_form_plugin->exposedFormSubmit($form, $form_state, $exclude);
foreach ($form_state->getValues() as $key => $value) {
if (!in_array($key, $exclude)) {
$view->exposed_raw_input[$key] = $value;
foreach ($values as $key => $value) {
if (!empty($key) && !in_array($key, $exclude)) {
if (is_array($value)) {
// Handle checkboxes, we only want to include the checked options.
// @todo: revisit the need for this when
// https://www.drupal.org/node/342316 is resolved.
$checked = Checkboxes::getCheckedCheckboxes($value);
foreach ($checked as $option_id) {
$view->exposed_raw_input[$option_id] = $value[$option_id];
}
}
else {
$view->exposed_raw_input[$key] = $value;
}
}
}
}

View file

@ -58,7 +58,7 @@ abstract class AccessPluginBase extends PluginBase {
* @param \Drupal\Core\Session\AccountInterface $account
* The user who wants to access this view.
*
* @return TRUE
* @return bool
* Returns whether the user has access to the view.
*/
abstract public function access(AccountInterface $account);

View file

@ -115,7 +115,7 @@ class Entity extends TokenizeAreaPluginBase {
$target = $target_entity->id();
}
}
$form['target'] = [
$form['target'] = [
'#title' => $this->t('@entity_type_label ID', ['@entity_type_label' => $label]),
'#type' => 'textfield',
'#default_value' => $target,

View file

@ -28,37 +28,37 @@ class View extends AreaPluginBase {
*
* @var \Drupal\Core\Entity\EntityStorageInterface
*/
protected $viewStorage;
protected $viewStorage;
/**
* Constructs a View object.
*
* @param array $configuration
* A configuration array containing information about the plugin instance.
* @param string $plugin_id
* The plugin_id for the plugin instance.
* @param mixed $plugin_definition
* The plugin implementation definition.
* @param \Drupal\Core\Entity\EntityStorageInterface $view_storage
* The view storage.
*/
public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityStorageInterface $view_storage) {
parent::__construct($configuration, $plugin_id, $plugin_definition);
/**
* Constructs a View object.
*
* @param array $configuration
* A configuration array containing information about the plugin instance.
* @param string $plugin_id
* The plugin_id for the plugin instance.
* @param mixed $plugin_definition
* The plugin implementation definition.
* @param \Drupal\Core\Entity\EntityStorageInterface $view_storage
* The view storage.
*/
public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityStorageInterface $view_storage) {
parent::__construct($configuration, $plugin_id, $plugin_definition);
$this->viewStorage = $view_storage;
}
$this->viewStorage = $view_storage;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
return new static(
$configuration,
$plugin_id,
$plugin_definition,
$container->get('entity.manager')->getStorage('view')
);
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
return new static(
$configuration,
$plugin_id,
$plugin_definition,
$container->get('entity.manager')->getStorage('view')
);
}
/**
* {@inheritdoc}

View file

@ -346,11 +346,11 @@ class Block extends DisplayPluginBase {
* Block views use exposed widgets only if AJAX is set.
*/
public function usesExposed() {
if ($this->ajaxEnabled()) {
return parent::usesExposed();
}
return FALSE;
if ($this->ajaxEnabled()) {
return parent::usesExposed();
}
return FALSE;
}
/**
* {@inheritdoc}

View file

@ -37,7 +37,7 @@ abstract class DisplayPluginBase extends PluginBase implements DisplayPluginInte
*
* @var \Drupal\views\Plugin\views\ViewsHandlerInterface[]
*/
public $handlers = [];
public $handlers = [];
/**
* An array of instantiated plugins used in this display.
@ -1051,9 +1051,9 @@ abstract class DisplayPluginBase extends PluginBase implements DisplayPluginInte
if (!isset($tokens["%$count"])) {
$tokens["%$count"] = '';
}
// Use strip tags as there should never be HTML in the path.
// However, we need to preserve special characters like " that
// were encoded by \Drupal\Component\Utility\Html::escape().
// Use strip tags as there should never be HTML in the path.
// However, we need to preserve special characters like " that
// were encoded by \Drupal\Component\Utility\Html::escape().
$tokens["!$count"] = isset($this->view->args[$count - 1]) ? strip_tags(Html::decodeEntities($this->view->args[$count - 1])) : '';
}
@ -1339,6 +1339,7 @@ abstract class DisplayPluginBase extends PluginBase implements DisplayPluginInte
);
}
/** @var \Drupal\views\Plugin\views\exposed_form\ExposedFormPluginInterface $exposed_form_plugin */
$exposed_form_plugin = $this->getPlugin('exposed_form');
if (!$exposed_form_plugin) {
// Default to the no cache control plugin.
@ -2235,7 +2236,7 @@ abstract class DisplayPluginBase extends PluginBase implements DisplayPluginInte
}
$plugin = $this->getPlugin('access');
/** @var \Drupal\views\Plugin\views\access\AccessPluginBase $plugin */
/** @var \Drupal\views\Plugin\views\access\AccessPluginBase $plugin */
if ($plugin) {
return $plugin->access($account);
}
@ -2254,6 +2255,7 @@ abstract class DisplayPluginBase extends PluginBase implements DisplayPluginInte
}
$this->view->initHandlers();
if ($this->usesExposed()) {
/** @var \Drupal\views\Plugin\views\exposed_form\ExposedFormPluginInterface $exposed_form */
$exposed_form = $this->getPlugin('exposed_form');
$exposed_form->preExecute();
}
@ -2550,6 +2552,7 @@ abstract class DisplayPluginBase extends PluginBase implements DisplayPluginInte
$this->view->initHandlers();
if ($this->usesExposed() && $this->getOption('exposed_block')) {
/** @var \Drupal\views\Plugin\views\exposed_form\ExposedFormPluginInterface $exposed_form */
$exposed_form = $this->getPlugin('exposed_form');
return $exposed_form->renderExposedForm(TRUE);
}

View file

@ -233,7 +233,7 @@ interface DisplayPluginInterface {
* block display links to a page display, the page display will be returned
* in both cases.
*
* @return \Drupal\views\Plugin\views\display\DisplayRouterInterface|NULL
* @return \Drupal\views\Plugin\views\display\DisplayRouterInterface|null
*/
public function getRoutedDisplay();

View file

@ -294,7 +294,7 @@ class Page extends PathPluginBase {
'#title' => $this->t('Show as expanded'),
'#type' => 'checkbox',
'#default_value' => !empty($menu['expanded']),
'#description' => $this->t('If selected and this menu link has children, the menu will always appear expanded. '),
'#description' => $this->t('If selected and this menu link has children, the menu will always appear expanded.'),
];
// Only display the parent selector if Menu UI module is enabled.
@ -520,7 +520,7 @@ class Page extends PathPluginBase {
public function getPagerText() {
return array(
'items per page title' => $this->t('Items per page'),
'items per page description' => $this->t('The number of items to display per page. Enter 0 for no limit.')
'items per page description' => $this->t('Enter 0 for no limit.')
);
}

View file

@ -9,32 +9,21 @@ use Drupal\Core\Form\FormState;
use Drupal\Core\Form\FormStateInterface;
use Drupal\views\Plugin\views\PluginBase;
/**
* @defgroup views_exposed_form_plugins Views exposed form plugins
* @{
* Plugins that handle validation, submission, and rendering of exposed forms.
*
* Exposed forms are used for filters, sorts, and pager settings that are
* exposed to site visitors. Exposed form plugins handle the rendering,
* validation, and submission of exposed forms, and may add additional form
* elements.
*
* Exposed form plugins extend
* \Drupal\views\Plugin\views\exposed_form\ExposedFormPluginBase. They must be
* annotated with \Drupal\views\Annotation\ViewsExposedForm annotation,
* and they must be in namespace directory Plugin\views\exposed_form.
*/
/**
* Base class for Views exposed filter form plugins.
*
* @ingroup views_exposed_form_plugins
*/
abstract class ExposedFormPluginBase extends PluginBase implements CacheableDependencyInterface {
abstract class ExposedFormPluginBase extends PluginBase implements CacheableDependencyInterface, ExposedFormPluginInterface {
/**
* {@inheritdoc}
*/
protected $usesOptions = TRUE;
/**
* {@inheritdoc}
*/
protected function defineOptions() {
$options = parent::defineOptions();
$options['submit_button'] = array('default' => $this->t('Apply'));
@ -47,6 +36,9 @@ abstract class ExposedFormPluginBase extends PluginBase implements CacheableDepe
return $options;
}
/**
* {@inheritdoc}
*/
public function buildOptionsForm(&$form, FormStateInterface $form_state) {
parent::buildOptionsForm($form, $form_state);
$form['submit_button'] = array(
@ -115,11 +107,7 @@ abstract class ExposedFormPluginBase extends PluginBase implements CacheableDepe
}
/**
* Render the exposed filter form.
*
* This actually does more than that; because it's using FAPI, the form will
* also assign data to the appropriate handlers for use in building the
* query.
* {@inheritdoc}
*/
public function renderExposedForm($block = FALSE) {
// Deal with any exposed filters we may have, before building.
@ -154,6 +142,9 @@ abstract class ExposedFormPluginBase extends PluginBase implements CacheableDepe
}
}
/**
* {@inheritdoc}
*/
public function query() {
$view = $this->view;
$exposed_data = isset($view->exposed_data) ? $view->exposed_data : array();
@ -179,21 +170,28 @@ abstract class ExposedFormPluginBase extends PluginBase implements CacheableDepe
}
}
/**
* {@inheritdoc}
*/
public function preRender($values) { }
/**
* {@inheritdoc}
*/
public function postRender(&$output) { }
/**
* {@inheritdoc}
*/
public function preExecute() { }
/**
* {@inheritdoc}
*/
public function postExecute() { }
/**
* Alters the view exposed form.
*
* @param $form
* The form build array. Passed by reference.
* @param $form_state
* The form state. Passed by reference.
* {@inheritdoc}
*/
public function exposedFormAlter(&$form, FormStateInterface $form_state) {
if (!empty($this->options['submit_button'])) {
@ -273,6 +271,9 @@ abstract class ExposedFormPluginBase extends PluginBase implements CacheableDepe
}
}
/**
* {@inheritdoc}
*/
public function exposedFormValidate(&$form, FormStateInterface $form_state) {
if ($pager_plugin = $form_state->get('pager_plugin')) {
$pager_plugin->exposedFormValidate($form, $form_state);
@ -280,15 +281,7 @@ abstract class ExposedFormPluginBase extends PluginBase implements CacheableDepe
}
/**
* This function is executed when exposed form is submitted.
*
* @param $form
* Nested array of form elements that comprise the form.
* @param $form_state
* The current state of the form.
* @param $exclude
* Nested array of keys to exclude of insert into
* $view->exposed_raw_input
* {@inheritdoc}
*/
public function exposedFormSubmit(&$form, FormStateInterface $form_state, &$exclude) {
if (!$form_state->isValueEmpty('op') && $form_state->getValue('op') == $this->options['reset_button_label']) {
@ -300,6 +293,17 @@ abstract class ExposedFormPluginBase extends PluginBase implements CacheableDepe
}
}
/**
* Resets all the states of the exposed form.
*
* This method is called when the "Reset" button is triggered. Clears
* user inputs, stored session, and the form state.
*
* @param array $form
* An associative array containing the structure of the form.
* @param \Drupal\Core\Form\FormStateInterface $form_state
* The current state of the form.
*/
public function resetForm(&$form, FormStateInterface $form_state) {
// _SESSION is not defined for users who are not logged in.
@ -373,7 +377,3 @@ abstract class ExposedFormPluginBase extends PluginBase implements CacheableDepe
}
}
/**
* @}
*/

View file

@ -0,0 +1,153 @@
<?php
namespace Drupal\views\Plugin\views\exposed_form;
use Drupal\Core\Form\FormStateInterface;
use Drupal\views\Plugin\views\ViewsPluginInterface;
/**
* @defgroup views_exposed_form_plugins Views exposed form plugins
* @{
* Plugins that handle validation, submission, and rendering of exposed forms.
*
* Exposed forms are used for filters, sorts, and pager settings that are
* exposed to site visitors. Exposed form plugins handle the rendering,
* validation, and submission of exposed forms, and may add additional form
* elements.
*
* To define a Exposed Form Plugin in a module you need to:
* - Implement
* \Drupal\views\Plugin\views\exposed_form\ExposedFormPluginInterface.
* - Usually you will want to extend the
* \Drupal\views\Plugin\views\exposed_form\ExposedFormPluginBase class.
* - Exposed form plugins are annotated with
* \Drupal\views\Annotation\ViewsExposedForm annotation. See the
* @link annotation Annotations topic @endlink for more information about
* annotations.
* - They must be in namespace directory Plugin\views\exposed_form.
*/
/**
* Interface for exposed filter form plugins.
*
* Exposed form plugins handle the rendering, validation, and submission
* of exposed forms, and may add additional form elements. These plugins can
* also alter the view query. See
* \Drupal\views\Plugin\views\exposed_form\InputRequired as an example of
* that functionality.
*
* @see \Drupal\views\Annotation\ViewsExposedForm
* @see \Drupal\views\Plugin\views\exposed_form\ExposedFormPluginBase
*/
interface ExposedFormPluginInterface extends ViewsPluginInterface {
/**
* Renders the exposed form.
*
* This method iterates over each handler configured to expose widgets
* to the end user and attach those widgets to the exposed form.
*
* @param bool $block
* (optional) TRUE if the exposed form is being rendered as part of a
* block; FALSE (default) if not.
*
* @return array
* Form build array. This method returns an empty array if the form is
* being rendered as a block.
*
* @see \Drupal\views\ViewExecutable::build()
*/
public function renderExposedForm($block = FALSE);
/**
* Runs before the view is rendered.
*
* Implement if your exposed form needs to run code before the view is
* rendered.
*
* @param \Drupal\views\ResultRow[] $values
* An array of all ResultRow objects returned from the query.
*
* @see \Drupal\views\ViewExecutable::render()
*/
public function preRender($values);
/**
* Runs after the view has been rendered.
*
* Implement if your exposed form needs to run code after the view is
* rendered.
*
* @param string $output
* The rendered output of the view display.
*
* @see \Drupal\views\ViewExecutable::render()
*/
public function postRender(&$output);
/**
* Runs before the view has been executed.
*
* Implement if your exposed form needs to run code before query execution.
*
* @see \Drupal\views\Plugin\views\display\DisplayPluginBase::preExecute()
*/
public function preExecute();
/**
* Runs after the view has been executed.
*
* Implement if your exposed form needs to run code after query execution.
*/
public function postExecute();
/**
* Alters the exposed form.
*
* The exposed form is built by calling the renderExposedForm() method on
* this class, and then letting each exposed filter and sort handler add
* widgets to the form. After that is finished, this method is called to
* let the class alter the finished form.
*
* @param array $form
* An associative array containing the structure of the form.
* @param \Drupal\Core\Form\FormStateInterface $form_state
* The current state of the form.
*
* @see \Drupal\views\Plugin\views\exposed_form\ExposedFormPluginInterface::renderExposedForm()
* @see \Drupal\views\Form\ViewsExposedForm::buildForm()
*/
public function exposedFormAlter(&$form, FormStateInterface $form_state);
/**
* Validates the exposed form submission.
*
* @param array $form
* An associative array containing the structure of the form.
* @param \Drupal\Core\Form\FormStateInterface $form_state
* The current state of the form.
*
* @see \Drupal\views\Form\ViewsExposedForm::validateForm()
*/
public function exposedFormValidate(&$form, FormStateInterface $form_state);
/**
* Submits the exposed form.
*
* @param array $form
* An associative array containing the structure of the form.
* @param \Drupal\Core\Form\FormStateInterface $form_state
* The current state of the form.
* @param array $exclude
* Array of keys that will not appear in $view->exposed_raw_input; for
* example, 'form_build_id'.
*
* @see \Drupal\views\Form\ViewsExposedForm::submitForm()
*/
public function exposedFormSubmit(&$form, FormStateInterface $form_state, &$exclude);
}
/**
* @}
*/

View file

@ -301,7 +301,7 @@ abstract class FieldPluginBase extends HandlerBase implements FieldHandlerInterf
if (!isset($elements)) {
// @todo Add possible html5 elements.
$elements = array(
'' => $this->t(' - Use default -'),
'' => $this->t('- Use default -'),
'0' => $this->t('- None -')
);
$elements += \Drupal::config('views.settings')->get('field_rewrite_elements');

View file

@ -3,6 +3,7 @@
namespace Drupal\views\Plugin\views\filter;
use Drupal\Core\Entity\EntityManagerInterface;
use Drupal\Core\Entity\EntityTypeBundleInfoInterface;
use Drupal\views\ViewExecutable;
use Drupal\views\Plugin\views\display\DisplayPluginBase;
use Symfony\Component\DependencyInjection\ContainerInterface;
@ -37,6 +38,13 @@ class Bundle extends InOperator {
*/
protected $entityManager;
/**
* The bundle info service.
*
* @var \Drupal\Core\Entity\EntityTypeBundleInfoInterface
*/
protected $bundleInfoService;
/**
* Constructs a Bundle object.
*
@ -49,10 +57,11 @@ class Bundle extends InOperator {
* @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager
* The entity manager.
*/
public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityManagerInterface $entity_manager) {
public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityManagerInterface $entity_manager, EntityTypeBundleInfoInterface $bundle_info_service) {
parent::__construct($configuration, $plugin_id, $plugin_definition);
$this->entityManager = $entity_manager;
$this->bundleInfoService = $bundle_info_service;
}
/**
@ -63,7 +72,8 @@ class Bundle extends InOperator {
$configuration,
$plugin_id,
$plugin_definition,
$container->get('entity.manager')
$container->get('entity.manager'),
$container->get('entity_type.bundle.info')
);
}
@ -83,7 +93,7 @@ class Bundle extends InOperator {
*/
public function getValueOptions() {
if (!isset($this->valueOptions)) {
$types = entity_get_bundles($this->entityTypeId);
$types = $this->bundleInfoService->getBundleInfo($this->entityTypeId);
$this->valueTitle = $this->t('@entity types', array('@entity' => $this->entityType->getLabel()));
$options = array();

View file

@ -99,22 +99,27 @@ class Combine extends StringFilter {
*/
public function validate() {
$errors = parent::validate();
$fields = $this->view->display_handler->getHandlers('field');
foreach ($this->options['fields'] as $id) {
if (!isset($fields[$id])) {
// Combined field filter only works with fields that are in the field
// settings.
$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()));
if ($this->displayHandler->usesFields()) {
$fields = $this->displayHandler->getHandlers('field');
foreach ($this->options['fields'] as $id) {
if (!isset($fields[$id])) {
// Combined field filter only works with fields that are in the field
// settings.
$errors[] = $this->t('Field %field set in %filter is not set in display %display.', array('%field' => $id, '%filter' => $this->adminLabel(), '%display' => $this->displayHandler->display['display_title']));
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()));
}
}
}
else {
$errors[] = $this->t('%display: %filter can only be used on displays that use fields. Set the style or row format for that display to one using fields to use the combine field filter.', array('%display' => $this->displayHandler->display['display_title'], '%filter' => $this->adminLabel()));
}
return $errors;
}

View file

@ -98,32 +98,23 @@ class Date extends NumericFilter {
}
/**
* Validate the build group options form.
* {@inheritdoc}
*/
protected function buildGroupValidate($form, FormStateInterface $form_state) {
// Special case to validate grouped date filters, this is because the
// $group['value'] array contains the type of filter (date or offset)
// and therefore the number of items the comparison has to be done
// against 'one' instead of 'zero'.
foreach ($form_state->getValue(array('options', 'group_info', 'group_items')) as $id => $group) {
if (empty($group['remove'])) {
// Check if the title is defined but value wasn't defined.
if (!empty($group['title'])) {
if ((!is_array($group['value']) && empty($group['value'])) || (is_array($group['value']) && count(array_filter($group['value'])) == 1)) {
$form_state->setError($form['group_info']['group_items'][$id]['value'], $this->t('The value is required if title for this item is defined.'));
}
}
// Check if the value is defined but title wasn't defined.
if ((!is_array($group['value']) && !empty($group['value'])) || (is_array($group['value']) && count(array_filter($group['value'])) > 1)) {
if (empty($group['title'])) {
$form_state->setError($form['group_info']['group_items'][$id]['title'], $this->t('The title is required if value for this item is defined.'));
}
}
}
protected function hasValidGroupedValue(array $group) {
if (!is_array($group['value']) || empty($group['value'])) {
return FALSE;
}
}
// Special case when validating grouped date filters because the
// $group['value'] array contains the type of filter (date or offset) and
// therefore the number of items the comparison has to be done against is
// one greater.
$operators = $this->operators();
$expected = $operators[$group['operator']]['values'] + 1;
$actual = count(array_filter($group['value'], 'static::arrayFilterZero'));
return $actual == $expected;
}
public function acceptExposedInput($input) {
if (empty($this->options['exposed'])) {

View file

@ -7,6 +7,7 @@ use Drupal\Core\Cache\CacheableDependencyInterface;
use Drupal\Core\Form\FormHelper;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Render\Element;
use Drupal\Core\Render\Element\Checkboxes;
use Drupal\user\RoleInterface;
use Drupal\views\Plugin\views\HandlerBase;
use Drupal\Component\Utility\Html;
@ -539,7 +540,7 @@ abstract class FilterPluginBase extends HandlerBase implements CacheableDependen
);
if (!empty($form['operator']['#type'])) {
// Increase the width of the left (operator) column.
// Increase the width of the left (operator) column.
$form['operator']['#prefix'] = '<div class="views-group-box views-left-40">';
$form['operator']['#suffix'] = '</div>';
$form['value']['#prefix'] = '<div class="views-group-box views-right-60">';
@ -617,6 +618,38 @@ abstract class FilterPluginBase extends HandlerBase implements CacheableDependen
$this->validateIdentifier($identifier, $form_state, $form['expose']['identifier']);
}
/**
* Determines if the given grouped filter entry has a valid value.
*
* @param array $group
* A group entry as defined by buildGroupForm().
*
* @return bool
*/
protected function hasValidGroupedValue(array $group) {
$operators = $this->operators();
if ($operators[$group['operator']]['values'] == 0) {
// Some filters, such as "is empty," do not require a value to be
// specified in order to be valid entries.
return TRUE;
}
else {
if (is_string($group['value'])) {
return trim($group['value']) != '';
}
elseif (is_array($group['value'])) {
// Some filters allow multiple options to be selected (for example, node
// types). Ensure at least the minimum number of values is present for
// this entry to be considered valid.
$min_values = $operators[$group['operator']]['values'];
$actual_values = count(array_filter($group['value'], 'static::arrayFilterZero'));
return $actual_values >= $min_values;
}
}
return FALSE;
}
/**
* Validate the build group options form.
*/
@ -627,25 +660,20 @@ abstract class FilterPluginBase extends HandlerBase implements CacheableDependen
}
if ($group_items = $form_state->getValue(array('options', 'group_info', 'group_items'))) {
$operators = $this->operators();
foreach ($group_items as $id => $group) {
if (empty($group['remove'])) {
// Check if the title is defined but value wasn't defined.
if (!empty($group['title']) && $operators[$group['operator']]['values'] > 0) {
if ((!is_array($group['value']) && trim($group['value']) == "") ||
(is_array($group['value']) && count(array_filter($group['value'], 'static::arrayFilterZero')) == 0)) {
$form_state->setError($form['group_info']['group_items'][$id]['value'], $this->t('The value is required if title for this item is defined.'));
$has_valid_value = $this->hasValidGroupedValue($group);
if ($has_valid_value && $group['title'] == '') {
$operators = $this->operators();
if ($operators[$group['operator']]['values'] == 0) {
$form_state->setError($form['group_info']['group_items'][$id]['title'], $this->t('A label is required for the specified operator.'));
}
else {
$form_state->setError($form['group_info']['group_items'][$id]['title'], $this->t('A label is required if the value for this item is defined.'));
}
}
// Check if the value is defined but title wasn't defined.
if ((!is_array($group['value']) && trim($group['value']) != "") ||
(is_array($group['value']) && count(array_filter($group['value'], 'static::arrayFilterZero')) > 0)) {
if (empty($group['title'])) {
$form_state->setError($form['group_info']['group_items'][$id]['title'], $this->t('The title is required if value for this item is defined.'));
}
if (!$has_valid_value && $group['title'] != '') {
$form_state->setError($form['group_info']['group_items'][$id]['value'], $this->t('A value is required if the label for this item is defined.'));
}
}
}
@ -1279,7 +1307,7 @@ abstract class FilterPluginBase extends HandlerBase implements CacheableDependen
*/
public function groupMultipleExposedInput(&$input) {
if (!empty($input[$this->options['group_info']['identifier']])) {
return array_filter($input[$this->options['group_info']['identifier']]);
return array_filter($input[$this->options['group_info']['identifier']]);
}
return array();
}
@ -1332,15 +1360,20 @@ abstract class FilterPluginBase extends HandlerBase implements CacheableDependen
}
/**
* Check to see if input from the exposed filters should change
* the behavior of this filter.
* Determines if the input from a filter should change the generated query.
*
* @param array $input
* The exposed data for this view.
*
* @return bool
* TRUE if the input for this filter should be included in the view query.
* FALSE otherwise.
*/
public function acceptExposedInput($input) {
if (empty($this->options['exposed'])) {
return TRUE;
}
if (!empty($this->options['expose']['use_operator']) && !empty($this->options['expose']['operator_id']) && isset($input[$this->options['expose']['operator_id']])) {
$this->operator = $input[$this->options['expose']['operator_id']];
}
@ -1358,6 +1391,12 @@ abstract class FilterPluginBase extends HandlerBase implements CacheableDependen
if ($value == 'All' || $value === array()) {
return FALSE;
}
// If checkboxes are used to render this filter, do not include the
// filter if no options are checked.
if (is_array($value) && Checkboxes::detectEmptyCheckboxes($value)) {
return FALSE;
}
}
if (!empty($this->alwaysMultiple) && $value === '') {
@ -1452,21 +1491,8 @@ abstract class FilterPluginBase extends HandlerBase implements CacheableDependen
*
* @return bool
*/
public function canGroup() {
return TRUE;
}
/**
* Filter by no empty values, though allow to use "0".
*
* @param string $var
* The variable to evaluate.
*
* @return bool
* TRUE if the value is equal to an empty string, FALSE otherwise.
*/
protected static function arrayFilterZero($var) {
return trim($var) != '';
public function canGroup() {
return TRUE;
}
/**
@ -1506,6 +1532,22 @@ abstract class FilterPluginBase extends HandlerBase implements CacheableDependen
}
}
/**
* Filter by no empty values, though allow the use of (string) "0".
*
* @param string $var
* The variable to evaluate.
*
* @return bool
* TRUE if the value is equal to an empty string, FALSE otherwise.
*/
protected static function arrayFilterZero($var) {
if (is_int($var)) {
return $var != 0;
}
return trim($var) != '';
}
}
/**

View file

@ -28,7 +28,7 @@ class GroupByNumeric extends NumericFilter {
$this->query->addHavingExpression($this->options['group'], "$field <= $placeholder_max", array($placeholder_max => $this->value['max']));
}
else {
$this->query->addHavingExpression($this->options['group'], "$field <= $placeholder_min OR $field >= $placeholder_max", array($placeholder_min => $this->value['min'], $placeholder_max => $this->value['max']));
$this->query->addHavingExpression($this->options['group'], "$field < $placeholder_min OR $field > $placeholder_max", array($placeholder_min => $this->value['min'], $placeholder_max => $this->value['max']));
}
}

View file

@ -54,7 +54,7 @@ class InOperator extends FilterPluginBase {
* This can use a guard to be used to reduce database hits as much as
* possible.
*
* @return array|NULL
* @return array|null
* The stored values from $this->valueOptions.
*/
public function getValueOptions() {
@ -282,15 +282,17 @@ class InOperator extends FilterPluginBase {
return $options;
}
/**
* {@inheritdoc}
*/
public function acceptExposedInput($input) {
// A very special override because the All state for this type of
// filter could have a default:
if (empty($this->options['exposed'])) {
return TRUE;
}
// If this is non-multiple and non-required, then this filter will
// participate, but using the default settings, *if* 'limit is true.
// The "All" state for this type of filter could have a default value. If
// this is a non-multiple and non-required option, then this filter will
// participate by using the default settings *if* 'limit' is true.
if (empty($this->options['expose']['multiple']) && empty($this->options['expose']['required']) && !empty($this->options['expose']['limit'])) {
$identifier = $this->options['expose']['identifier'];
if ($input[$identifier] == 'All') {

View file

@ -248,7 +248,7 @@ class NumericFilter extends FilterPluginBase {
$this->query->addWhere($this->options['group'], $field, array($this->value['min'], $this->value['max']), 'BETWEEN');
}
else {
$this->query->addWhere($this->options['group'], db_or()->condition($field, $this->value['min'], '<=')->condition($field, $this->value['max'], '>='));
$this->query->addWhere($this->options['group'], $field, array($this->value['min'], $this->value['max']), 'NOT BETWEEN');
}
}

View file

@ -38,7 +38,7 @@ class Mini extends SqlBase {
if (!empty($this->options['offset'])) {
return $this->formatPlural($this->options['items_per_page'], 'Mini pager, @count item, skip @skip', 'Mini pager, @count items, skip @skip', array('@count' => $this->options['items_per_page'], '@skip' => $this->options['offset']));
}
return $this->formatPlural($this->options['items_per_page'], 'Mini pager, @count item', 'Mini pager, @count items', array('@count' => $this->options['items_per_page']));
return $this->formatPlural($this->options['items_per_page'], 'Mini pager, @count item', 'Mini pager, @count items', array('@count' => $this->options['items_per_page']));
}
/**

View file

@ -22,7 +22,7 @@ class Some extends PagerPluginBase {
if (!empty($this->options['offset'])) {
return $this->formatPlural($this->options['items_per_page'], '@count item, skip @skip', '@count items, skip @skip', array('@count' => $this->options['items_per_page'], '@skip' => $this->options['offset']));
}
return $this->formatPlural($this->options['items_per_page'], '@count item', '@count items', array('@count' => $this->options['items_per_page']));
return $this->formatPlural($this->options['items_per_page'], '@count item', '@count items', array('@count' => $this->options['items_per_page']));
}
protected function defineOptions() {

View file

@ -68,7 +68,7 @@ abstract class SqlBase extends PagerPluginBase implements CacheableDependencyInt
$form['total_pages'] = array(
'#type' => 'number',
'#title' => $this->t('Number of pages'),
'#description' => $this->t('The total number of pages. Leave empty to show all pages.'),
'#description' => $this->t('Leave empty to show all pages.'),
'#default_value' => $this->options['total_pages'],
);

View file

@ -1553,7 +1553,7 @@ class Sql extends QueryPluginBase {
$flat_ids = iterator_to_array(new \RecursiveIteratorIterator(new \RecursiveArrayIterator($ids)), FALSE);
$entities = $entity_storage->loadMultiple(array_unique($flat_ids));
$results = $this->_assignEntitiesToResult($ids, $entities, $results);
$results = $this->assignEntitiesToResult($ids, $entities, $results);
}
// Now load all revisions.
@ -1569,7 +1569,7 @@ class Sql extends QueryPluginBase {
}
}
$results = $this->_assignEntitiesToResult($revision_ids, $entities, $results);
$results = $this->assignEntitiesToResult($revision_ids, $entities, $results);
}
}
@ -1590,7 +1590,7 @@ class Sql extends QueryPluginBase {
* @return \Drupal\views\ResultRow[]
* The changed views results.
*/
protected function _assignEntitiesToResult($ids, array $entities, array $results) {
protected function assignEntitiesToResult($ids, array $entities, array $results) {
foreach ($ids as $index => $relationships) {
foreach ($relationships as $relationship_id => $id) {
if (isset($entities[$id])) {

View file

@ -3,6 +3,7 @@
namespace Drupal\views\Plugin\views\sort;
use Drupal\Core\Cache\CacheableDependencyInterface;
use Drupal\Core\Cache\UncacheableDependencyTrait;
use Drupal\Core\Form\FormStateInterface;
/**
@ -12,6 +13,8 @@ use Drupal\Core\Form\FormStateInterface;
*/
class Random extends SortPluginBase implements CacheableDependencyInterface {
use UncacheableDependencyTrait;
/**
* {@inheritdoc}
*/
@ -28,25 +31,4 @@ class Random extends SortPluginBase implements CacheableDependencyInterface {
$form['order']['#access'] = FALSE;
}
/**
* {@inheritdoc}
*/
public function getCacheMaxAge() {
return 0;
}
/**
* {@inheritdoc}
*/
public function getCacheContexts() {
return [];
}
/**
* {@inheritdoc}
*/
public function getCacheTags() {
return [];
}
}

View file

@ -64,11 +64,10 @@ abstract class SortPluginBase extends HandlerBase implements CacheableDependency
case 'asc':
default:
return $this->t('asc');
break;
case 'DESC';
case 'desc';
return $this->t('desc');
break;
}
}

View file

@ -345,7 +345,7 @@ abstract class StylePluginBase extends PluginBase {
$form['default_row_class'] = array(
'#title' => $this->t('Add views row classes'),
'#description' => $this->t('Add the default row classes like views-row-1 to the output. You can use this to quickly reduce the amount of markup the view provides by default, at the cost of making it more difficult to apply CSS.'),
'#description' => $this->t('Add the default row classes like @classes to the output. You can use this to quickly reduce the amount of markup the view provides by default, at the cost of making it more difficult to apply CSS.', array('@classes' => 'views-row')),
'#type' => 'checkbox',
'#default_value' => $this->options['default_row_class'],
);

View file

@ -3,6 +3,7 @@
namespace Drupal\views\Plugin\views\wizard;
use Drupal\Component\Utility\NestedArray;
use Drupal\Core\Entity\EntityTypeBundleInfoInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Routing\UrlGeneratorTrait;
use Drupal\views\Entity\View;
@ -10,6 +11,7 @@ use Drupal\views\Views;
use Drupal\views_ui\ViewUI;
use Drupal\views\Plugin\views\display\DisplayPluginBase;
use Drupal\views\Plugin\views\PluginBase;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* @defgroup views_wizard_plugins Views wizard plugins
@ -108,12 +110,32 @@ abstract class WizardPluginBase extends PluginBase implements WizardInterface {
'group' => 1,
);
/**
* The bundle info service.
*
* @var \Drupal\Core\Entity\EntityTypeBundleInfoInterface
*/
protected $bundleInfoService;
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
return new static(
$configuration,
$plugin_id,
$plugin_definition,
$container->get('entity_type.bundle.info')
);
}
/**
* Constructs a WizardPluginBase object.
*/
public function __construct(array $configuration, $plugin_id, $plugin_definition) {
public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityTypeBundleInfoInterface $bundle_info_service) {
parent::__construct($configuration, $plugin_id, $plugin_definition);
$this->bundleInfoService = $bundle_info_service;
$this->base_table = $this->definition['base_table'];
$entity_types = \Drupal::entityManager()->getDefinitions();
@ -585,7 +607,7 @@ abstract class WizardPluginBase extends PluginBase implements WizardInterface {
protected function buildFilters(&$form, FormStateInterface $form_state) {
module_load_include('inc', 'views_ui', 'admin');
$bundles = entity_get_bundles($this->entityTypeId);
$bundles = $this->bundleInfoService->getBundleInfo($this->entityTypeId);
// If the current base table support bundles and has more than one (like user).
if (!empty($bundles) && $this->entityType && $this->entityType->hasKey('bundle')) {
// Get all bundles and their human readable names.

View file

@ -69,8 +69,7 @@ class FieldEntityTranslationTest extends ViewTestBase {
$translation->save();
$this->drupalGet('test_entity_field_renderers/entity_translation');
$this->assertRows(
[
$this->assertRows([
[
'title' => 'example EN',
'sticky' => 'Off',
@ -82,82 +81,76 @@ class FieldEntityTranslationTest extends ViewTestBase {
]);
$this->drupalGet('test_entity_field_renderers/entity_default');
$this->assertRows(
$this->assertRows([
[
[
'title' => 'example EN',
'sticky' => 'Off',
],
[
'title' => 'example EN',
'sticky' => 'Off',
],
]);
'title' => 'example EN',
'sticky' => 'Off',
],
[
'title' => 'example EN',
'sticky' => 'Off',
],
]);
$this->drupalGet('test_entity_field_renderers/site_default');
$this->assertRows(
$this->assertRows([
[
[
'title' => 'example EN',
'sticky' => 'Off',
],
[
'title' => 'example EN',
'sticky' => 'Off',
],
]);
'title' => 'example EN',
'sticky' => 'Off',
],
[
'title' => 'example EN',
'sticky' => 'Off',
],
]);
$this->drupalGet('test_entity_field_renderers/language_interface');
$this->assertRows(
$this->assertRows([
[
[
'title' => 'example EN',
'sticky' => 'Off',
],
[
'title' => 'example EN',
'sticky' => 'Off',
],
]);
'title' => 'example EN',
'sticky' => 'Off',
],
[
'title' => 'example EN',
'sticky' => 'Off',
],
]);
$this->drupalGet('test_entity_field_renderers/language_interface', ['language' => new Language(['id' => 'es'])]);
$this->assertRows(
$this->assertRows([
[
[
'title' => 'example ES',
'sticky' => 'On',
],
[
'title' => 'example ES',
'sticky' => 'On',
],
]);
'title' => 'example ES',
'sticky' => 'On',
],
[
'title' => 'example ES',
'sticky' => 'On',
],
]);
$this->drupalGet('test_entity_field_renderers/en');
$this->assertRows(
$this->assertRows([
[
[
'title' => 'example EN',
'sticky' => 'Off',
],
[
'title' => 'example EN',
'sticky' => 'Off',
],
]);
'title' => 'example EN',
'sticky' => 'Off',
],
[
'title' => 'example EN',
'sticky' => 'Off',
],
]);
$this->drupalGet('test_entity_field_renderers/es');
$this->assertRows(
$this->assertRows([
[
[
'title' => 'example ES',
'sticky' => 'On',
],
[
'title' => 'example ES',
'sticky' => 'On',
],
]);
'title' => 'example ES',
'sticky' => 'On',
],
[
'title' => 'example ES',
'sticky' => 'On',
],
]);
}
/**

View file

@ -50,7 +50,7 @@ class FilterEntityBundleTest extends ViewTestBase {
ViewTestData::createTestViews(get_class($this), array('views_test_config'));
$this->entityBundles = entity_get_bundles('node');
$this->entityBundles = $this->container->get('entity_type.bundle.info')->getBundleInfo('node');
$this->entities['count'] = 0;

View file

@ -169,7 +169,7 @@ class FieldWebTest extends HandlerTestBase {
* @param array $arguments
* Some arguments for the xpath.
*
* @return array|FALSE
* @return array|false
* The return value of the xpath search. For details on the xpath string
* format and return values see the SimpleXML documentation,
* http://php.net/manual/function.simplexml-element-xpath.php.

View file

@ -88,8 +88,8 @@ class FilterDateTest extends HandlerTestBase {
// Test between with min and max.
$view->initHandlers();
$view->filter['created']->operator = 'between';
$view->filter['created']->value['min'] = format_date(150000, 'custom', 'Y-m-d H:s');
$view->filter['created']->value['max'] = format_date(250000, 'custom', 'Y-m-d H:s');
$view->filter['created']->value['min'] = format_date(150000, 'custom', 'Y-m-d H:i:s');
$view->filter['created']->value['max'] = format_date(200000, 'custom', 'Y-m-d H:i:s');
$view->executeDisplay('default');
$expected_result = array(
array('nid' => $this->nodes[1]->id()),
@ -100,7 +100,7 @@ class FilterDateTest extends HandlerTestBase {
// Test between with just max.
$view->initHandlers();
$view->filter['created']->operator = 'between';
$view->filter['created']->value['max'] = format_date(250000, 'custom', 'Y-m-d H:s');
$view->filter['created']->value['max'] = format_date(200000, 'custom', 'Y-m-d H:i:s');
$view->executeDisplay('default');
$expected_result = array(
array('nid' => $this->nodes[0]->id()),
@ -112,11 +112,11 @@ class FilterDateTest extends HandlerTestBase {
// Test not between with min and max.
$view->initHandlers();
$view->filter['created']->operator = 'not between';
$view->filter['created']->value['min'] = format_date(150000, 'custom', 'Y-m-d H:s');
$view->filter['created']->value['max'] = format_date(250000, 'custom', 'Y-m-d H:s');
$view->filter['created']->value['min'] = format_date(100000, 'custom', 'Y-m-d H:i:s');
$view->filter['created']->value['max'] = format_date(200000, 'custom', 'Y-m-d H:i:s');
$view->executeDisplay('default');
$expected_result = array(
array('nid' => $this->nodes[0]->id()),
array('nid' => $this->nodes[2]->id()),
array('nid' => $this->nodes[3]->id()),
);
@ -126,10 +126,9 @@ class FilterDateTest extends HandlerTestBase {
// Test not between with just max.
$view->initHandlers();
$view->filter['created']->operator = 'not between';
$view->filter['created']->value['max'] = format_date(150000, 'custom', 'Y-m-d H:s');
$view->filter['created']->value['max'] = format_date(200000, 'custom', 'Y-m-d H:i:s');
$view->executeDisplay('default');
$expected_result = array(
array('nid' => $this->nodes[1]->id()),
array('nid' => $this->nodes[2]->id()),
array('nid' => $this->nodes[3]->id()),
);

View file

@ -97,7 +97,7 @@ class CacheTagTest extends PluginTestBase {
* @param \Drupal\views\ViewExecutable $view
* The view.
*
* @return array|FALSE
* @return array|false
* The render cache result or FALSE if not existent.
*/
protected function getRenderCache(ViewExecutable $view) {

View file

@ -8,6 +8,7 @@ use Drupal\system\Tests\Cache\AssertPageCacheContextsAndTagsTrait;
use Drupal\views\Tests\ViewTestBase;
use Drupal\views\ViewExecutable;
use Drupal\views\Views;
use Drupal\views\Entity\View;
/**
* Tests exposed forms functionality.
@ -208,6 +209,48 @@ class ExposedFormTest extends ViewTestBase {
$this->assertEqual(count($result), 1, 'Filter description was found.');
}
/**
* Tests overriding the default render option with checkboxes.
*/
public function testExposedFormRenderCheckboxes() {
// Make sure we have at least two options for node type.
$this->drupalCreateContentType(['type' => 'page']);
$this->drupalCreateNode(['type' => 'page']);
// Use a test theme to convert multi-select elements into checkboxes.
\Drupal::service('theme_handler')->install(array('views_test_checkboxes_theme'));
$this->config('system.theme')
->set('default', 'views_test_checkboxes_theme')
->save();
// Set the "type" filter to multi-select.
$view = Views::getView('test_exposed_form_buttons');
$filter = $view->getHandler('page_1', 'filter', 'type');
$filter['expose']['multiple'] = TRUE;
$view->setHandler('page_1', 'filter', 'type', $filter);
// Only display 5 items per page so we can test that paging works.
$display = &$view->storage->getDisplay('default');
$display['display_options']['pager']['options']['items_per_page'] = 5;
$view->save();
$this->drupalGet('test_exposed_form_buttons');
$actual = $this->xpath('//form//input[@type="checkbox" and @name="type[article]"]');
$this->assertEqual(count($actual), 1, 'Article option renders as a checkbox.');
$actual = $this->xpath('//form//input[@type="checkbox" and @name="type[page]"]');
$this->assertEqual(count($actual), 1, 'Page option renders as a checkbox');
// Ensure that all results are displayed.
$rows = $this->xpath("//div[contains(@class, 'views-row')]");
$this->assertEqual(count($rows), 5, '5 rows are displayed by default on the first page when no options are checked.');
$this->clickLink('Page 2');
$rows = $this->xpath("//div[contains(@class, 'views-row')]");
$this->assertEqual(count($rows), 1, '1 row is displayed by default on the second page when no options are checked.');
$this->assertNoText('An illegal choice has been detected. Please contact the site administrator.');
}
/**
* Tests the exposed block functionality.
*/
@ -244,7 +287,7 @@ class ExposedFormTest extends ViewTestBase {
* Test the input required exposed form type.
*/
public function testInputRequired() {
$view = entity_load('view', 'test_exposed_form_buttons');
$view = View::load('test_exposed_form_buttons');
$display = &$view->getDisplay('default');
$display['display_options']['exposed_form']['type'] = 'input_required';
$view->save();

View file

@ -6,6 +6,9 @@ use Drupal\views\Tests\ViewKernelTestBase;
/**
* Base test class for views plugin unit tests.
*
* @deprecated Scheduled for removal in Drupal 9.0.0.
* Use \Drupal\Tests\views\Kernel\ViewsKernelTestBase instead.
*/
abstract class PluginKernelTestBase extends ViewKernelTestBase {

View file

@ -2,6 +2,8 @@
namespace Drupal\views\Tests\Plugin;
use Drupal\views\Entity\View;
/**
* Tests the table style views plugin.
*
@ -44,7 +46,7 @@ class StyleTableTest extends PluginTestBase {
$this->assertEqual(trim((string) $result[0]), 'description-text');
// Remove the caption and ensure the caption is not displayed anymore.
$view = entity_load('view', 'test_table');
$view = View::load('test_table');
$display = &$view->getDisplay('default');
$display['display_options']['style']['options']['caption'] = '';
$view->save();
@ -88,7 +90,7 @@ class StyleTableTest extends PluginTestBase {
$this->assertTrue(count($result), 'Ensure there is a td with the class views-field-job-1');
// Combine the second job-column with the first one, with ', ' as separator.
$view = entity_load('view', 'test_table');
$view = View::load('test_table');
$display = &$view->getDisplay('default');
$display['display_options']['style']['options']['columns']['job_1'] = 'job';
$display['display_options']['style']['options']['info']['job']['separator'] = ', ';

View file

@ -0,0 +1,40 @@
<?php
namespace Drupal\views\Tests\Update;
use Drupal\system\Tests\Update\UpdatePathTestBase;
use Drupal\views\Entity\View;
/**
* Tests the upgrade path for boolean field values.
*
* @see views_post_update_boolean_filter_values()
*
* @group Update
*/
class BooleanFilterValuesUpdateTest extends UpdatePathTestBase {
/**
* {@inheritdoc}
*/
protected function setDatabaseDumpFiles() {
$this->databaseDumpFiles = [
__DIR__ . '/../../../../system/tests/fixtures/update/drupal-8.bare.standard.php.gz',
__DIR__ . '/../../../tests/fixtures/update/boolean-filter-values.php',
];
}
/**
* Tests that boolean filter values are updated properly.
*/
public function testViewsPostUpdateBooleanFilterValues() {
$this->runUpdates();
// Load and initialize our test view.
$view = View::load('test_boolean_filter_values');
$data = $view->toArray();
// Check that the field is using the expected string value.
$this->assertIdentical('1', $data['display']['default']['display_options']['filters']['status']['value']);
}
}

View file

@ -3,6 +3,7 @@
namespace Drupal\views\Tests;
use Drupal\Component\Serialization\Json;
use Drupal\Core\EventSubscriber\MainContentViewSubscriber;
/**
* Tests the ajax view functionality.
@ -46,7 +47,7 @@ class ViewAjaxTest extends ViewTestBase {
'view_display_id' => 'page_1',
);
$post += $this->getAjaxPageStatePostData();
$response = $this->drupalPost('views/ajax', 'application/vnd.drupal-ajax', $post);
$response = $this->drupalPost('views/ajax', '', $post, ['query' => [MainContentViewSubscriber::WRAPPER_FORMAT => 'drupal_ajax']]);
$data = Json::decode($response);
$this->assertTrue(isset($data[0]['settings']['views']['ajaxViews']));

View file

@ -26,7 +26,7 @@ class BasicTest extends WizardTestBase {
// Check if we can access the main views admin page.
$this->drupalGet('admin/structure/views');
$this->assertText(t('Add new view'));
$this->assertText(t('Add view'));
// Create a simple and not at all useful view.
$view1 = array();

View file

@ -1220,6 +1220,7 @@ class ViewExecutable implements \Serializable {
$this->_preQuery();
if ($this->display_handler->usesExposed()) {
/** @var \Drupal\views\Plugin\views\exposed_form\ExposedFormPluginInterface $exposed_form */
$exposed_form = $this->display_handler->getPlugin('exposed_form');
$this->exposed_widgets = $exposed_form->renderExposedForm();
if (FormState::hasAnyErrors() || !empty($this->build_info['abort'])) {
@ -1447,6 +1448,7 @@ class ViewExecutable implements \Serializable {
return;
}
/** @var \Drupal\views\Plugin\views\exposed_form\ExposedFormPluginInterface $exposed_form */
$exposed_form = $this->display_handler->getPlugin('exposed_form');
$exposed_form->preRender($this->result);
@ -1653,7 +1655,7 @@ class ViewExecutable implements \Serializable {
/**
* Runs attachments and lets the display do what it needs to before running.
*
* @param array @args
* @param array $args
* An array of arguments from the URL that can be used by the view.
*/
public function preExecute($args = array()) {

View file

@ -81,7 +81,7 @@ class ViewsData {
protected $moduleHandler;
/**
* The language manager
* The language manager.
*
* @var \Drupal\Core\Language\LanguageManagerInterface
*/
@ -108,6 +108,26 @@ class ViewsData {
$this->skipCache = $config->get('views.settings')->get('skip_cache');
}
/**
* Gets all table data.
*
* @see https://www.drupal.org/node/2723553
*
* @return array $data
* An array of table data.
*/
public function getAll() {
if (!$this->fullyLoaded) {
$this->allStorage = $this->getData();
}
// Set storage from allStorage outside of the fullyLoaded check to prevent
// cache calls on requests that have requested all data to get a single
// tables data. Make sure $this->storage is populated in this case.
$this->storage = $this->allStorage;
return $this->allStorage;
}
/**
* Gets data for a particular table, or all tables.
*
@ -115,57 +135,50 @@ class ViewsData {
* The key of the cache entry to retrieve. Defaults to NULL, this will
* return all table data.
*
* @deprecated NULL $key deprecated in Drupal 8.2.x and will be removed in
* 9.0.0. Use getAll() instead.
*
* @see https://www.drupal.org/node/2723553
*
* @return array $data
* An array of table data.
*/
public function get($key = NULL) {
if ($key) {
if (!isset($this->storage[$key])) {
// Prepare a cache ID for get and set.
$cid = $this->baseCid . ':' . $key;
$from_cache = FALSE;
if ($data = $this->cacheGet($cid)) {
$this->storage[$key] = $data->data;
$from_cache = TRUE;
}
// If there is no cached entry and data is not already fully loaded,
// rebuild. This will stop requests for invalid tables calling getData.
elseif (!$this->fullyLoaded) {
$this->allStorage = $this->getData();
}
if (!$from_cache) {
if (!isset($this->allStorage[$key])) {
// Write an empty cache entry if no information for that table
// exists to avoid repeated cache get calls for this table and
// prevent loading all tables unnecessarily.
$this->storage[$key] = array();
$this->allStorage[$key] = array();
}
else {
$this->storage[$key] = $this->allStorage[$key];
}
// Create a cache entry for the requested table.
$this->cacheSet($cid, $this->allStorage[$key]);
}
}
return $this->storage[$key];
if (!$key) {
return $this->getAll();
}
else {
if (!$this->fullyLoaded) {
if (!isset($this->storage[$key])) {
// Prepare a cache ID for get and set.
$cid = $this->baseCid . ':' . $key;
$from_cache = FALSE;
if ($data = $this->cacheGet($cid)) {
$this->storage[$key] = $data->data;
$from_cache = TRUE;
}
// If there is no cached entry and data is not already fully loaded,
// rebuild. This will stop requests for invalid tables calling getData.
elseif (!$this->fullyLoaded) {
$this->allStorage = $this->getData();
}
// Set storage from allStorage outside of the fullyLoaded check to prevent
// cache calls on requests that have requested all data to get a single
// tables data. Make sure $this->storage is populated in this case.
$this->storage = $this->allStorage;
}
if (!$from_cache) {
if (!isset($this->allStorage[$key])) {
// Write an empty cache entry if no information for that table
// exists to avoid repeated cache get calls for this table and
// prevent loading all tables unnecessarily.
$this->storage[$key] = array();
$this->allStorage[$key] = array();
}
else {
$this->storage[$key] = $this->allStorage[$key];
}
return $this->allStorage;
// Create a cache entry for the requested table.
$this->cacheSet($cid, $this->allStorage[$key]);
}
}
return $this->storage[$key];
}
/**

View file

@ -5,8 +5,8 @@
* Text fixture.
*/
use Drupal\Component\Serialization\Yaml;
use Drupal\Core\Database\Database;
use Drupal\Core\Serialization\Yaml;
$connection = Database::getConnection();

View file

@ -0,0 +1,19 @@
<?php
/**
* @file
* Test fixture.
*/
use Drupal\Core\Database\Database;
use Drupal\Core\Serialization\Yaml;
$connection = Database::getConnection();
$connection->insert('config')
->fields(array(
'collection' => '',
'name' => 'views.view.test_boolean_filter_values',
'data' => serialize(Yaml::decode(file_get_contents('core/modules/views/tests/fixtures/update/views.view.test_boolean_filter_values.yml'))),
))
->execute();

View file

@ -5,8 +5,8 @@
* Test fixture.
*/
use Drupal\Component\Serialization\Yaml;
use Drupal\Core\Database\Database;
use Drupal\Core\Serialization\Yaml;
$connection = Database::getConnection();

View file

@ -0,0 +1,604 @@
langcode: en
status: true
dependencies:
module:
- node
- user
id: test_boolean_filter_values
label: Content
module: node
description: 'Find and manage content.'
tag: default
base_table: node_field_data
base_field: nid
core: 8.x
display:
default:
display_options:
access:
type: perm
options:
perm: 'access content overview'
cache:
type: tag
query:
type: views_query
exposed_form:
type: basic
options:
submit_button: Filter
reset_button: true
reset_button_label: Reset
exposed_sorts_label: 'Sort by'
expose_sort_order: true
sort_asc_label: Asc
sort_desc_label: Desc
pager:
type: full
options:
items_per_page: 50
tags:
previous: ' Previous'
next: 'Next '
first: '« First'
last: 'Last »'
style:
type: table
options:
grouping: { }
row_class: ''
default_row_class: true
override: true
sticky: true
caption: ''
summary: ''
description: ''
columns:
node_bulk_form: node_bulk_form
title: title
type: type
name: name
status: status
changed: changed
edit_node: edit_node
delete_node: delete_node
dropbutton: dropbutton
timestamp: title
info:
node_bulk_form:
align: ''
separator: ''
empty_column: false
responsive: ''
title:
sortable: true
default_sort_order: asc
align: ''
separator: ''
empty_column: false
responsive: ''
type:
sortable: true
default_sort_order: asc
align: ''
separator: ''
empty_column: false
responsive: ''
name:
sortable: false
default_sort_order: asc
align: ''
separator: ''
empty_column: false
responsive: priority-low
status:
sortable: true
default_sort_order: asc
align: ''
separator: ''
empty_column: false
responsive: ''
changed:
sortable: true
default_sort_order: desc
align: ''
separator: ''
empty_column: false
responsive: priority-low
edit_node:
sortable: false
default_sort_order: asc
align: ''
separator: ''
empty_column: false
responsive: ''
delete_node:
sortable: false
default_sort_order: asc
align: ''
separator: ''
empty_column: false
responsive: ''
dropbutton:
sortable: false
default_sort_order: asc
align: ''
separator: ''
empty_column: false
responsive: ''
timestamp:
sortable: false
default_sort_order: asc
align: ''
separator: ''
empty_column: false
responsive: ''
default: changed
empty_table: true
row:
type: fields
fields:
node_bulk_form:
id: node_bulk_form
table: node
field: node_bulk_form
label: ''
exclude: false
alter:
alter_text: false
element_class: ''
element_default_classes: true
empty: ''
hide_empty: false
empty_zero: false
hide_alter_empty: true
plugin_id: node_bulk_form
entity_type: node
title:
id: title
table: node_field_data
field: title
label: Title
exclude: false
alter:
alter_text: false
element_class: ''
element_default_classes: true
empty: ''
hide_empty: false
empty_zero: false
hide_alter_empty: true
entity_type: node
entity_field: title
type: string
settings:
link_to_entity: true
plugin_id: field
type:
id: type
table: node_field_data
field: type
relationship: none
group_type: group
admin_label: ''
label: 'Content type'
exclude: false
alter:
alter_text: false
text: ''
make_link: false
path: ''
absolute: false
external: false
replace_spaces: false
path_case: none
trim_whitespace: false
alt: ''
rel: ''
link_class: ''
prefix: ''
suffix: ''
target: ''
nl2br: false
max_length: 0
word_boundary: true
ellipsis: true
more_link: false
more_link_text: ''
more_link_path: ''
strip_tags: false
trim: false
preserve_tags: ''
html: false
element_type: ''
element_class: ''
element_label_type: ''
element_label_class: ''
element_label_colon: true
element_wrapper_type: ''
element_wrapper_class: ''
element_default_classes: true
empty: ''
hide_empty: false
empty_zero: false
hide_alter_empty: true
click_sort_column: target_id
type: entity_reference_label
settings:
link: false
group_column: target_id
group_columns: { }
group_rows: true
delta_limit: 0
delta_offset: 0
delta_reversed: false
delta_first_last: false
multi_type: separator
separator: ', '
field_api_classes: false
entity_type: node
entity_field: type
plugin_id: field
name:
id: name
table: users_field_data
field: name
relationship: uid
label: Author
exclude: false
alter:
alter_text: false
element_class: ''
element_default_classes: true
empty: ''
hide_empty: false
empty_zero: false
hide_alter_empty: true
plugin_id: field
type: user_name
entity_type: user
entity_field: name
status:
id: status
table: node_field_data
field: status
label: Status
exclude: false
alter:
alter_text: false
element_class: ''
element_default_classes: true
empty: ''
hide_empty: false
empty_zero: false
hide_alter_empty: true
type: boolean
settings:
format: custom
format_custom_true: Published
format_custom_false: Unpublished
plugin_id: field
entity_type: node
entity_field: status
changed:
id: changed
table: node_field_data
field: changed
label: Updated
exclude: false
alter:
alter_text: false
element_class: ''
element_default_classes: true
empty: ''
hide_empty: false
empty_zero: false
hide_alter_empty: true
type: timestamp
settings:
date_format: short
custom_date_format: ''
timezone: ''
plugin_id: field
entity_type: node
entity_field: changed
operations:
id: operations
table: node
field: operations
relationship: none
group_type: group
admin_label: ''
label: Operations
exclude: false
alter:
alter_text: false
text: ''
make_link: false
path: ''
absolute: false
external: false
replace_spaces: false
path_case: none
trim_whitespace: false
alt: ''
rel: ''
link_class: ''
prefix: ''
suffix: ''
target: ''
nl2br: false
max_length: 0
word_boundary: true
ellipsis: true
more_link: false
more_link_text: ''
more_link_path: ''
strip_tags: false
trim: false
preserve_tags: ''
html: false
element_type: ''
element_class: ''
element_label_type: ''
element_label_class: ''
element_label_colon: true
element_wrapper_type: ''
element_wrapper_class: ''
element_default_classes: true
empty: ''
hide_empty: false
empty_zero: false
hide_alter_empty: true
destination: true
plugin_id: entity_operations
filters:
status_extra:
id: status_extra
table: node_field_data
field: status_extra
operator: '='
value: false
plugin_id: node_status
group: 1
entity_type: node
status:
id: status
table: node_field_data
field: status
relationship: none
group_type: group
admin_label: ''
operator: '='
value: true
group: 1
exposed: true
expose:
operator_id: ''
label: Status
description: ''
use_operator: false
operator: status_op
identifier: status
required: false
remember: false
multiple: false
remember_roles:
authenticated: authenticated
is_grouped: true
group_info:
label: 'Published status'
description: ''
identifier: status
optional: true
widget: select
multiple: false
remember: false
default_group: All
default_group_multiple: { }
group_items:
1:
title: Published
operator: '='
value: '1'
2:
title: Unpublished
operator: '='
value: '0'
plugin_id: boolean
entity_type: node
entity_field: status
type:
id: type
table: node_field_data
field: type
relationship: none
group_type: group
admin_label: ''
operator: in
value: { }
group: 1
exposed: true
expose:
operator_id: type_op
label: 'Content type'
description: ''
use_operator: false
operator: type_op
identifier: type
required: false
remember: false
multiple: false
remember_roles:
authenticated: authenticated
anonymous: '0'
administrator: '0'
reduce: false
is_grouped: false
group_info:
label: ''
description: ''
identifier: ''
optional: true
widget: select
multiple: false
remember: false
default_group: All
default_group_multiple: { }
group_items: { }
plugin_id: bundle
entity_type: node
entity_field: type
title:
id: title
table: node_field_data
field: title
relationship: none
group_type: group
admin_label: ''
operator: contains
value: ''
group: 1
exposed: true
expose:
operator_id: title_op
label: Title
description: ''
use_operator: false
operator: title_op
identifier: title
required: false
remember: false
multiple: false
remember_roles:
authenticated: authenticated
anonymous: '0'
administrator: '0'
is_grouped: false
group_info:
label: ''
description: ''
identifier: ''
optional: true
widget: select
multiple: false
remember: false
default_group: All
default_group_multiple: { }
group_items: { }
plugin_id: string
entity_type: node
entity_field: title
langcode:
id: langcode
table: node_field_data
field: langcode
relationship: none
group_type: group
admin_label: ''
operator: in
value: { }
group: 1
exposed: true
expose:
operator_id: langcode_op
label: Language
description: ''
use_operator: false
operator: langcode_op
identifier: langcode
required: false
remember: false
multiple: false
remember_roles:
authenticated: authenticated
anonymous: '0'
administrator: '0'
reduce: false
is_grouped: false
group_info:
label: ''
description: ''
identifier: ''
optional: true
widget: select
multiple: false
remember: false
default_group: All
default_group_multiple: { }
group_items: { }
plugin_id: language
entity_type: node
entity_field: langcode
sorts: { }
title: Content
empty:
area_text_custom:
id: area_text_custom
table: views
field: area_text_custom
empty: true
content: 'No content available.'
plugin_id: text_custom
arguments: { }
relationships:
uid:
id: uid
table: node_field_data
field: uid
admin_label: author
required: true
plugin_id: standard
show_admin_links: false
filter_groups:
operator: AND
groups:
1: AND
display_extenders: { }
display_plugin: default
display_title: Master
id: default
position: 0
cache_metadata:
contexts:
- 'languages:language_content'
- 'languages:language_interface'
- url
- url.query_args
- user
- 'user.node_grants:view'
- user.permissions
max-age: 0
tags: { }
page_1:
display_options:
path: admin/content/node
menu:
type: 'default tab'
title: Content
description: ''
menu_name: admin
weight: -10
context: ''
tab_options:
type: normal
title: Content
description: 'Find and manage content'
menu_name: admin
weight: -10
display_extenders: { }
display_plugin: page
display_title: Page
id: page_1
position: 1
cache_metadata:
contexts:
- 'languages:language_content'
- 'languages:language_interface'
- url
- url.query_args
- user
- 'user.node_grants:view'
- user.permissions
max-age: 0
tags: { }

View file

@ -119,7 +119,7 @@ display:
field_api_classes: false
filters:
status:
value: true
value: '1'
table: node_field_data
field: status
plugin_id: boolean

View file

@ -0,0 +1,216 @@
langcode: en
status: true
dependencies:
config:
- core.entity_view_mode.node.teaser
- user.role.authenticated
module:
- node
- rest
- user
id: rest_export_with_authorization
label: 'Rest Export'
module: views
description: ''
tag: ''
base_table: node_field_data
base_field: nid
core: 8.x
display:
default:
display_plugin: default
id: default
display_title: Master
position: 0
display_options:
access:
type: role
options:
role:
authenticated: authenticated
cache:
type: tag
options: { }
query:
type: views_query
options:
disable_sql_rewrite: false
distinct: false
replica: false
query_comment: ''
query_tags: { }
exposed_form:
type: basic
options:
submit_button: Apply
reset_button: false
reset_button_label: Reset
exposed_sorts_label: 'Sort by'
expose_sort_order: true
sort_asc_label: Asc
sort_desc_label: Desc
pager:
type: full
options:
items_per_page: 10
offset: 0
id: 0
total_pages: null
expose:
items_per_page: false
items_per_page_label: 'Items per page'
items_per_page_options: '5, 10, 25, 50'
items_per_page_options_all: false
items_per_page_options_all_label: '- All -'
offset: false
offset_label: Offset
tags:
previous: ' Previous'
next: 'Next '
first: '« First'
last: 'Last »'
quantity: 9
style:
type: default
row:
type: 'entity:node'
options:
view_mode: teaser
fields:
title:
id: title
table: node_field_data
field: title
entity_type: node
entity_field: title
label: ''
alter:
alter_text: false
make_link: false
absolute: false
trim: false
word_boundary: false
ellipsis: false
strip_tags: false
html: false
hide_empty: false
empty_zero: false
settings:
link_to_entity: true
plugin_id: field
relationship: none
group_type: group
admin_label: ''
exclude: false
element_type: ''
element_class: ''
element_label_type: ''
element_label_class: ''
element_label_colon: true
element_wrapper_type: ''
element_wrapper_class: ''
element_default_classes: true
empty: ''
hide_alter_empty: true
click_sort_column: value
type: string
group_column: value
group_columns: { }
group_rows: true
delta_limit: 0
delta_offset: 0
delta_reversed: false
delta_first_last: false
multi_type: separator
separator: ', '
field_api_classes: false
filters:
status:
id: status
table: node_field_data
field: status
relationship: none
group_type: group
admin_label: ''
operator: '='
value: '0'
group: 1
exposed: false
expose:
operator_id: ''
label: ''
description: ''
use_operator: false
operator: ''
identifier: ''
required: false
remember: false
multiple: false
remember_roles:
authenticated: authenticated
is_grouped: false
group_info:
label: ''
description: ''
identifier: ''
optional: true
widget: select
multiple: false
remember: false
default_group: All
default_group_multiple: { }
group_items: { }
plugin_id: boolean
entity_type: node
entity_field: status
sorts:
created:
id: created
table: node_field_data
field: created
order: DESC
entity_type: node
entity_field: created
plugin_id: date
relationship: none
group_type: group
admin_label: ''
exposed: false
expose:
label: ''
granularity: second
title: 'Rest Export'
header: { }
footer: { }
empty: { }
relationships: { }
arguments: { }
display_extenders: { }
cache_metadata:
max-age: -1
contexts:
- 'languages:language_content'
- 'languages:language_interface'
- url.query_args
- 'user.node_grants:view'
- user.roles
tags: { }
rest_export_1:
display_plugin: rest_export
id: rest_export_1
display_title: 'REST export'
position: 2
display_options:
display_extenders: { }
path: unpublished-content
auth:
basic_auth: basic_auth
cache_metadata:
max-age: -1
contexts:
- 'languages:language_content'
- 'languages:language_interface'
- request_format
- 'user.node_grants:view'
- user.roles
tags: { }

View file

@ -121,7 +121,7 @@ display:
field_api_classes: false
filters:
status:
value: true
value: '1'
table: node_field_data
field: status
plugin_id: boolean

View file

@ -115,7 +115,7 @@ display:
hide_alter_empty: true
filters:
status:
value: true
value: '1'
table: node_field_data
field: status
plugin_id: boolean

View file

@ -130,7 +130,7 @@ display:
field_api_classes: false
filters:
status:
value: true
value: '1'
table: node_field_data
field: status
plugin_id: boolean

View file

@ -110,7 +110,7 @@ display:
hide_alter_empty: true
filters:
status:
value: true
value: '1'
table: node_field_data
field: status
plugin_id: boolean

View file

@ -0,0 +1,616 @@
langcode: en
status: true
dependencies:
module:
- node
- user
id: test_content_ajax
label: Content
module: node
description: 'Find and manage content.'
tag: default
base_table: node_field_data
base_field: nid
core: 8.x
display:
default:
display_options:
use_ajax: true
access:
type: perm
options:
perm: 'access content overview'
cache:
type: tag
query:
type: views_query
exposed_form:
type: basic
options:
submit_button: Filter
reset_button: true
reset_button_label: Reset
exposed_sorts_label: 'Sort by'
expose_sort_order: true
sort_asc_label: Asc
sort_desc_label: Desc
pager:
type: full
options:
items_per_page: 50
offset: 0
id: 0
tags:
previous: ' Previous'
next: 'Next '
first: '« First'
last: 'Last »'
expose:
items_per_page: true
items_per_page_label: 'Items per page'
items_per_page_options: '5, 10, 25, 50'
items_per_page_options_all: false
items_per_page_options_all_label: '- All -'
offset: false
offset_label: Offset
quantity: 9
style:
type: table
options:
grouping: { }
row_class: ''
default_row_class: true
override: true
sticky: true
caption: ''
summary: ''
description: ''
columns:
node_bulk_form: node_bulk_form
title: title
type: type
name: name
status: status
changed: changed
edit_node: edit_node
delete_node: delete_node
dropbutton: dropbutton
timestamp: title
info:
node_bulk_form:
align: ''
separator: ''
empty_column: false
responsive: ''
title:
sortable: true
default_sort_order: asc
align: ''
separator: ''
empty_column: false
responsive: ''
type:
sortable: true
default_sort_order: asc
align: ''
separator: ''
empty_column: false
responsive: ''
name:
sortable: false
default_sort_order: asc
align: ''
separator: ''
empty_column: false
responsive: priority-low
status:
sortable: true
default_sort_order: asc
align: ''
separator: ''
empty_column: false
responsive: ''
changed:
sortable: true
default_sort_order: desc
align: ''
separator: ''
empty_column: false
responsive: priority-low
edit_node:
sortable: false
default_sort_order: asc
align: ''
separator: ''
empty_column: false
responsive: ''
delete_node:
sortable: false
default_sort_order: asc
align: ''
separator: ''
empty_column: false
responsive: ''
dropbutton:
sortable: false
default_sort_order: asc
align: ''
separator: ''
empty_column: false
responsive: ''
timestamp:
sortable: false
default_sort_order: asc
align: ''
separator: ''
empty_column: false
responsive: ''
default: changed
empty_table: true
row:
type: fields
fields:
node_bulk_form:
id: node_bulk_form
table: node
field: node_bulk_form
label: ''
exclude: false
alter:
alter_text: false
element_class: ''
element_default_classes: true
empty: ''
hide_empty: false
empty_zero: false
hide_alter_empty: true
plugin_id: node_bulk_form
entity_type: node
title:
id: title
table: node_field_data
field: title
label: Title
exclude: false
alter:
alter_text: false
element_class: ''
element_default_classes: true
empty: ''
hide_empty: false
empty_zero: false
hide_alter_empty: true
entity_type: node
entity_field: title
type: string
settings:
link_to_entity: true
plugin_id: field
type:
id: type
table: node_field_data
field: type
relationship: none
group_type: group
admin_label: ''
label: 'Content type'
exclude: false
alter:
alter_text: false
text: ''
make_link: false
path: ''
absolute: false
external: false
replace_spaces: false
path_case: none
trim_whitespace: false
alt: ''
rel: ''
link_class: ''
prefix: ''
suffix: ''
target: ''
nl2br: false
max_length: 0
word_boundary: true
ellipsis: true
more_link: false
more_link_text: ''
more_link_path: ''
strip_tags: false
trim: false
preserve_tags: ''
html: false
element_type: ''
element_class: ''
element_label_type: ''
element_label_class: ''
element_label_colon: true
element_wrapper_type: ''
element_wrapper_class: ''
element_default_classes: true
empty: ''
hide_empty: false
empty_zero: false
hide_alter_empty: true
click_sort_column: target_id
type: entity_reference_label
settings:
link: false
group_column: target_id
group_columns: { }
group_rows: true
delta_limit: 0
delta_offset: 0
delta_reversed: false
delta_first_last: false
multi_type: separator
separator: ', '
field_api_classes: false
entity_type: node
entity_field: type
plugin_id: field
name:
id: name
table: users_field_data
field: name
relationship: uid
label: Author
exclude: false
alter:
alter_text: false
element_class: ''
element_default_classes: true
empty: ''
hide_empty: false
empty_zero: false
hide_alter_empty: true
plugin_id: field
type: user_name
entity_type: user
entity_field: name
status:
id: status
table: node_field_data
field: status
label: Status
exclude: false
alter:
alter_text: false
element_class: ''
element_default_classes: true
empty: ''
hide_empty: false
empty_zero: false
hide_alter_empty: true
type: boolean
settings:
format: custom
format_custom_true: Published
format_custom_false: Unpublished
plugin_id: field
entity_type: node
entity_field: status
changed:
id: changed
table: node_field_data
field: changed
label: Updated
exclude: false
alter:
alter_text: false
element_class: ''
element_default_classes: true
empty: ''
hide_empty: false
empty_zero: false
hide_alter_empty: true
type: timestamp
settings:
date_format: short
custom_date_format: ''
timezone: ''
plugin_id: field
entity_type: node
entity_field: changed
operations:
id: operations
table: node
field: operations
relationship: none
group_type: group
admin_label: ''
label: Operations
exclude: false
alter:
alter_text: false
text: ''
make_link: false
path: ''
absolute: false
external: false
replace_spaces: false
path_case: none
trim_whitespace: false
alt: ''
rel: ''
link_class: ''
prefix: ''
suffix: ''
target: ''
nl2br: false
max_length: 0
word_boundary: true
ellipsis: true
more_link: false
more_link_text: ''
more_link_path: ''
strip_tags: false
trim: false
preserve_tags: ''
html: false
element_type: ''
element_class: ''
element_label_type: ''
element_label_class: ''
element_label_colon: true
element_wrapper_type: ''
element_wrapper_class: ''
element_default_classes: true
empty: ''
hide_empty: false
empty_zero: false
hide_alter_empty: true
destination: true
plugin_id: entity_operations
filters:
status_extra:
id: status_extra
table: node_field_data
field: status_extra
operator: '='
value: false
plugin_id: node_status
group: 1
entity_type: node
status:
id: status
table: node_field_data
field: status
relationship: none
group_type: group
admin_label: ''
operator: '='
value: '1'
group: 1
exposed: true
expose:
operator_id: ''
label: Status
description: ''
use_operator: false
operator: status_op
identifier: status
required: false
remember: false
multiple: false
remember_roles:
authenticated: authenticated
is_grouped: true
group_info:
label: 'Published status'
description: ''
identifier: status
optional: true
widget: select
multiple: false
remember: false
default_group: All
default_group_multiple: { }
group_items:
1:
title: Published
operator: '='
value: '1'
2:
title: Unpublished
operator: '='
value: '0'
plugin_id: boolean
entity_type: node
entity_field: status
type:
id: type
table: node_field_data
field: type
relationship: none
group_type: group
admin_label: ''
operator: in
value: { }
group: 1
exposed: true
expose:
operator_id: type_op
label: 'Content type'
description: ''
use_operator: false
operator: type_op
identifier: type
required: false
remember: false
multiple: false
remember_roles:
authenticated: authenticated
anonymous: '0'
administrator: '0'
reduce: false
is_grouped: false
group_info:
label: ''
description: ''
identifier: ''
optional: true
widget: select
multiple: false
remember: false
default_group: All
default_group_multiple: { }
group_items: { }
plugin_id: bundle
entity_type: node
entity_field: type
title:
id: title
table: node_field_data
field: title
relationship: none
group_type: group
admin_label: ''
operator: contains
value: ''
group: 1
exposed: true
expose:
operator_id: title_op
label: Title
description: ''
use_operator: false
operator: title_op
identifier: title
required: false
remember: false
multiple: false
remember_roles:
authenticated: authenticated
anonymous: '0'
administrator: '0'
is_grouped: false
group_info:
label: ''
description: ''
identifier: ''
optional: true
widget: select
multiple: false
remember: false
default_group: All
default_group_multiple: { }
group_items: { }
plugin_id: string
entity_type: node
entity_field: title
langcode:
id: langcode
table: node_field_data
field: langcode
relationship: none
group_type: group
admin_label: ''
operator: in
value: { }
group: 1
exposed: true
expose:
operator_id: langcode_op
label: Language
description: ''
use_operator: false
operator: langcode_op
identifier: langcode
required: false
remember: false
multiple: false
remember_roles:
authenticated: authenticated
anonymous: '0'
administrator: '0'
reduce: false
is_grouped: false
group_info:
label: ''
description: ''
identifier: ''
optional: true
widget: select
multiple: false
remember: false
default_group: All
default_group_multiple: { }
group_items: { }
plugin_id: language
entity_type: node
entity_field: langcode
sorts: { }
title: Content
empty:
area_text_custom:
id: area_text_custom
table: views
field: area_text_custom
empty: true
content: 'No content available.'
plugin_id: text_custom
arguments: { }
relationships:
uid:
id: uid
table: node_field_data
field: uid
admin_label: author
required: true
plugin_id: standard
show_admin_links: false
filter_groups:
operator: AND
groups:
1: AND
display_extenders: { }
display_plugin: default
display_title: Master
id: default
position: 0
cache_metadata:
contexts:
- 'languages:language_content'
- 'languages:language_interface'
- url
- url.query_args
- user
- 'user.node_grants:view'
- user.permissions
max-age: 0
tags: { }
page_1:
display_options:
path: test-content-ajax
menu:
type: 'default tab'
title: Content
description: ''
menu_name: admin
weight: -10
context: ''
tab_options:
type: normal
title: Content
description: 'Find and manage content'
menu_name: admin
weight: -10
display_extenders: { }
display_plugin: page
display_title: Page
id: page_1
position: 1
cache_metadata:
contexts:
- 'languages:language_content'
- 'languages:language_interface'
- url
- url.query_args
- user
- 'user.node_grants:view'
- user.permissions
max-age: 0
tags: { }

View file

@ -126,7 +126,7 @@ display:
entity_type: node
entity_field: nid
status:
field: status
field: '1'
id: status
table: node_field_data
plugin_id: boolean

View file

@ -109,7 +109,7 @@ display:
hide_alter_empty: true
filters:
status:
value: true
value: '1'
table: node_field_data
field: status
plugin_id: boolean

View file

@ -35,7 +35,7 @@ display:
group: 1
id: status
table: node_field_data
value: true
value: '1'
plugin_id: boolean
entity_type: node
entity_field: status

View file

@ -115,7 +115,7 @@ display:
group: 1
id: status
table: node_field_data
value: true
value: '1'
plugin_id: boolean
entity_type: node
entity_field: status

View file

@ -215,7 +215,7 @@ display:
destination: true
filters:
status:
value: true
value: '1'
table: node_field_data
field: status
id: status

View file

@ -224,7 +224,7 @@ display:
plugin_id: date
filters:
status:
value: true
value: '1'
table: node_field_data
field: status
plugin_id: boolean

View file

@ -144,7 +144,7 @@ display:
plugin_id: field
filters:
status:
value: true
value: '1'
table: node_field_data
field: status
plugin_id: boolean

View file

@ -41,7 +41,7 @@ display:
group: 1
id: status
table: node_field_data
value: true
value: '1'
plugin_id: boolean
entity_type: node
entity_field: status

View file

@ -65,7 +65,7 @@ display:
group: 1
id: status
table: node_field_data
value: true
value: '1'
plugin_id: boolean
entity_type: node
entity_field: status
@ -130,7 +130,7 @@ display:
group: 1
id: status
table: node_field_data
value: true
value: '1'
plugin_id: boolean
entity_type: node
entity_field: status

View file

@ -59,7 +59,7 @@ display:
entity_field: title
filters:
status:
value: true
value: '1'
table: node_field_data
field: status
id: status

View file

@ -107,7 +107,7 @@ display:
comments: false
filters:
status:
value: true
value: '1'
table: node_field_data
field: status
plugin_id: boolean
@ -152,7 +152,7 @@ display:
group_type: group
admin_label: ''
operator: '='
value: true
value: '1'
group: 1
exposed: false
expose:

View file

@ -54,7 +54,7 @@ display:
entity_field: title
filters:
status:
value: true
value: '1'
table: node_field_data
field: status
id: status

View file

@ -59,7 +59,7 @@ display:
entity_field: title
filters:
status:
value: true
value: '1'
table: node_field_data
field: status
id: status

View file

@ -464,7 +464,7 @@ display:
plugin_id: entity_operations
filters:
status:
value: true
value: '1'
table: node_field_data
field: status
plugin_id: boolean

View file

@ -464,7 +464,7 @@ display:
plugin_id: entity_operations
filters:
status:
value: true
value: '1'
table: node_field_data
field: status
plugin_id: boolean

View file

@ -97,7 +97,7 @@ display:
link_to_entity: true
filters:
status:
value: true
value: '1'
table: node_field_data
field: status
id: status
@ -135,7 +135,7 @@ display:
display_description: ''
filters:
status:
value: true
value: '1'
table: node_field_data
field: status
id: status
@ -200,7 +200,7 @@ display:
display_description: ''
filters:
status:
value: true
value: '1'
table: node_field_data
field: status
id: status

View file

@ -96,7 +96,6 @@ display:
footer: { }
empty: { }
relationships: { }
fields: { }
display_extenders: { }
cache_metadata:
contexts:

View file

@ -151,7 +151,7 @@ display:
plugin_id: field
filters:
status:
value: true
value: '1'
table: node_field_data
field: status
plugin_id: boolean

View file

@ -90,7 +90,7 @@ class QueryTest extends QueryPluginBase {
// @todo You could add a string representation of the query.
$this->view->build_info['query'] = "";
$this->view->build_info['count_query'] = "";
}
}
/**
* {@inheritdoc}

View file

@ -0,0 +1,77 @@
<?php
namespace Drupal\Tests\views\FunctionalJavascript;
use Drupal\FunctionalJavascriptTests\JavascriptTestBase;
use Drupal\simpletest\ContentTypeCreationTrait;
use Drupal\simpletest\NodeCreationTrait;
use Drupal\views\Tests\ViewTestData;
/**
* Tests the click sorting AJAX functionality of Views exposed forms.
*
* @group views
*/
class ClickSortingAJAXTest extends JavascriptTestBase {
use ContentTypeCreationTrait;
use NodeCreationTrait;
/**
* {@inheritdoc}
*/
public static $modules = ['node', 'views', 'views_test_config'];
public static $testViews = ['test_content_ajax'];
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
ViewTestData::createTestViews(self::class, ['views_test_config']);
// Create a Content type and two test nodes.
$this->createContentType(['type' => 'page']);
$this->createNode(['title' => 'Page A', 'changed' => REQUEST_TIME]);
$this->createNode(['title' => 'Page B', 'changed' => REQUEST_TIME + 1000]);
// Create a user privileged enough to view content.
$user = $this->drupalCreateUser([
'administer site configuration',
'access content',
'access content overview',
]);
$this->drupalLogin($user);
}
/**
* Tests if sorting via AJAX works for the "Content" View.
*/
public function testClickSorting() {
// Visit the content page.
$this->drupalGet('test-content-ajax');
$session_assert = $this->assertSession();
$page = $this->getSession()->getPage();
// Ensure that the Content we're testing for is in the right order, default
// sorting is by changed timestamp so the last created node should be first.
/** @var \Behat\Mink\Element\NodeElement[] $rows */
$rows = $page->findAll('css', 'tbody tr');
$this->assertCount(2, $rows);
$this->assertContains('Page B', $rows[0]->getHtml());
$this->assertContains('Page A', $rows[1]->getHtml());
// Now sort by title and check if the order changed.
$page->clickLink('Title');
$session_assert->assertWaitOnAjaxRequest();
$rows = $page->findAll('css', 'tbody tr');
$this->assertCount(2, $rows);
$this->assertContains('Page A', $rows[0]->getHtml());
$this->assertContains('Page B', $rows[1]->getHtml());
}
}

View file

@ -0,0 +1,118 @@
<?php
namespace Drupal\Tests\views\FunctionalJavascript;
use Drupal\FunctionalJavascriptTests\JavascriptTestBase;
use Drupal\simpletest\ContentTypeCreationTrait;
use Drupal\simpletest\NodeCreationTrait;
use Drupal\views\Tests\ViewTestData;
/**
* Tests the click sorting AJAX functionality of Views exposed forms.
*
* @group views
*/
class PaginationAJAXTest extends JavascriptTestBase {
use ContentTypeCreationTrait;
use NodeCreationTrait;
/**
* {@inheritdoc}
*/
public static $modules = ['node', 'views', 'views_test_config'];
/**
* @var array
* Test Views to enable.
*/
public static $testViews = ['test_content_ajax'];
protected $user;
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
ViewTestData::createTestViews(self::class, ['views_test_config']);
// Create a Content type and eleven test nodes.
$this->createContentType(['type' => 'page']);
for ($i = 1; $i <= 11; $i++) {
$this->createNode(['title' => 'Node ' . $i . ' content', 'changed' => $i * 1000]);
}
// Create a user privileged enough to view content.
$user = $this->drupalCreateUser([
'administer site configuration',
'access content',
'access content overview',
]);
$this->drupalLogin($user);
}
/**
* Tests if pagination via AJAX works for the "Content" View.
*/
public function testBasicPagination() {
// Visit the content page.
$this->drupalGet('test-content-ajax');
$session_assert = $this->assertSession();
$page = $this->getSession()->getPage();
// Set the number of items displayed per page to 5 using the exposed pager.
$page->selectFieldOption('edit-items-per-page', 5);
$page->pressButton('Filter');
$session_assert->assertWaitOnAjaxRequest();
// Change 'Updated' sorting from descending to ascending.
$page->clickLink('Updated');
$session_assert->assertWaitOnAjaxRequest();
// Use the pager by clicking on the links and test if we see the expected
// number of rows on each page. For easy targeting the titles of the pager
// links are used.
/** @var \Behat\Mink\Element\NodeElement[] $rows */
$rows = $page->findAll('css', 'tbody tr');
$this->assertCount(5, $rows);
$this->assertContains('Node 1 content', $rows[0]->getHtml());
$this->clickLink('Go to page 2');
$session_assert->assertWaitOnAjaxRequest();
$rows = $page->findAll('css', 'tbody tr');
$this->assertCount(5, $rows);
$this->assertContains('Node 6 content', $rows[0]->getHtml());
$this->clickLink('Go to page 3');
$session_assert->assertWaitOnAjaxRequest();
$rows = $page->findAll('css', 'tbody tr');
$this->assertCount(1, $rows);
$this->assertContains('Node 11 content', $rows[0]->getHtml());
// Navigate back to the first page.
$this->clickLink('Go to first page');
$session_assert->assertWaitOnAjaxRequest();
$rows = $page->findAll('css', 'tbody tr');
$this->assertCount(5, $rows);
$this->assertContains('Node 1 content', $rows[0]->getHtml());
// Navigate using the 'next' link.
$this->clickLink('Go to next page');
$session_assert->assertWaitOnAjaxRequest();
$rows = $page->findAll('css', 'tbody tr');
$this->assertCount(5, $rows);
$this->assertContains('Node 6 content', $rows[0]->getHtml());
// Navigate using the 'last' link.
$this->clickLink('Go to last page');
$session_assert->assertWaitOnAjaxRequest();
$rows = $page->findAll('css', 'tbody tr');
$this->assertCount(1, $rows);
$this->assertContains('Node 11 content', $rows[0]->getHtml());
}
}

View file

@ -12,12 +12,17 @@ use Drupal\views\Views;
*/
class FilterCombineTest extends ViewsKernelTestBase {
/**
* {@inheritdoc}
*/
public static $modules = array('entity_test');
/**
* Views used by this test.
*
* @var array
*/
public static $testViews = array('test_view');
public static $testViews = array('test_view', 'entity_test_fields');
/**
* Map column names.
@ -29,6 +34,15 @@ class FilterCombineTest extends ViewsKernelTestBase {
'views_test_data_job' => 'job',
);
/**
* {@inheritdoc}
*/
protected function setUp($import_test_views = TRUE) {
parent::setUp($import_test_views);
$this->installEntitySchema('entity_test');
}
public function testFilterCombineContains() {
$view = Views::getView('test_view');
$view->setDisplay();
@ -126,7 +140,42 @@ class FilterCombineTest extends ViewsKernelTestBase {
$this->assertTrue($view->build_info['fail'], "View build has been marked as failed.");
// Make sure this view does not pass validation with the right error.
$errors = $view->validate();
$this->assertEqual(reset($errors['default']), t('Field %field set in %filter is not set in this display.', array('%field' => 'dummy', '%filter' => 'Global: Combine fields filter')));
$this->assertEquals(t('Field %field set in %filter is not set in display %display.', array('%field' => 'dummy', '%filter' => 'Global: Combine fields filter', '%display' => 'Master')), reset($errors['default']));
}
/**
* Tests that the combine field filter is not valid on displays that don't use
* fields.
*/
public function testNonFieldsRow() {
$view = Views::getView('entity_test_fields');
$view->setDisplay();
// Set the rows to a plugin type that doesn't support fields.
$view->displayHandlers->get('default')->overrideOption('row', array(
'type' => 'entity:entity_test',
'options' => array(
'view_mode' => 'teaser',
),
));
// Change the filtering.
$view->displayHandlers->get('default')->overrideOption('filters', array(
'name' => array(
'id' => 'combine',
'table' => 'views',
'field' => 'combine',
'relationship' => 'none',
'operator' => 'contains',
'fields' => array(
'name',
),
'value' => 'ing',
),
));
$this->executeView($view);
$errors = $view->validate();
// Check that the right error is shown.
$this->assertEquals(t('%display: %filter can only be used on displays that use fields. Set the style or row format for that display to one using fields to use the combine field filter.', array('%filter' => 'Global: Combine fields filter', '%display' => 'Master')), reset($errors['default']));
}
/**

View file

@ -127,7 +127,7 @@ class FilterNumericTest extends ViewsKernelTestBase {
$view->destroy();
$view->setDisplay();
// Change the filtering
// Change the filtering
$view->displayHandlers->get('default')->overrideOption('filters', array(
'age' => array(
'id' => 'age',
@ -148,10 +148,6 @@ class FilterNumericTest extends ViewsKernelTestBase {
'name' => 'John',
'age' => 25,
),
array(
'name' => 'Paul',
'age' => 26,
),
array(
'name' => 'Meredith',
'age' => 30,
@ -208,10 +204,6 @@ class FilterNumericTest extends ViewsKernelTestBase {
'name' => 'John',
'age' => 25,
),
array(
'name' => 'Paul',
'age' => 26,
),
array(
'name' => 'Meredith',
'age' => 30,

View file

@ -297,7 +297,7 @@ class FilterStringTest extends ViewsKernelTestBase {
function testFilterStringGroupedExposedWord() {
$filters = $this->getGroupedExposedFilters();
$filters = $this->getGroupedExposedFilters();
$view = $this->getBasicPageView();
// Filter: Name, Operator: contains, Value: ing

View file

@ -24,61 +24,61 @@ class SortDateTest extends ViewsKernelTestBase {
$expected = array();
if (!$reverse) {
switch ($granularity) {
case 'second':
$expected = array(
array('name' => 'John'),
array('name' => 'Paul'),
array('name' => 'Meredith'),
array('name' => 'Ringo'),
array('name' => 'George'),
);
break;
case 'minute':
$expected = array(
array('name' => 'John'),
array('name' => 'Paul'),
array('name' => 'Ringo'),
array('name' => 'Meredith'),
array('name' => 'George'),
);
break;
case 'hour':
$expected = array(
array('name' => 'John'),
array('name' => 'Ringo'),
array('name' => 'Paul'),
array('name' => 'Meredith'),
array('name' => 'George'),
);
break;
case 'day':
$expected = array(
array('name' => 'John'),
array('name' => 'Ringo'),
array('name' => 'Paul'),
array('name' => 'Meredith'),
array('name' => 'George'),
);
break;
case 'month':
$expected = array(
array('name' => 'John'),
array('name' => 'George'),
array('name' => 'Ringo'),
array('name' => 'Paul'),
array('name' => 'Meredith'),
);
break;
case 'year':
$expected = array(
array('name' => 'John'),
array('name' => 'George'),
array('name' => 'Ringo'),
array('name' => 'Paul'),
array('name' => 'Meredith'),
);
break;
}
case 'second':
$expected = array(
array('name' => 'John'),
array('name' => 'Paul'),
array('name' => 'Meredith'),
array('name' => 'Ringo'),
array('name' => 'George'),
);
break;
case 'minute':
$expected = array(
array('name' => 'John'),
array('name' => 'Paul'),
array('name' => 'Ringo'),
array('name' => 'Meredith'),
array('name' => 'George'),
);
break;
case 'hour':
$expected = array(
array('name' => 'John'),
array('name' => 'Ringo'),
array('name' => 'Paul'),
array('name' => 'Meredith'),
array('name' => 'George'),
);
break;
case 'day':
$expected = array(
array('name' => 'John'),
array('name' => 'Ringo'),
array('name' => 'Paul'),
array('name' => 'Meredith'),
array('name' => 'George'),
);
break;
case 'month':
$expected = array(
array('name' => 'John'),
array('name' => 'George'),
array('name' => 'Ringo'),
array('name' => 'Paul'),
array('name' => 'Meredith'),
);
break;
case 'year':
$expected = array(
array('name' => 'John'),
array('name' => 'George'),
array('name' => 'Ringo'),
array('name' => 'Paul'),
array('name' => 'Meredith'),
);
break;
}
}
else {
switch ($granularity) {

View file

@ -199,7 +199,7 @@ class ModuleTest extends ViewsKernelTestBase {
$expected_opt_groups = array();
foreach ($all_views as $view) {
foreach ($view->get('display') as $display) {
$expected_opt_groups[$view->id()][$view->id() . ':' . $display['id']] = (string) t('@view : @display', array('@view' => $view->id(), '@display' => $display['id']));
$expected_opt_groups[$view->id()][$view->id() . ':' . $display['id']] = (string) t('@view : @display', array('@view' => $view->id(), '@display' => $display['id']));
}
}
$this->assertIdentical($expected_opt_groups, $this->castSafeStrings(Views::getViewsAsOptions(FALSE, 'all', NULL, TRUE)), 'Expected option array for an option group returned.');

View file

@ -6,7 +6,7 @@ use Drupal\views\Views;
use Drupal\Tests\views\Kernel\ViewsKernelTestBase;
use Drupal\views\Plugin\views\style\StylePluginBase;
use Drupal\views\Plugin\views\access\AccessPluginBase;
use Drupal\views\Plugin\views\exposed_form\ExposedFormPluginBase;
use Drupal\views\Plugin\views\exposed_form\ExposedFormPluginInterface;
use Drupal\views\Plugin\views\pager\PagerPluginBase;
use Drupal\views\Plugin\views\query\QueryPluginBase;
use Drupal\views\Plugin\views\cache\CachePluginBase;
@ -96,7 +96,7 @@ class DisplayKernelTest extends ViewsKernelTestBase {
$this->assertTrue($display_handler->getPlugin('access') instanceof AccessPluginBase, 'An access plugin instance was returned.');
$this->assertTrue($display_handler->getPlugin('cache') instanceof CachePluginBase, 'A cache plugin instance was returned.');
$this->assertTrue($display_handler->getPlugin('exposed_form') instanceof ExposedFormPluginBase, 'An exposed_form plugin instance was returned.');
$this->assertTrue($display_handler->getPlugin('exposed_form') instanceof ExposedFormPluginInterface, 'An exposed_form plugin instance was returned.');
$this->assertTrue($display_handler->getPlugin('pager') instanceof PagerPluginBase, 'A pager plugin instance was returned.');
$this->assertTrue($display_handler->getPlugin('query') instanceof QueryPluginBase, 'A query plugin instance was returned.');
$this->assertTrue($display_handler->getPlugin('row') instanceof RowPluginBase, 'A row plugin instance was returned.');

View file

@ -99,7 +99,7 @@ class ViewExecutableTest extends ViewsKernelTestBase {
public function testFactoryService() {
$factory = $this->container->get('views.executable');
$this->assertTrue($factory instanceof ViewExecutableFactory, 'A ViewExecutableFactory instance was returned from the container.');
$view = entity_load('view', 'test_executable_displays');
$view = View::load('test_executable_displays');
$this->assertTrue($factory->get($view) instanceof ViewExecutable, 'A ViewExecutable instance was returned from the factory.');
}

View file

@ -78,7 +78,7 @@ class ViewStorageTest extends ViewsKernelTestBase {
* Tests loading configuration entities.
*/
protected function loadTests() {
$view = entity_load('view', 'test_view_storage');
$view = View::load('test_view_storage');
$data = $this->config('views.view.test_view_storage')->get();
// Confirm that an actual view object is loaded and that it returns all of
@ -143,7 +143,7 @@ class ViewStorageTest extends ViewsKernelTestBase {
// Check the UUID of the loaded View.
$created->save();
$created_loaded = entity_load('view', 'test_view_storage_new');
$created_loaded = View::load('test_view_storage_new');
$this->assertIdentical($created->uuid(), $created_loaded->uuid(), 'The created UUID has been saved correctly.');
}
@ -152,7 +152,7 @@ class ViewStorageTest extends ViewsKernelTestBase {
*/
protected function displayTests() {
// Check whether a display can be added and saved to a View.
$view = entity_load('view', 'test_view_storage_new');
$view = View::load('test_view_storage_new');
$new_id = $view->addDisplay('page', 'Test', 'test');
$display = $view->get('display');

View file

@ -1,6 +1,6 @@
<?php
namespace Drupal\Tests\views\Unit\Controller {
namespace Drupal\Tests\views\Unit\Controller;
use Drupal\Core\Render\RenderContext;
use Drupal\Tests\UnitTestCase;
@ -358,5 +358,3 @@ class ViewAjaxControllerTest extends UnitTestCase {
}
}
}

View file

@ -5,7 +5,7 @@
* Contains \Drupal\Tests\views\Unit\EntityViewsDataTest.
*/
namespace Drupal\Tests\views\Unit {
namespace Drupal\Tests\views\Unit;
use Drupal\Core\Config\Entity\ConfigEntityType;
use Drupal\Core\Entity\ContentEntityType;
@ -568,7 +568,7 @@ class EntityViewsDataTest extends UnitTestCase {
$this->viewsData->setEntityType($entity_type);
// Setup the table mapping.
// Setup the table mapping.
$table_mapping = $this->getMockBuilder(DefaultTableMapping::class)
->disableOriginalConstructor()
->getMock();
@ -717,7 +717,7 @@ class EntityViewsDataTest extends UnitTestCase {
$this->viewsData->setEntityType($entity_type);
// Setup the table mapping.
// Setup the table mapping.
$table_mapping = $this->getMockBuilder(DefaultTableMapping::class)
->disableOriginalConstructor()
->getMock();
@ -1100,12 +1100,10 @@ class TestEntityType extends EntityType {
}
}
namespace Drupal\entity_test\Entity;
namespace Drupal\entity_test\Entity {
if (!function_exists('t')) {
function t($string, array $args = []) {
return strtr($string, $args);
}
if (!function_exists('t')) {
function t($string, array $args = []) {
return strtr($string, $args);
}
}

View file

@ -1,6 +1,6 @@
<?php
namespace Drupal\Tests\views\Unit\Plugin\Block {
namespace Drupal\Tests\views\Unit\Plugin\Block;
use Drupal\Core\DependencyInjection\ContainerBuilder;
use Drupal\Tests\UnitTestCase;
@ -198,13 +198,11 @@ class ViewsBlockTest extends UnitTestCase {
}
}
// @todo https://www.drupal.org/node/2571679 replace
// views_add_contextual_links().
namespace Drupal\views\Plugin\Block;
namespace {
// @todo https://www.drupal.org/node/2571679 replace
// views_add_contextual_links().
if (!function_exists('views_add_contextual_links')) {
function views_add_contextual_links() {
}
if (!function_exists('views_add_contextual_links')) {
function views_add_contextual_links() {
}
}

View file

@ -5,7 +5,7 @@
* Contains \Drupal\Tests\views\Unit\Plugin\field\FieldPluginBaseTest.
*/
namespace Drupal\Tests\views\Unit\Plugin\field {
namespace Drupal\Tests\views\Unit\Plugin\field;
use Drupal\Core\GeneratedUrl;
use Drupal\Core\Language\Language;
@ -692,12 +692,12 @@ class FieldPluginBaseTestField extends FieldPluginBase {
}
}
}
// @todo Remove as part of https://www.drupal.org/node/2529170.
namespace {
if (!function_exists('base_path')) {
function base_path() {
return '/';
}
namespace Drupal\views\Plugin\views\field;
if (!function_exists('base_path')) {
function base_path() {
return '/';
}
}

View file

@ -239,7 +239,7 @@ class SqlTest extends UnitTestCase {
/**
* @covers ::loadEntities
* @covers ::_assignEntitiesToResult
* @covers ::assignEntitiesToResult
*/
public function testLoadEntitiesWithEmptyResult() {
$view = $this->prophesize('Drupal\views\ViewExecutable')->reveal();
@ -261,7 +261,7 @@ class SqlTest extends UnitTestCase {
/**
* @covers ::loadEntities
* @covers ::_assignEntitiesToResult
* @covers ::assignEntitiesToResult
*/
public function testLoadEntitiesWithNoRelationshipAndNoRevision() {
$view = $this->prophesize('Drupal\views\ViewExecutable')->reveal();
@ -317,7 +317,7 @@ class SqlTest extends UnitTestCase {
/**
* @covers ::loadEntities
* @covers ::_assignEntitiesToResult
* @covers ::assignEntitiesToResult
*/
public function testLoadEntitiesWithRelationship() {
// We don't use prophecy, because prophecy enforces methods.
@ -375,7 +375,7 @@ class SqlTest extends UnitTestCase {
/**
* @covers ::loadEntities
* @covers ::_assignEntitiesToResult
* @covers ::assignEntitiesToResult
*/
public function testLoadEntitiesWithNonEntityRelationship() {
// We don't use prophecy, because prophecy enforces methods.
@ -424,7 +424,7 @@ class SqlTest extends UnitTestCase {
/**
* @covers ::loadEntities
* @covers ::_assignEntitiesToResult
* @covers ::assignEntitiesToResult
*/
public function testLoadEntitiesWithRevision() {
// We don't use prophecy, because prophecy enforces methods.
@ -469,7 +469,7 @@ class SqlTest extends UnitTestCase {
/**
* @covers ::loadEntities
* @covers ::_assignEntitiesToResult
* @covers ::assignEntitiesToResult
*/
public function testLoadEntitiesWithRevisionOfSameEntityType() {
// We don't use prophecy, because prophecy enforces methods.
@ -529,7 +529,7 @@ class SqlTest extends UnitTestCase {
/**
* @covers ::loadEntities
* @covers ::_assignEntitiesToResult
* @covers ::assignEntitiesToResult
*/
public function testLoadEntitiesWithRelationshipAndRevision() {
// We don't use prophecy, because prophecy enforces methods.

View file

@ -1,6 +1,6 @@
<?php
namespace Drupal\Tests\views\Unit\Plugin\views\field {
namespace Drupal\Tests\views\Unit\Plugin\views\field;
use Drupal\Tests\UnitTestCase;
use Drupal\views\Plugin\views\field\EntityOperations;
@ -165,5 +165,3 @@ class EntityOperationsUnitTest extends UnitTestCase {
}
}
}

View file

@ -1,6 +1,6 @@
<?php
namespace Drupal\Tests\views\Unit\Routing {
namespace Drupal\Tests\views\Unit\Routing;
use Drupal\Core\Routing\RouteMatch;
use Drupal\Tests\UnitTestCase;
@ -177,13 +177,11 @@ class ViewPageControllerTest extends UnitTestCase {
}
}
// @todo https://www.drupal.org/node/2571679 replace
// views_add_contextual_links().
namespace Drupal\views\Routing;
namespace {
// @todo https://www.drupal.org/node/2571679 replace
// views_add_contextual_links()
if (!function_exists('views_add_contextual_links')) {
function views_add_contextual_links() {
}
if (!function_exists('views_add_contextual_links')) {
function views_add_contextual_links() {
}
}

View file

@ -148,7 +148,7 @@ class ViewsDataTest extends UnitTestCase {
*/
public function testFetchBaseTables() {
$this->setupMockedModuleHandler();
$data = $this->viewsData->get();
$data = $this->viewsData->getAll();
$base_tables = $this->viewsData->fetchBaseTables();
@ -198,7 +198,7 @@ class ViewsDataTest extends UnitTestCase {
->will($this->returnValue(FALSE));
$expected_views_data = $this->viewsDataWithProvider();
$views_data = $this->viewsData->get();
$views_data = $this->viewsData->getAll();
$this->assertSame($expected_views_data, $views_data);
}
@ -271,7 +271,7 @@ class ViewsDataTest extends UnitTestCase {
->method('set')
->with("views_data:$random_table_name:en", array());
$views_data = $this->viewsData->get();
$views_data = $this->viewsData->getAll();
$this->assertSame($expected_views_data, $views_data);
// Request a specific table should be static cached.
@ -288,7 +288,7 @@ class ViewsDataTest extends UnitTestCase {
$this->viewsData->clear();
// Get the views data again.
$this->viewsData->get();
$this->viewsData->getAll();
$this->viewsData->get($table_name);
$this->viewsData->get($table_name_2);
$this->viewsData->get($random_table_name);
@ -312,10 +312,10 @@ class ViewsDataTest extends UnitTestCase {
->with("views_data:en")
->will($this->returnValue(FALSE));
$views_data = $this->viewsData->get();
$views_data = $this->viewsData->getAll();
$this->assertSame($expected_views_data, $views_data);
$views_data = $this->viewsData->get();
$views_data = $this->viewsData->getAll();
$this->assertSame($expected_views_data, $views_data);
}
@ -349,7 +349,7 @@ class ViewsDataTest extends UnitTestCase {
$this->assertSame($expected_views_data[$table_name], $views_data, 'Make sure fetching cached views data by table works as expected.');
// Test that this data is present if all views data is returned.
$views_data = $this->viewsData->get();
$views_data = $this->viewsData->getAll();
$this->assertArrayHasKey($table_name, $views_data, 'Make sure the views_test_data info appears in the total views data.');
$this->assertSame($expected_views_data[$table_name], $views_data[$table_name], 'Make sure the views_test_data has the expected values.');
@ -568,7 +568,7 @@ class ViewsDataTest extends UnitTestCase {
// Initialize the views data cache and repeat with no specified table. This
// should only load the cache entry for all tables.
for ($i = 0; $i < 5; $i++) {
$views_data = $this->viewsData->get();
$views_data = $this->viewsData->getAll();
$this->assertSame($expected_views_data, $views_data);
}
}
@ -595,7 +595,7 @@ class ViewsDataTest extends UnitTestCase {
// Initialize the views data cache and repeat with no specified table. This
// should only load the cache entry for all tables.
for ($i = 0; $i < 5; $i++) {
$views_data = $this->viewsData->get();
$views_data = $this->viewsData->getAll();
$this->assertSame($expected_views_data, $views_data);
}
}
@ -638,4 +638,30 @@ class ViewsDataTest extends UnitTestCase {
$this->assertSame($expected_views_data[$table_name_2], $this->viewsData->get($table_name_2));
}
/**
* Tests that getting all data has same results as getting data with NULL
* logic.
*
* @covers ::getAll
*/
public function testGetAllEqualsToGetNull() {
$expected_views_data = $this->viewsDataWithProvider();
$this->setupMockedModuleHandler();
// Setup a warm cache backend for a single table.
$this->cacheBackend->expects($this->once())
->method('get')
->with("views_data:en");
$this->cacheBackend->expects($this->once())
->method('set')
->with('views_data:en', $expected_views_data);
// Initialize the views data cache and repeat with no specified table. This
// should only load the cache entry for all tables.
for ($i = 0; $i < 5; $i++) {
$this->assertSame($expected_views_data, $this->viewsData->getAll());
$this->assertSame($expected_views_data, $this->viewsData->get());
}
}
}

View file

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

View file

@ -0,0 +1,5 @@
name: Views test checkboxes theme
type: theme
description: Theme for testing Views rendering of checkboxes.
version: VERSION
core: 8.x

View file

@ -0,0 +1,15 @@
<?php
/**
* @file
* Changes an exposed "type" filter from a multi-select to checkboxes.
*/
use Drupal\Core\Form\FormStateInterface;
/**
* Changes an exposed "type" filter from a multi-select to checkboxes.
*/
function views_test_checkboxes_theme_form_views_exposed_form_alter(&$form, FormStateInterface $form_state) {
$form['type']['#type'] = 'checkboxes';
}

View file

@ -392,3 +392,19 @@ function views_update_8101() {
/**
* @} End of "addtogroup updates-8.1.0".
*/
/**
* @addtogroup updates-8.2.0
* @{
*/
/**
* Rebuild the container to add a new container parameter.
*/
function views_update_8200() {
// Empty update to cause a cache rebuild so that the container is rebuilt.
}
/**
* @} End of "addtogroup updates-8.2.0".
*/

View file

@ -182,3 +182,60 @@ function views_post_update_taxonomy_index_tid() {
/**
* @} End of "addtogroup updates-8.1.x".
*/
/**
* @addtogroup updates-8.2.x
* @{
*/
/**
* Fix views with serializer dependencies.
*/
function views_post_update_serializer_dependencies() {
$views = View::loadMultiple();
array_walk($views, function(View $view) {
$old_dependencies = $view->getDependencies();
$new_dependencies = $view->calculateDependencies()->getDependencies();
if ($old_dependencies !== $new_dependencies) {
$view->save();
}
});
}
/**
* Set all boolean filter values to strings.
*/
function views_post_update_boolean_filter_values() {
$config_factory = \Drupal::configFactory();
foreach ($config_factory->listAll('views.view.') as $view_config_name) {
$view = $config_factory->getEditable($view_config_name);
$save = FALSE;
foreach ($view->get('display') as $display_name => $display) {
if (isset($display['display_options']['filters'])) {
foreach ($display['display_options']['filters'] as $filter_name => $filter) {
if (isset($filter['plugin_id']) && $filter['plugin_id'] === 'boolean') {
$new_value = FALSE;
// Update all boolean and integer values to strings.
if ($filter['value'] === TRUE || $filter['value'] === 1) {
$new_value = '1';
}
elseif ($filter['value'] === FALSE || $filter['value'] === 0) {
$new_value = '0';
}
if ($new_value !== FALSE) {
$view->set("display.$display_name.display_options.filters.$filter_name.value", $new_value);
$save = TRUE;
}
}
}
}
}
if ($save) {
$view->save();
}
}
}
/**
* @} End of "addtogroup updates-8.2.x".
*/

View file

@ -2,8 +2,6 @@ views.ajax:
path: '/views/ajax'
defaults:
_controller: '\Drupal\views\Controller\ViewAjaxController::ajaxView'
options:
_theme: ajax_base_page
requirements:
_access: 'TRUE'

View file

@ -114,7 +114,7 @@ function views_views_data() {
$data['views']['combine'] = array(
'title' => t('Combine fields filter'),
'help' => t('Combine two fields together and search by them.'),
'help' => t('Combine multiple fields together and search by them.'),
'filter' => array(
'id' => 'combine',
),