Update to drupal 8.0.0-rc1. For more information, see https://www.drupal.org/node/2582663
This commit is contained in:
parent
eb34d130a8
commit
f32e58e4b1
8476 changed files with 211648 additions and 170042 deletions
|
@ -127,3 +127,7 @@ views.display.attachment:
|
|||
render_pager:
|
||||
type: boolean
|
||||
label: 'Render pager'
|
||||
|
||||
views.display.entity_reference:
|
||||
type: views_display
|
||||
label: 'Entity Reference'
|
||||
|
|
|
@ -85,3 +85,7 @@ views.row.opml_fields:
|
|||
url_field:
|
||||
type: string
|
||||
label: 'URL attribute'
|
||||
|
||||
views.row.entity_reference:
|
||||
type: views.row.fields
|
||||
label: 'Entity Reference inline fields'
|
||||
|
|
|
@ -118,15 +118,23 @@ views.view.*:
|
|||
type: mapping
|
||||
label: 'Cache metadata'
|
||||
mapping:
|
||||
cacheable:
|
||||
type: boolean
|
||||
label: 'Cacheable'
|
||||
max-age:
|
||||
type: integer
|
||||
label: 'Cache maximum age'
|
||||
contexts:
|
||||
type: sequence
|
||||
label: 'Cache contexts'
|
||||
sequence:
|
||||
type: string
|
||||
|
||||
tags:
|
||||
type: sequence
|
||||
label: 'Cache tags'
|
||||
sequence:
|
||||
type: string
|
||||
# Deprecated.
|
||||
cacheable:
|
||||
type: boolean
|
||||
label: 'Cacheable'
|
||||
views_block:
|
||||
type: block_settings
|
||||
label: 'View block'
|
||||
|
|
|
@ -143,3 +143,14 @@ views.style.unformatted_summary:
|
|||
separator:
|
||||
type: string
|
||||
label: 'Separator'
|
||||
|
||||
views.style.entity_reference:
|
||||
type: views_style
|
||||
label: 'Entity Reference list'
|
||||
mapping:
|
||||
search_fields:
|
||||
type: sequence
|
||||
label: 'Search fields'
|
||||
sequence:
|
||||
type: string
|
||||
label: 'Search field'
|
||||
|
|
|
@ -1,28 +0,0 @@
|
|||
/**
|
||||
* @file
|
||||
* Javascript related to contextual links.
|
||||
*/
|
||||
|
||||
(function ($) {
|
||||
|
||||
"use strict";
|
||||
|
||||
/**
|
||||
* Attaches contextual region classes to views elements.
|
||||
*
|
||||
* @type {Drupal~behavior}
|
||||
*
|
||||
* @prop {Drupal~behaviorAttach} attach
|
||||
* Adds class `contextual-region` to views elements.
|
||||
*/
|
||||
Drupal.behaviors.viewsContextualLinks = {
|
||||
attach: function (context) {
|
||||
var id = $('body').attr('data-views-page-contextual-id');
|
||||
|
||||
$('[data-contextual-id="' + id + '"]')
|
||||
.closest(':has(.view)')
|
||||
.addClass('contextual-region');
|
||||
}
|
||||
};
|
||||
|
||||
})(jQuery);
|
|
@ -51,6 +51,7 @@ class View extends RenderElement {
|
|||
$view = $element['#view'];
|
||||
}
|
||||
|
||||
$element += $view->element;
|
||||
$view->element = &$element;
|
||||
// Mark the element as being prerendered, so other code like
|
||||
// \Drupal\views\ViewExecutable::setCurrentPage knows that its no longer
|
||||
|
|
|
@ -215,11 +215,13 @@ class EntityFieldRenderer extends RendererBase {
|
|||
$display_sets = [];
|
||||
foreach ($field_ids as $field_id) {
|
||||
$field = $this->view->field[$field_id];
|
||||
$field_name = $field->definition['field_name'];
|
||||
$index = 0;
|
||||
while (isset($display_sets[$index][$field->definition['field_name']])) {
|
||||
while (isset($display_sets[$index]['field_names'][$field_name])) {
|
||||
$index++;
|
||||
}
|
||||
$display_sets[$index][$field_id] = $field;
|
||||
$display_sets[$index]['field_names'][$field_name] = $field;
|
||||
$display_sets[$index]['field_ids'][$field_id] = $field;
|
||||
}
|
||||
|
||||
// For each set of fields, build the output by bundle.
|
||||
|
@ -231,7 +233,7 @@ class EntityFieldRenderer extends RendererBase {
|
|||
'bundle' => $bundle,
|
||||
'status' => TRUE,
|
||||
]);
|
||||
foreach ($display_fields as $field_id => $field) {
|
||||
foreach ($display_fields['field_ids'] as $field) {
|
||||
$display->setComponent($field->definition['field_name'], [
|
||||
'type' => $field->options['type'],
|
||||
'settings' => $field->options['settings'],
|
||||
|
@ -242,7 +244,7 @@ class EntityFieldRenderer extends RendererBase {
|
|||
// Collect the field render arrays and index them using our internal
|
||||
// row indexes and field IDs.
|
||||
foreach ($display_build as $row_index => $entity_build) {
|
||||
foreach ($display_fields as $field_id => $field) {
|
||||
foreach ($display_fields['field_ids'] as $field_id => $field) {
|
||||
$build[$row_index][$field_id] = !empty($entity_build[$field->definition['field_name']]) ? $entity_build[$field->definition['field_name']] : [];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,9 +7,10 @@
|
|||
|
||||
namespace Drupal\views\Entity\Render;
|
||||
|
||||
use Drupal\Core\Cache\Cache;
|
||||
use Drupal\Core\Cache\CacheableDependencyInterface;
|
||||
use Drupal\Core\Entity\EntityTypeInterface;
|
||||
use Drupal\Core\Language\LanguageManagerInterface;
|
||||
use Drupal\views\Plugin\CacheablePluginInterface;
|
||||
use Drupal\views\Plugin\views\query\QueryPluginBase;
|
||||
use Drupal\views\ResultRow;
|
||||
use Drupal\views\ViewExecutable;
|
||||
|
@ -17,7 +18,7 @@ use Drupal\views\ViewExecutable;
|
|||
/**
|
||||
* Defines a base class for entity renderers.
|
||||
*/
|
||||
abstract class RendererBase implements CacheablePluginInterface {
|
||||
abstract class RendererBase implements CacheableDependencyInterface {
|
||||
|
||||
/**
|
||||
* The view executable wrapping the view storage entity.
|
||||
|
@ -66,8 +67,8 @@ abstract class RendererBase implements CacheablePluginInterface {
|
|||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function isCacheable() {
|
||||
return TRUE;
|
||||
public function getCacheMaxAge() {
|
||||
return Cache::PERMANENT;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -77,6 +78,13 @@ abstract class RendererBase implements CacheablePluginInterface {
|
|||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getCacheTags() {
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Alters the query if needed.
|
||||
*
|
||||
|
|
|
@ -191,7 +191,7 @@ class View extends ConfigEntityBase implements ViewEntityInterface {
|
|||
'display_plugin' => $plugin_id,
|
||||
'id' => $id,
|
||||
// Cast the display title to a string since it is an object.
|
||||
// @see \Drupal\Core\StringTranslation\TranslationWrapper
|
||||
// @see \Drupal\Core\StringTranslation\TranslatableMarkup
|
||||
'display_title' => (string) $title,
|
||||
'position' => $id === 'default' ? 0 : count($this->display),
|
||||
'display_options' => array(),
|
||||
|
@ -286,7 +286,7 @@ class View extends ConfigEntityBase implements ViewEntityInterface {
|
|||
$this->calculatePluginDependencies($display);
|
||||
}
|
||||
|
||||
return $this->dependencies;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -311,8 +311,9 @@ class View extends ConfigEntityBase implements ViewEntityInterface {
|
|||
*
|
||||
* Cache metadata is set per view and per display, and ends up being stored in
|
||||
* the view's configuration. This allows Views to determine very efficiently:
|
||||
* - whether a view is cacheable at all
|
||||
* - what the cache key for a given view should be
|
||||
* - the max-age
|
||||
* - the cache contexts
|
||||
* - the cache tags
|
||||
*
|
||||
* In other words: this allows us to do the (expensive) work of initializing
|
||||
* Views plugins and handlers to determine their effect on the cacheability of
|
||||
|
@ -327,7 +328,10 @@ class View extends ConfigEntityBase implements ViewEntityInterface {
|
|||
$display =& $this->getDisplay($display_id);
|
||||
$executable->setDisplay($display_id);
|
||||
|
||||
list($display['cache_metadata']['cacheable'], $display['cache_metadata']['contexts']) = $executable->getDisplay()->calculateCacheMetadata();
|
||||
$cache_metadata = $executable->getDisplay()->calculateCacheMetadata();
|
||||
$display['cache_metadata']['max-age'] = $cache_metadata->getCacheMaxAge();
|
||||
$display['cache_metadata']['contexts'] = $cache_metadata->getCacheContexts();
|
||||
$display['cache_metadata']['tags'] = $cache_metadata->getCacheTags();
|
||||
// Always include at least the 'languages:' context as there will most
|
||||
// probably be translatable strings in the view output.
|
||||
$display['cache_metadata']['contexts'] = Cache::mergeContexts($display['cache_metadata']['contexts'], ['languages:' . LanguageInterface::TYPE_INTERFACE]);
|
||||
|
|
|
@ -188,7 +188,11 @@ class ViewsEntitySchemaSubscriber implements EntityTypeListenerInterface, EventS
|
|||
}
|
||||
|
||||
foreach ($all_views as $view) {
|
||||
$view->save();
|
||||
// All changes done to the views here can be trusted and this might be
|
||||
// called during updates, when it is not safe to rely on configuration
|
||||
// containing valid schema. Trust the data and disable schema validation
|
||||
// and casting.
|
||||
$view->trustData()->save();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -25,7 +25,7 @@ class ViewsFormMainForm implements FormInterface {
|
|||
public function buildForm(array $form, FormStateInterface $form_state, ViewExecutable $view = NULL, $output = []) {
|
||||
$form['#prefix'] = '<div class="views-form">';
|
||||
$form['#suffix'] = '</div>';
|
||||
$form['#theme'] = 'form';
|
||||
|
||||
$form['#pre_render'][] = 'views_pre_render_views_form_views_form';
|
||||
|
||||
// Add the output markup to the form array so that it's included when the form
|
||||
|
|
|
@ -159,7 +159,7 @@ abstract class ViewsBlockBase extends BlockBase implements ContainerFactoryPlugi
|
|||
);
|
||||
|
||||
if ($this->view->storage->access('edit') && \Drupal::moduleHandler()->moduleExists('views_ui')) {
|
||||
$form['views_label']['#description'] = $this->t('Changing the title here means it cannot be dynamically altered anymore. (Try changing it directly in <a href="@url">@name</a>.)', array('@url' => \Drupal::url('entity.view.edit_display_form', array('view' => $this->view->storage->id(), 'display_id' => $this->displayID)), '@name' => $this->view->storage->label()));
|
||||
$form['views_label']['#description'] = $this->t('Changing the title here means it cannot be dynamically altered anymore. (Try changing it directly in <a href=":url">@name</a>.)', array(':url' => \Drupal::url('entity.view.edit_display_form', array('view' => $this->view->storage->id(), 'display_id' => $this->displayID)), '@name' => $this->view->storage->label()));
|
||||
}
|
||||
else {
|
||||
$form['views_label']['#description'] = $this->t('Changing the title here means it cannot be dynamically altered anymore.');
|
||||
|
|
|
@ -1,35 +0,0 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\views\Plugin\CacheablePluginInterface.
|
||||
*/
|
||||
|
||||
namespace Drupal\views\Plugin;
|
||||
|
||||
/**
|
||||
* Provides caching information about the result cacheability of views plugins.
|
||||
*
|
||||
* For caching on the render level, we rely on bubbling of the cache contexts.
|
||||
*/
|
||||
interface CacheablePluginInterface {
|
||||
|
||||
/**
|
||||
* Returns TRUE if this plugin is cacheable at all.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isCacheable();
|
||||
|
||||
/**
|
||||
* Returns an array of cache contexts, this plugin varies by.
|
||||
*
|
||||
* Note: This method is called on views safe time, so you do have the
|
||||
* configuration available. For example an exposed filter changes its
|
||||
* cacheability depending on the URL.
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
public function getCacheContexts();
|
||||
|
||||
}
|
|
@ -9,6 +9,7 @@ namespace Drupal\views\Plugin\Derivative;
|
|||
|
||||
use Drupal\Core\Entity\EntityStorageInterface;
|
||||
use Drupal\Core\Plugin\Discovery\ContainerDeriverInterface;
|
||||
use Drupal\Core\StringTranslation\TranslatableMarkup;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
|
@ -89,19 +90,24 @@ class ViewsBlock implements ContainerDeriverInterface {
|
|||
// Add a block plugin definition for each block display.
|
||||
if (isset($display) && !empty($display->definition['uses_hook_block'])) {
|
||||
$delta = $view->id() . '-' . $display->display['id'];
|
||||
$desc = $display->getOption('block_description');
|
||||
|
||||
if (empty($desc)) {
|
||||
$admin_label = $display->getOption('block_description');
|
||||
if (empty($admin_label)) {
|
||||
if ($display->display['display_title'] == $display->definition['title']) {
|
||||
$desc = t('!view', array('!view' => $view->label()));
|
||||
$admin_label = $view->label();
|
||||
}
|
||||
else {
|
||||
$desc = t('!view: !display', array('!view' => $view->label(), '!display' => $display->display['display_title']));
|
||||
// Allow translators to control the punctuation. Plugin
|
||||
// definitions get cached, so use TranslatableMarkup() instead of
|
||||
// t() to avoid double escaping when $admin_label is rendered
|
||||
// during requests that use the cached definition.
|
||||
$admin_label = new TranslatableMarkup('@view: @display', ['@view' => $view->label(), '@display' => $display->display['display_title']]);
|
||||
}
|
||||
}
|
||||
|
||||
$this->derivatives[$delta] = array(
|
||||
'category' => $display->getOption('block_category'),
|
||||
'admin_label' => $desc,
|
||||
'admin_label' => $admin_label,
|
||||
'config_dependencies' => array(
|
||||
'config' => array(
|
||||
$view->getConfigDependencyName(),
|
||||
|
|
|
@ -7,10 +7,17 @@
|
|||
|
||||
namespace Drupal\views\Plugin\EntityReferenceSelection;
|
||||
|
||||
use Drupal\Core\Entity\Plugin\EntityReferenceSelection\SelectionBase;
|
||||
use Drupal\Core\Database\Query\SelectInterface;
|
||||
use Drupal\Core\Entity\EntityManagerInterface;
|
||||
use Drupal\Core\Entity\EntityReferenceSelection\SelectionInterface;
|
||||
use Drupal\Core\Extension\ModuleHandlerInterface;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
|
||||
use Drupal\Core\Plugin\PluginBase;
|
||||
use Drupal\Core\Session\AccountInterface;
|
||||
use Drupal\Core\Url;
|
||||
use Drupal\views\Views;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Plugin implementation of the 'selection' entity_reference.
|
||||
|
@ -22,7 +29,66 @@ use Drupal\views\Views;
|
|||
* weight = 0
|
||||
* )
|
||||
*/
|
||||
class ViewsSelection extends SelectionBase {
|
||||
class ViewsSelection extends PluginBase implements SelectionInterface, ContainerFactoryPluginInterface {
|
||||
|
||||
/**
|
||||
* The entity manager.
|
||||
*
|
||||
* @var \Drupal\Core\Entity\EntityManagerInterface
|
||||
*/
|
||||
protected $entityManager;
|
||||
|
||||
/**
|
||||
* The module handler service.
|
||||
*
|
||||
* @var \Drupal\Core\Extension\ModuleHandlerInterface
|
||||
*/
|
||||
protected $moduleHandler;
|
||||
|
||||
/**
|
||||
* The current user.
|
||||
*
|
||||
* @var \Drupal\Core\Session\AccountInterface
|
||||
*/
|
||||
protected $currentUser;
|
||||
|
||||
/**
|
||||
* Constructs a new SelectionBase 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\EntityManagerInterface $entity_manager
|
||||
* The entity manager service.
|
||||
* @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
|
||||
* The module handler service.
|
||||
* @param \Drupal\Core\Session\AccountInterface $current_user
|
||||
* The current user.
|
||||
*/
|
||||
public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityManagerInterface $entity_manager, ModuleHandlerInterface $module_handler, AccountInterface $current_user) {
|
||||
parent::__construct($configuration, $plugin_id, $plugin_definition);
|
||||
|
||||
$this->entityManager = $entity_manager;
|
||||
$this->moduleHandler = $module_handler;
|
||||
$this->currentUser = $current_user;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@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'),
|
||||
$container->get('module_handler'),
|
||||
$container->get('current_user')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* The loaded View object.
|
||||
|
@ -82,9 +148,9 @@ class ViewsSelection extends SelectionBase {
|
|||
else {
|
||||
if ($this->currentUser->hasPermission('administer views') && $this->moduleHandler->moduleExists('views_ui')) {
|
||||
$form['view']['no_view_help'] = array(
|
||||
'#markup' => '<p>' . $this->t('No eligible views were found. <a href="@create">Create a view</a> with an <em>Entity Reference</em> display, or add such a display to an <a href="@existing">existing view</a>.', array(
|
||||
'@create' => Url::fromRoute('views_ui.add')->toString(),
|
||||
'@existing' => Url::fromRoute('entity.view.collection')->toString(),
|
||||
'#markup' => '<p>' . $this->t('No eligible views were found. <a href=":create">Create a view</a> with an <em>Entity Reference</em> display, or add such a display to an <a href=":existing">existing view</a>.', array(
|
||||
':create' => Url::fromRoute('views_ui.add')->toString(),
|
||||
':existing' => Url::fromRoute('entity.view.collection')->toString(),
|
||||
)) . '</p>',
|
||||
);
|
||||
}
|
||||
|
@ -95,6 +161,16 @@ class ViewsSelection extends SelectionBase {
|
|||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function validateConfigurationForm(array &$form, FormStateInterface $form_state) { }
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function submitConfigurationForm(array &$form, FormStateInterface $form_state) { }
|
||||
|
||||
/**
|
||||
* Initializes a view.
|
||||
*
|
||||
|
@ -215,8 +291,6 @@ class ViewsSelection extends SelectionBase {
|
|||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function buildEntityQuery($match = NULL, $match_operator = 'CONTAINS') {
|
||||
throw new \BadMethodCallException('The Views selection plugin does not use the Entity Query system for entity selection.');
|
||||
}
|
||||
public function entityQueryAlter(SelectInterface $query) { }
|
||||
|
||||
}
|
||||
|
|
|
@ -61,7 +61,7 @@ class ViewsMenuLinkForm extends MenuLinkDefaultForm {
|
|||
$id = $view->storage->id();
|
||||
$label = $view->storage->label();
|
||||
if ($this->moduleHandler->moduleExists('views_ui')) {
|
||||
$message = $this->t('This link is provided by the Views module. The path can be changed by editing the view <a href="@url">@label</a>', array('@url' => \Drupal::url('entity.view.edit_form', array('view' => $id)), '@label' => $label));
|
||||
$message = $this->t('This link is provided by the Views module. The path can be changed by editing the view <a href=":url">@label</a>', array(':url' => \Drupal::url('entity.view.edit_form', array('view' => $id)), '@label' => $label));
|
||||
}
|
||||
else {
|
||||
$message = $this->t('This link is provided by the Views module from view %label.', array('%label' => $label));
|
||||
|
|
|
@ -69,7 +69,7 @@ trait BrokenHandlerTrait {
|
|||
$form['description'] = array(
|
||||
'#type' => 'container',
|
||||
'#attributes' => array(
|
||||
'class' => array('form-item', 'description'),
|
||||
'class' => array('js-form-item', 'form-item', 'description'),
|
||||
),
|
||||
'description_top' => array(
|
||||
'#markup' => '<p>' . $description_top . '</p>',
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
namespace Drupal\views\Plugin\views;
|
||||
|
||||
use Drupal\Component\Utility\SafeMarkup;
|
||||
use Drupal\Component\Utility\Html;
|
||||
use Drupal\Component\Utility\Unicode;
|
||||
use Drupal\Component\Utility\UrlHelper;
|
||||
use Drupal\Component\Utility\Xss;
|
||||
|
@ -16,6 +16,7 @@ use Drupal\Core\Form\FormStateInterface;
|
|||
use Drupal\Core\Render\Element;
|
||||
use Drupal\Core\Session\AccountInterface;
|
||||
use Drupal\views\Plugin\views\display\DisplayPluginBase;
|
||||
use Drupal\views\Render\ViewsRenderPipelineMarkup;
|
||||
use Drupal\views\ViewExecutable;
|
||||
use Drupal\Core\Database\Database;
|
||||
use Drupal\views\Views;
|
||||
|
@ -181,11 +182,10 @@ abstract class HandlerBase extends PluginBase implements ViewsHandlerInterface {
|
|||
*/
|
||||
public function adminLabel($short = FALSE) {
|
||||
if (!empty($this->options['admin_label'])) {
|
||||
$title = SafeMarkup::checkPlain($this->options['admin_label']);
|
||||
return $title;
|
||||
return $this->options['admin_label'];
|
||||
}
|
||||
$title = ($short && isset($this->definition['title short'])) ? $this->definition['title short'] : $this->definition['title'];
|
||||
return $this->t('!group: !title', array('!group' => $this->definition['group'], '!title' => $title));
|
||||
return $this->t('@group: @title', array('@group' => $this->definition['group'], '@title' => $title));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -230,13 +230,13 @@ abstract class HandlerBase extends PluginBase implements ViewsHandlerInterface {
|
|||
$value = Xss::filterAdmin($value);
|
||||
break;
|
||||
case 'url':
|
||||
$value = SafeMarkup::checkPlain(UrlHelper::stripDangerousProtocols($value));
|
||||
$value = Html::escape(UrlHelper::stripDangerousProtocols($value));
|
||||
break;
|
||||
default:
|
||||
$value = SafeMarkup::checkPlain($value);
|
||||
$value = Html::escape($value);
|
||||
break;
|
||||
}
|
||||
return $value;
|
||||
return ViewsRenderPipelineMarkup::create($value);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -305,7 +305,9 @@ abstract class HandlerBase extends PluginBase implements ViewsHandlerInterface {
|
|||
'#type' => 'details',
|
||||
'#title' => $this->t('More'),
|
||||
'#weight' => 200,
|
||||
'#optional' => TRUE,
|
||||
);
|
||||
|
||||
// Allow to alter the default values brought into the form.
|
||||
// @todo Do we really want to keep this hook.
|
||||
$this->getModuleHandler()->alter('views_handler_options', $this->options, $this->view);
|
||||
|
|
|
@ -8,13 +8,13 @@
|
|||
namespace Drupal\views\Plugin\views;
|
||||
|
||||
use Drupal\Component\Plugin\DependentPluginInterface;
|
||||
use Drupal\Component\Utility\SafeMarkup;
|
||||
use Drupal\Component\Utility\Xss;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\Language\LanguageInterface;
|
||||
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
|
||||
use Drupal\Core\Plugin\PluginBase as ComponentPluginBase;
|
||||
use Drupal\Core\Render\Element;
|
||||
use Drupal\Core\StringTranslation\TranslatableMarkup;
|
||||
use Drupal\views\Plugin\views\display\DisplayPluginBase;
|
||||
use Drupal\views\ViewExecutable;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
@ -314,9 +314,9 @@ abstract class PluginBase extends ComponentPluginBase implements ContainerFactor
|
|||
public function pluginTitle() {
|
||||
// Short_title is optional so its defaults to an empty string.
|
||||
if (!empty($this->definition['short_title'])) {
|
||||
return SafeMarkup::checkPlain($this->definition['short_title']);
|
||||
return $this->definition['short_title'];
|
||||
}
|
||||
return SafeMarkup::checkPlain($this->definition['title']);
|
||||
return $this->definition['title'];
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -337,10 +337,6 @@ abstract class PluginBase extends ComponentPluginBase implements ContainerFactor
|
|||
* Replaces Views' tokens in a given string. The resulting string will be
|
||||
* sanitized with Xss::filterAdmin.
|
||||
*
|
||||
* This used to be a simple strtr() scattered throughout the code. Some Views
|
||||
* tokens, such as arguments (e.g.: %1 or !1), still use the old format so we
|
||||
* handle those as well as the new Twig-based tokens (e.g.: {{ field_name }})
|
||||
*
|
||||
* @param $text
|
||||
* Unsanitized string with possible tokens.
|
||||
* @param $tokens
|
||||
|
@ -357,34 +353,44 @@ abstract class PluginBase extends ComponentPluginBase implements ContainerFactor
|
|||
return Xss::filterAdmin($text);
|
||||
}
|
||||
|
||||
// Separate Twig tokens from other tokens (e.g.: contextual filter tokens in
|
||||
// the form of %1).
|
||||
$twig_tokens = array();
|
||||
$other_tokens = array();
|
||||
foreach ($tokens as $token => $replacement) {
|
||||
// Twig wants a token replacement array stripped of curly-brackets.
|
||||
// Some Views tokens come with curly-braces, others do not.
|
||||
//@todo: https://www.drupal.org/node/2544392
|
||||
if (strpos($token, '{{') !== FALSE) {
|
||||
// Twig wants a token replacement array stripped of curly-brackets.
|
||||
$token = trim(str_replace(array('{', '}'), '', $token));
|
||||
$token = trim(str_replace(['{{', '}}'], '', $token));
|
||||
}
|
||||
|
||||
// Check for arrays in Twig tokens. Internally these are passed as
|
||||
// dot-delimited strings, but need to be turned into associative arrays
|
||||
// for parsing.
|
||||
if (strpos($token, '.') === FALSE) {
|
||||
// We need to validate tokens are valid Twig variables. Twig uses the
|
||||
// same variable naming rules as PHP.
|
||||
// @see http://php.net/manual/en/language.variables.basics.php
|
||||
assert('preg_match(\'/^[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*$/\', $token) === 1', 'Tokens need to be valid Twig variables.');
|
||||
|
||||
$twig_tokens[$token] = $replacement;
|
||||
}
|
||||
else {
|
||||
$other_tokens[$token] = $replacement;
|
||||
$parts = explode('.', $token);
|
||||
$top = array_shift($parts);
|
||||
assert('preg_match(\'/^[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*$/\', $top) === 1', 'Tokens need to be valid Twig variables.');
|
||||
$token_array = array(array_pop($parts) => $replacement);
|
||||
foreach(array_reverse($parts) as $key) {
|
||||
assert('preg_match(\'/^[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*$/\', $key) === 1', 'Tokens need to be valid Twig variables.');
|
||||
$token_array = array($key => $token_array);
|
||||
}
|
||||
$twig_tokens[$top] = $token_array;
|
||||
}
|
||||
}
|
||||
|
||||
// Non-Twig tokens are a straight string replacement, Twig tokens get run
|
||||
// through an inline template for rendering and replacement.
|
||||
$text = strtr($text, $other_tokens);
|
||||
if ($twig_tokens) {
|
||||
// Use the unfiltered text for the Twig template, then filter the output.
|
||||
// Otherwise, Xss::filterAdmin could remove valid Twig syntax before the
|
||||
// template is parsed.
|
||||
|
||||
$build = array(
|
||||
'#type' => 'inline_template',
|
||||
'#template' => $text,
|
||||
|
@ -396,10 +402,14 @@ abstract class PluginBase extends ComponentPluginBase implements ContainerFactor
|
|||
],
|
||||
);
|
||||
|
||||
return (string) $this->getRenderer()->render($build);
|
||||
// Currently you cannot attach assets to tokens with
|
||||
// Renderer::renderPlain(). This may be unnecessarily limiting. Consider
|
||||
// using Renderer::executeInRenderContext() instead.
|
||||
// @todo: https://www.drupal.org/node/2566621
|
||||
return (string) $this->getRenderer()->renderPlain($build);
|
||||
}
|
||||
else {
|
||||
return $text;
|
||||
return Xss::filterAdmin($text);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -473,7 +483,6 @@ abstract class PluginBase extends ComponentPluginBase implements ContainerFactor
|
|||
unset($form[$key]);
|
||||
}
|
||||
}
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
|
@ -552,7 +561,14 @@ abstract class PluginBase extends ComponentPluginBase implements ContainerFactor
|
|||
// Since this is not a real language, surround it by '***LANGUAGE_...***',
|
||||
// like the negotiated languages below.
|
||||
if ($flags & LanguageInterface::STATE_SITE_DEFAULT) {
|
||||
$list[PluginBase::VIEWS_QUERY_LANGUAGE_SITE_DEFAULT] = $this->t($languages[LanguageInterface::LANGCODE_SITE_DEFAULT]->getName());
|
||||
$name = $languages[LanguageInterface::LANGCODE_SITE_DEFAULT]->getName();
|
||||
// The language name may have already been translated, no need to
|
||||
// translate it again.
|
||||
// @see Drupal\Core\Language::filterLanguages().
|
||||
if (!$name instanceof TranslatableMarkup) {
|
||||
$name = $this->t($name);
|
||||
}
|
||||
$list[PluginBase::VIEWS_QUERY_LANGUAGE_SITE_DEFAULT] = $name;
|
||||
// Remove site default language from $languages so it's not added
|
||||
// twice with the real languages below.
|
||||
unset($languages[LanguageInterface::LANGCODE_SITE_DEFAULT]);
|
||||
|
@ -568,7 +584,7 @@ abstract class PluginBase extends ComponentPluginBase implements ContainerFactor
|
|||
$name = $types_info[$id]['name'];
|
||||
// Surround IDs by '***LANGUAGE_...***', to avoid query collisions.
|
||||
$id = '***LANGUAGE_' . $id . '***';
|
||||
$list[$id] = $this->t('!type language selected for page', array('!type' => $name));
|
||||
$list[$id] = $this->t('@type language selected for page', array('@type' => $name));
|
||||
}
|
||||
}
|
||||
if (!empty($current_values)) {
|
||||
|
@ -578,7 +594,7 @@ abstract class PluginBase extends ComponentPluginBase implements ContainerFactor
|
|||
// add that option too, so it is not lost. If not among the current
|
||||
// values, skip displaying it to avoid user confusion.
|
||||
if (isset($type['name']) && !isset($list[$id]) && in_array($id, $current_values)) {
|
||||
$list[$id] = $this->t('!type language selected for page', array('!type' => $type['name']));
|
||||
$list[$id] = $this->t('@type language selected for page', array('@type' => $type['name']));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -72,9 +72,10 @@ interface ViewsHandlerInterface extends ViewsPluginInterface {
|
|||
* @param $value
|
||||
* The value being rendered.
|
||||
* @param $type
|
||||
* The type of sanitization needed. If not provided, SafeMarkup::checkPlain() is used.
|
||||
* The type of sanitization needed. If not provided,
|
||||
* \Drupal\Component\Utility\Html::escape() is used.
|
||||
*
|
||||
* @return string
|
||||
* @return \Drupal\views\Render\ViewsRenderPipelineMarkup
|
||||
* Returns the safe value.
|
||||
*/
|
||||
public function sanitizeValue($value, $type = NULL);
|
||||
|
|
|
@ -29,6 +29,24 @@ use Symfony\Component\Routing\Route;
|
|||
|
||||
/**
|
||||
* The base plugin to handle access control.
|
||||
*
|
||||
* Access plugins are responsible for controlling a user's access to the view.
|
||||
* Views includes plugins for checking user roles and individual permissions.
|
||||
*
|
||||
* To define an access control plugin, extend this base class. Your access
|
||||
* plugin should have an annotation that includes the plugin's metadata, for
|
||||
* example:
|
||||
* @Plugin(
|
||||
* id = "denyall",
|
||||
* title = @Translation("No Access"),
|
||||
* help = @Translation("Will not be accessible.")
|
||||
* )
|
||||
* The definition should include the following keys:
|
||||
* - id: The unique identifier of your access plugin.
|
||||
* - title: The human-readable name for your access plugin.
|
||||
* - help: A short help message for your plugin.
|
||||
*
|
||||
* @see \Drupal\views\Plugin\ViewsPluginManager
|
||||
*/
|
||||
abstract class AccessPluginBase extends PluginBase {
|
||||
|
||||
|
|
|
@ -113,7 +113,7 @@ class Entity extends TokenizeAreaPluginBase {
|
|||
// display the entity ID to the admin form user.
|
||||
// @todo Use a method to check for tokens in
|
||||
// https://www.drupal.org/node/2396607.
|
||||
if (strpos($this->options['target'], '{{') === FALSE && strpos($this->options['target'], '!') === FALSE && strpos($this->options['target'], '%') === FALSE && strpos($this->options['target'], '[') === FALSE) {
|
||||
if (strpos($this->options['target'], '{{') === FALSE) {
|
||||
// @todo If the entity does not exist, this will will show the config
|
||||
// target identifier. Decide if this is the correct behavior in
|
||||
// https://www.drupal.org/node/2415391.
|
||||
|
@ -146,7 +146,7 @@ class Entity extends TokenizeAreaPluginBase {
|
|||
// @todo Use a method to check for tokens in
|
||||
// https://www.drupal.org/node/2396607.
|
||||
$options = $form_state->getValue('options');
|
||||
if (strpos($options['target'], '{{') === FALSE && strpos($options['target'], '!') === FALSE && strpos($options['target'], '%') === FALSE && strpos($options['target'], '[') === FALSE) {
|
||||
if (strpos($options['target'], '{{') === FALSE) {
|
||||
if ($entity = $this->entityManager->getStorage($this->entityType)->load($options['target'])) {
|
||||
$options['target'] = $entity->getConfigTarget();
|
||||
}
|
||||
|
@ -161,8 +161,10 @@ class Entity extends TokenizeAreaPluginBase {
|
|||
if (!$empty || !empty($this->options['empty'])) {
|
||||
// @todo Use a method to check for tokens in
|
||||
// https://www.drupal.org/node/2396607.
|
||||
if (strpos($this->options['target'], '{{') !== FALSE || strpos($this->options['target'], '!') !== FALSE || strpos($this->options['target'], '%') !== FALSE || strpos($this->options['target'], '[') !== FALSE) {
|
||||
$target_id = $this->tokenizeValue($this->options['target']);
|
||||
if (strpos($this->options['target'], '{{') !== FALSE) {
|
||||
// We cast as we need the integer/string value provided by the
|
||||
// ::tokenizeValue() call.
|
||||
$target_id = (string) $this->tokenizeValue($this->options['target']);
|
||||
if ($entity = $this->entityManager->getStorage($this->entityType)->load($target_id)) {
|
||||
$target_entity = $entity;
|
||||
}
|
||||
|
@ -190,7 +192,7 @@ class Entity extends TokenizeAreaPluginBase {
|
|||
// Ensure that we don't add dependencies for placeholders.
|
||||
// @todo Use a method to check for tokens in
|
||||
// https://www.drupal.org/node/2396607.
|
||||
if (strpos($this->options['target'], '{{') === FALSE && strpos($this->options['target'], '!') === FALSE && strpos($this->options['target'], '%') === FALSE && strpos($this->options['target'], '[') === FALSE) {
|
||||
if (strpos($this->options['target'], '{{') === FALSE) {
|
||||
if ($entity = $this->entityManager->loadEntityByConfigTarget($this->entityType, $this->options['target'])) {
|
||||
$dependencies[$this->entityManager->getDefinition($this->entityType)->getConfigDependencyKey()][] = $entity->getConfigDependencyName();
|
||||
}
|
||||
|
|
|
@ -48,7 +48,7 @@ class HTTPStatusCode extends AreaPluginBase {
|
|||
|
||||
// Add the HTTP status code, so it's easier for people to find it.
|
||||
array_walk($options, function($title, $code) use(&$options) {
|
||||
$options[$code] = $this->t('@code (!title)', array('@code' => $code, '!title' => $title));
|
||||
$options[$code] = $this->t('@code (@title)', array('@code' => $code, '@title' => $title));
|
||||
});
|
||||
|
||||
$form['status_code'] = array(
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
namespace Drupal\views\Plugin\views\area;
|
||||
|
||||
use Drupal\Component\Utility\SafeMarkup;
|
||||
use Drupal\Component\Utility\Html;
|
||||
use Drupal\Component\Utility\Xss;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\views\Plugin\views\style\DefaultSummary;
|
||||
|
@ -87,7 +87,7 @@ class Result extends AreaPluginBase {
|
|||
// @TODO: Maybe use a possible is views empty functionality.
|
||||
// Not every view has total_rows set, use view->result instead.
|
||||
$total = isset($this->view->total_rows) ? $this->view->total_rows : count($this->view->result);
|
||||
$label = SafeMarkup::checkPlain($this->view->storage->label());
|
||||
$label = Html::escape($this->view->storage->label());
|
||||
if ($per_page === 0) {
|
||||
$page_count = 1;
|
||||
$start = 1;
|
||||
|
|
|
@ -52,14 +52,15 @@ abstract class TokenizeAreaPluginBase extends AreaPluginBase {
|
|||
|
||||
// Get a list of the available fields and arguments for token replacement.
|
||||
$options = array();
|
||||
$optgroup_arguments = (string) t('Arguments');
|
||||
$optgroup_fields = (string) t('Fields');
|
||||
foreach ($this->view->display_handler->getHandlers('field') as $field => $handler) {
|
||||
$options[t('Fields')]["[$field]"] = $handler->adminLabel();
|
||||
$options[$optgroup_fields]["{{ $field }}"] = $handler->adminLabel();
|
||||
}
|
||||
|
||||
$count = 0; // This lets us prepare the key as we want it printed.
|
||||
foreach ($this->view->display_handler->getHandlers('argument') as $handler) {
|
||||
$options[t('Arguments')]['%' . ++$count] = $this->t('@argument title', array('@argument' => $handler->adminLabel()));
|
||||
$options[t('Arguments')]['!' . $count] = $this->t('@argument input', array('@argument' => $handler->adminLabel()));
|
||||
foreach ($this->view->display_handler->getHandlers('argument') as $arg => $handler) {
|
||||
$options[$optgroup_arguments]["{{ arguments.$arg }}"] = $this->t('@argument title', array('@argument' => $handler->adminLabel()));
|
||||
$options[$optgroup_arguments]["{{ raw_arguments.$arg }}"] = $this->t('@argument input', array('@argument' => $handler->adminLabel()));
|
||||
}
|
||||
|
||||
if (!empty($options)) {
|
||||
|
@ -75,7 +76,7 @@ abstract class TokenizeAreaPluginBase extends AreaPluginBase {
|
|||
),
|
||||
);
|
||||
$form['tokens']['help'] = array(
|
||||
'#markup' => '<p>' . $this->t('The following tokens are available. If you would like to have the characters \'[\' and \']\' use the HTML entity codes \'%5B\' or \'%5D\' or they will get replaced with empty space.') . '</p>',
|
||||
'#markup' => '<p>' . $this->t('The following tokens are available. You may use Twig syntax in this field.') . '</p>',
|
||||
);
|
||||
foreach (array_keys($options) as $type) {
|
||||
if (!empty($options[$type])) {
|
||||
|
|
|
@ -10,10 +10,10 @@ namespace Drupal\views\Plugin\views\argument;
|
|||
use Drupal\Component\Plugin\DependentPluginInterface;
|
||||
use Drupal\Component\Utility\Html;
|
||||
use Drupal\Component\Utility\NestedArray;
|
||||
use Drupal\Component\Utility\SafeMarkup;
|
||||
use Drupal\Core\Cache\Cache;
|
||||
use Drupal\Core\Cache\CacheableDependencyInterface;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\Render\Element;
|
||||
use Drupal\views\Plugin\CacheablePluginInterface;
|
||||
use Drupal\views\Plugin\views\PluginBase;
|
||||
use Drupal\views\Plugin\views\display\DisplayPluginBase;
|
||||
use Drupal\views\ViewExecutable;
|
||||
|
@ -59,7 +59,7 @@ use Drupal\views\Views;
|
|||
* - numeric: If set to TRUE this field is numeric and will use %d instead of
|
||||
* %s in queries.
|
||||
*/
|
||||
abstract class ArgumentPluginBase extends HandlerBase implements CacheablePluginInterface {
|
||||
abstract class ArgumentPluginBase extends HandlerBase implements CacheableDependencyInterface {
|
||||
|
||||
var $validator = NULL;
|
||||
var $argument = NULL;
|
||||
|
@ -211,7 +211,7 @@ abstract class ArgumentPluginBase extends HandlerBase implements CacheablePlugin
|
|||
'#title_display' => 'invisible',
|
||||
'#size' => 20,
|
||||
'#default_value' => $this->options['exception']['title'],
|
||||
'#description' => $this->t('Override the view and other argument titles. Use "%1" for the first argument, "%2" for the second, etc.'),
|
||||
'#description' => $this->t('Override the view and other argument titles. You may use Twig syntax in this field as well as the "arguments" and "raw_arguments" arrays.'),
|
||||
'#states' => array(
|
||||
'visible' => array(
|
||||
':input[name="options[exception][title_enable]"]' => array('checked' => TRUE),
|
||||
|
@ -249,7 +249,7 @@ abstract class ArgumentPluginBase extends HandlerBase implements CacheablePlugin
|
|||
'#title' => $this->t('Provide title'),
|
||||
'#title_display' => 'invisible',
|
||||
'#default_value' => $this->options['title'],
|
||||
'#description' => $this->t('Override the view and other argument titles. Use "%1" for the first argument, "%2" for the second, etc.'),
|
||||
'#description' => $this->t('Override the view and other argument titles. You may use Twig syntax in this field.'),
|
||||
'#states' => array(
|
||||
'visible' => array(
|
||||
':input[name="options[title_enable]"]' => array('checked' => TRUE),
|
||||
|
@ -258,6 +258,23 @@ abstract class ArgumentPluginBase extends HandlerBase implements CacheablePlugin
|
|||
'#fieldset' => 'argument_present',
|
||||
);
|
||||
|
||||
$output = $this->getTokenHelp();
|
||||
$form['token_help'] = [
|
||||
'#type' => 'details',
|
||||
'#title' => $this->t('Replacement patterns'),
|
||||
'#value' => $output,
|
||||
'#states' => [
|
||||
'visible' => [
|
||||
[
|
||||
':input[name="options[title_enable]"]' => ['checked' => TRUE],
|
||||
],
|
||||
[
|
||||
':input[name="options[exception][title_enable]"]' => ['checked' => TRUE],
|
||||
],
|
||||
],
|
||||
],
|
||||
];
|
||||
|
||||
$form['specify_validation'] = array(
|
||||
'#type' => 'checkbox',
|
||||
'#title' => $this->t('Specify validation criteria'),
|
||||
|
@ -348,6 +365,45 @@ abstract class ArgumentPluginBase extends HandlerBase implements CacheablePlugin
|
|||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Provide token help information for the argument.
|
||||
*
|
||||
* @return array
|
||||
* A render array.
|
||||
*/
|
||||
protected function getTokenHelp() {
|
||||
$output = [];
|
||||
|
||||
foreach ($this->view->display_handler->getHandlers('argument') as $arg => $handler) {
|
||||
/** @var \Drupal\views\Plugin\views\argument\ArgumentPluginBase $handler */
|
||||
$options[(string) t('Arguments')]["{{ arguments.$arg }}"] = $this->t('@argument title', array('@argument' => $handler->adminLabel()));
|
||||
$options[(string) t('Arguments')]["{{ raw_arguments.$arg }}"] = $this->t('@argument input', array('@argument' => $handler->adminLabel()));
|
||||
}
|
||||
|
||||
// We have some options, so make a list.
|
||||
if (!empty($options)) {
|
||||
$output[] = [
|
||||
'#markup' => '<p>' . $this->t("The following replacement tokens are available for this argument.") . '</p>',
|
||||
];
|
||||
foreach (array_keys($options) as $type) {
|
||||
if (!empty($options[$type])) {
|
||||
$items = array();
|
||||
foreach ($options[$type] as $key => $value) {
|
||||
$items[] = $key . ' == ' . $value;
|
||||
}
|
||||
$item_list = array(
|
||||
'#theme' => 'item_list',
|
||||
'#items' => $items,
|
||||
);
|
||||
$output[] = $item_list;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
|
||||
public function validateOptionsForm(&$form, FormStateInterface $form_state) {
|
||||
$option_values = &$form_state->getValue('options');
|
||||
if (empty($option_values)) {
|
||||
|
@ -404,6 +460,16 @@ abstract class ArgumentPluginBase extends HandlerBase implements CacheablePlugin
|
|||
$option_values['summary_options'] = $options;
|
||||
}
|
||||
|
||||
// If the 'Specify validation criteria' checkbox is not checked, reset the
|
||||
// validation options.
|
||||
if (empty($option_values['specify_validation'])) {
|
||||
$option_values['validate']['type'] = 'none';
|
||||
// We need to keep the empty array of options for the 'None' plugin as
|
||||
// it will be needed later.
|
||||
$option_values['validate']['options'] = ['none' => []];
|
||||
$option_values['validate']['fail'] = 'not found';
|
||||
}
|
||||
|
||||
$sanitized_id = $option_values['validate']['type'];
|
||||
// Correct ID for js sanitized version.
|
||||
$option_values['validate']['type'] = $validate_id = static::decodeValidatorId($sanitized_id);
|
||||
|
@ -882,7 +948,7 @@ abstract class ArgumentPluginBase extends HandlerBase implements CacheablePlugin
|
|||
if (empty($value) && !empty($this->definition['empty field name'])) {
|
||||
$value = $this->definition['empty field name'];
|
||||
}
|
||||
return SafeMarkup::checkPlain($value);
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -901,7 +967,7 @@ abstract class ArgumentPluginBase extends HandlerBase implements CacheablePlugin
|
|||
* This usually needs to be overridden to provide a proper title.
|
||||
*/
|
||||
function title() {
|
||||
return SafeMarkup::checkPlain($this->argument);
|
||||
return $this->argument;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1180,24 +1246,24 @@ abstract class ArgumentPluginBase extends HandlerBase implements CacheablePlugin
|
|||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function isCacheable() {
|
||||
$result = TRUE;
|
||||
public function getCacheMaxAge() {
|
||||
$max_age = Cache::PERMANENT;
|
||||
|
||||
// Asks all subplugins (argument defaults, argument validator and styles).
|
||||
if (($plugin = $this->getPlugin('argument_default')) && $plugin instanceof CacheablePluginInterface) {
|
||||
$result &= $plugin->isCacheable();
|
||||
if (($plugin = $this->getPlugin('argument_default')) && $plugin instanceof CacheableDependencyInterface) {
|
||||
$max_age = Cache::mergeMaxAges($max_age, $plugin->getCacheMaxAge());
|
||||
}
|
||||
|
||||
if (($plugin = $this->getPlugin('argument_validator')) && $plugin instanceof CacheablePluginInterface) {
|
||||
$result &= $plugin->isCacheable();
|
||||
if (($plugin = $this->getPlugin('argument_validator')) && $plugin instanceof CacheableDependencyInterface) {
|
||||
$max_age = Cache::mergeMaxAges($max_age, $plugin->getCacheMaxAge());
|
||||
}
|
||||
|
||||
// Summaries use style plugins.
|
||||
if (($plugin = $this->getPlugin('style')) && $plugin instanceof CacheablePluginInterface) {
|
||||
$result &= $plugin->isCacheable();
|
||||
if (($plugin = $this->getPlugin('style')) && $plugin instanceof CacheableDependencyInterface) {
|
||||
$max_age = Cache::mergeMaxAges($max_age, $plugin->getCacheMaxAge());
|
||||
}
|
||||
|
||||
return $result;
|
||||
return $max_age;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1211,21 +1277,43 @@ abstract class ArgumentPluginBase extends HandlerBase implements CacheablePlugin
|
|||
$contexts[] = 'url';
|
||||
|
||||
// Asks all subplugins (argument defaults, argument validator and styles).
|
||||
if (($plugin = $this->getPlugin('argument_default')) && $plugin instanceof CacheablePluginInterface) {
|
||||
$contexts = array_merge($plugin->getCacheContexts(), $contexts);
|
||||
if (($plugin = $this->getPlugin('argument_default')) && $plugin instanceof CacheableDependencyInterface) {
|
||||
$contexts = Cache::mergeContexts($contexts, $plugin->getCacheContexts());
|
||||
}
|
||||
|
||||
if (($plugin = $this->getPlugin('argument_validator')) && $plugin instanceof CacheablePluginInterface) {
|
||||
$contexts = array_merge($plugin->getCacheContexts(), $contexts);
|
||||
if (($plugin = $this->getPlugin('argument_validator')) && $plugin instanceof CacheableDependencyInterface) {
|
||||
$contexts = Cache::mergeContexts($contexts, $plugin->getCacheContexts());
|
||||
}
|
||||
|
||||
if (($plugin = $this->getPlugin('style')) && $plugin instanceof CacheablePluginInterface) {
|
||||
$contexts = array_merge($plugin->getCacheContexts(), $contexts);
|
||||
if (($plugin = $this->getPlugin('style')) && $plugin instanceof CacheableDependencyInterface) {
|
||||
$contexts = Cache::mergeContexts($contexts, $plugin->getCacheContexts());
|
||||
}
|
||||
|
||||
return $contexts;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getCacheTags() {
|
||||
$tags = [];
|
||||
|
||||
// Asks all subplugins (argument defaults, argument validator and styles).
|
||||
if (($plugin = $this->getPlugin('argument_default')) && $plugin instanceof CacheableDependencyInterface) {
|
||||
$tags = Cache::mergeTags($tags, $plugin->getCacheTags());
|
||||
}
|
||||
|
||||
if (($plugin = $this->getPlugin('argument_validator')) && $plugin instanceof CacheableDependencyInterface) {
|
||||
$tags = Cache::mergeTags($tags, $plugin->getCacheTags());
|
||||
}
|
||||
|
||||
if (($plugin = $this->getPlugin('style')) && $plugin instanceof CacheableDependencyInterface) {
|
||||
$tags = Cache::mergeTags($tags, $plugin->getCacheTags());
|
||||
}
|
||||
|
||||
return $tags;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
|
|
@ -1,82 +0,0 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\views\Plugin\views\argument\FieldList.
|
||||
*/
|
||||
|
||||
namespace Drupal\views\Plugin\views\argument;
|
||||
|
||||
use Drupal\Component\Utility\SafeMarkup;
|
||||
use Drupal\Core\Field\AllowedTagsXssTrait;
|
||||
use Drupal\Core\Field\FieldFilteredString;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\views\ViewExecutable;
|
||||
use Drupal\views\Plugin\views\display\DisplayPluginBase;
|
||||
use Drupal\views\Plugin\views\argument\NumericArgument;
|
||||
|
||||
/**
|
||||
* Argument handler for list field to show the human readable name in the
|
||||
* summary.
|
||||
*
|
||||
* @ingroup views_argument_handlers
|
||||
*
|
||||
* @ViewsArgument("field_list")
|
||||
*/
|
||||
class FieldList extends NumericArgument {
|
||||
|
||||
use AllowedTagsXssTrait;
|
||||
|
||||
/**
|
||||
* Stores the allowed values of this field.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
var $allowed_values = NULL;
|
||||
|
||||
/**
|
||||
* Overrides \Drupal\views\Plugin\views\argument\ArgumentPluginBase::init().
|
||||
*/
|
||||
public function init(ViewExecutable $view, DisplayPluginBase $display, array &$options = NULL) {
|
||||
parent::init($view, $display, $options);
|
||||
|
||||
$field_storage_definitions = \Drupal::entityManager()->getFieldStorageDefinitions($this->definition['entity_type']);
|
||||
$field_storage = $field_storage_definitions[$this->definition['field_name']];
|
||||
$this->allowed_values = options_allowed_values($field_storage);
|
||||
}
|
||||
|
||||
protected function defineOptions() {
|
||||
$options = parent::defineOptions();
|
||||
$options['summary']['contains']['human'] = array('default' => FALSE);
|
||||
|
||||
return $options;
|
||||
}
|
||||
|
||||
public function buildOptionsForm(&$form, FormStateInterface $form_state) {
|
||||
parent::buildOptionsForm($form, $form_state);
|
||||
|
||||
$form['summary']['human'] = array(
|
||||
'#title' => $this->t('Display list value as human readable'),
|
||||
'#type' => 'checkbox',
|
||||
'#default_value' => $this->options['summary']['human'],
|
||||
'#states' => array(
|
||||
'visible' => array(
|
||||
':input[name="options[default_action]"]' => array('value' => 'summary'),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
public function summaryName($data) {
|
||||
$value = $data->{$this->name_alias};
|
||||
// If the list element has a human readable name show it,
|
||||
if (isset($this->allowed_values[$value]) && !empty($this->options['summary']['human'])) {
|
||||
return FieldFilteredString::create($this->allowed_values[$value]);
|
||||
}
|
||||
// else fallback to the key.
|
||||
else {
|
||||
return SafeMarkup::checkPlain($value);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,81 +0,0 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\views\Plugin\views\argument\ListString.
|
||||
*/
|
||||
|
||||
namespace Drupal\views\Plugin\views\argument;
|
||||
|
||||
use Drupal\Component\Utility\SafeMarkup;
|
||||
use Drupal\Core\Field\AllowedTagsXssTrait;
|
||||
use Drupal\Core\Field\FieldFilteredString;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\views\ViewExecutable;
|
||||
use Drupal\views\Plugin\views\display\DisplayPluginBase;
|
||||
use Drupal\views\Plugin\views\argument\StringArgument;
|
||||
|
||||
/**
|
||||
* Argument handler for list field to show the human readable name in the
|
||||
* summary.
|
||||
*
|
||||
* @ingroup views_argument_handlers
|
||||
*
|
||||
* @ViewsArgument("field_list_string")
|
||||
*/
|
||||
class ListString extends StringArgument {
|
||||
|
||||
use AllowedTagsXssTrait;
|
||||
|
||||
/**
|
||||
* Stores the allowed values of this field.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
var $allowed_values = NULL;
|
||||
|
||||
/**
|
||||
* Overrides \Drupal\views\Plugin\views\argument\StringArgument::init().
|
||||
*/
|
||||
public function init(ViewExecutable $view, DisplayPluginBase $display, array &$options = NULL) {
|
||||
parent::init($view, $display, $options);
|
||||
|
||||
$field_storage_definitions = \Drupal::entityManager()->getFieldStorageDefinitions($this->definition['entity_type']);
|
||||
$field_storage = $field_storage_definitions[$this->definition['field_name']];
|
||||
$this->allowed_values = options_allowed_values($field_storage);
|
||||
}
|
||||
|
||||
protected function defineOptions() {
|
||||
$options = parent::defineOptions();
|
||||
|
||||
$options['summary']['contains']['human'] = array('default' => FALSE);
|
||||
|
||||
return $options;
|
||||
}
|
||||
|
||||
public function buildOptionsForm(&$form, FormStateInterface $form_state) {
|
||||
parent::buildOptionsForm($form, $form_state);
|
||||
|
||||
$form['summary']['human'] = array(
|
||||
'#title' => $this->t('Display list value as human readable'),
|
||||
'#type' => 'checkbox',
|
||||
'#default_value' => $this->options['summary']['human'],
|
||||
'#states' => array(
|
||||
'visible' => array(
|
||||
':input[name="options[default_action]"]' => array('value' => 'summary'),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
public function summaryName($data) {
|
||||
$value = $data->{$this->name_alias};
|
||||
// If the list element has a human readable name show it,
|
||||
if (isset($this->allowed_values[$value]) && !empty($this->options['summary']['human'])) {
|
||||
$value = $this->allowed_values[$value];
|
||||
}
|
||||
return FieldFilteredString::create($this->caseTransform($value, $this->options['case']));
|
||||
}
|
||||
|
||||
}
|
|
@ -72,7 +72,7 @@ class ManyToOne extends ArgumentPluginBase {
|
|||
'#title' => $this->t('Allow multiple values'),
|
||||
'#description' => $this->t('If selected, users can enter multiple values in the form of 1+2+3 (for OR) or 1,2,3 (for AND).'),
|
||||
'#default_value' => !empty($this->options['break_phrase']),
|
||||
'#fieldset' => 'more',
|
||||
'#group' => 'options][more',
|
||||
);
|
||||
|
||||
$form['add_table'] = array(
|
||||
|
@ -80,14 +80,14 @@ class ManyToOne extends ArgumentPluginBase {
|
|||
'#title' => $this->t('Allow multiple filter values to work together'),
|
||||
'#description' => $this->t('If selected, multiple instances of this filter can work together, as though multiple values were supplied to the same filter. This setting is not compatible with the "Reduce duplicates" setting.'),
|
||||
'#default_value' => !empty($this->options['add_table']),
|
||||
'#fieldset' => 'more',
|
||||
'#group' => 'options][more',
|
||||
);
|
||||
|
||||
$form['require_value'] = array(
|
||||
'#type' => 'checkbox',
|
||||
'#title' => $this->t('Do not display items with no value in summary'),
|
||||
'#default_value' => !empty($this->options['require_value']),
|
||||
'#fieldset' => 'more',
|
||||
'#group' => 'options][more',
|
||||
);
|
||||
|
||||
$this->helper->buildOptionsForm($form, $form_state);
|
||||
|
|
|
@ -35,7 +35,7 @@ class NullArgument extends ArgumentPluginBase {
|
|||
'#title' => $this->t('Fail basic validation if any argument is given'),
|
||||
'#default_value' => !empty($this->options['must_not_be']),
|
||||
'#description' => $this->t('By checking this field, you can use this to make sure views with more arguments than necessary fail validation.'),
|
||||
'#fieldset' => 'more',
|
||||
'#group' => 'options][more',
|
||||
);
|
||||
|
||||
unset($form['exception']);
|
||||
|
|
|
@ -49,7 +49,7 @@ class NumericArgument extends ArgumentPluginBase {
|
|||
'#title' => $this->t('Allow multiple values'),
|
||||
'#description' => $this->t('If selected, users can enter multiple values in the form of 1+2+3 (for OR) or 1,2,3 (for AND).'),
|
||||
'#default_value' => !empty($this->options['break_phrase']),
|
||||
'#fieldset' => 'more',
|
||||
'#group' => 'options][more',
|
||||
);
|
||||
|
||||
$form['not'] = array(
|
||||
|
@ -57,7 +57,7 @@ class NumericArgument extends ArgumentPluginBase {
|
|||
'#title' => $this->t('Exclude'),
|
||||
'#description' => $this->t('If selected, the numbers entered for the filter will be excluded rather than limiting the view.'),
|
||||
'#default_value' => !empty($this->options['not']),
|
||||
'#fieldset' => 'more',
|
||||
'#group' => 'options][more',
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -65,7 +65,7 @@ class StringArgument extends ArgumentPluginBase {
|
|||
'#title' => $this->t('Glossary mode'),
|
||||
'#description' => $this->t('Glossary mode applies a limit to the number of characters used in the filter value, which allows the summary view to act as a glossary.'),
|
||||
'#default_value' => $this->options['glossary'],
|
||||
'#fieldset' => 'more',
|
||||
'#group' => 'options][more',
|
||||
);
|
||||
|
||||
$form['limit'] = array(
|
||||
|
@ -78,7 +78,7 @@ class StringArgument extends ArgumentPluginBase {
|
|||
':input[name="options[glossary]"]' => array('checked' => TRUE),
|
||||
),
|
||||
),
|
||||
'#fieldset' => 'more',
|
||||
'#group' => 'options][more',
|
||||
);
|
||||
|
||||
$form['case'] = array(
|
||||
|
@ -93,7 +93,7 @@ class StringArgument extends ArgumentPluginBase {
|
|||
'ucwords' => $this->t('Capitalize each word'),
|
||||
),
|
||||
'#default_value' => $this->options['case'],
|
||||
'#fieldset' => 'more',
|
||||
'#group' => 'options][more',
|
||||
);
|
||||
|
||||
$form['path_case'] = array(
|
||||
|
@ -108,14 +108,14 @@ class StringArgument extends ArgumentPluginBase {
|
|||
'ucwords' => $this->t('Capitalize each word'),
|
||||
),
|
||||
'#default_value' => $this->options['path_case'],
|
||||
'#fieldset' => 'more',
|
||||
'#group' => 'options][more',
|
||||
);
|
||||
|
||||
$form['transform_dash'] = array(
|
||||
'#type' => 'checkbox',
|
||||
'#title' => $this->t('Transform spaces to dashes in URL'),
|
||||
'#default_value' => $this->options['transform_dash'],
|
||||
'#fieldset' => 'more',
|
||||
'#group' => 'options][more',
|
||||
);
|
||||
|
||||
if (!empty($this->definition['many to one'])) {
|
||||
|
@ -124,14 +124,14 @@ class StringArgument extends ArgumentPluginBase {
|
|||
'#title' => $this->t('Allow multiple filter values to work together'),
|
||||
'#description' => $this->t('If selected, multiple instances of this filter can work together, as though multiple values were supplied to the same filter. This setting is not compatible with the "Reduce duplicates" setting.'),
|
||||
'#default_value' => !empty($this->options['add_table']),
|
||||
'#fieldset' => 'more',
|
||||
'#group' => 'options][more',
|
||||
);
|
||||
|
||||
$form['require_value'] = array(
|
||||
'#type' => 'checkbox',
|
||||
'#title' => $this->t('Do not display items with no value in summary'),
|
||||
'#default_value' => !empty($this->options['require_value']),
|
||||
'#fieldset' => 'more',
|
||||
'#group' => 'options][more',
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -141,7 +141,7 @@ class StringArgument extends ArgumentPluginBase {
|
|||
'#title' => $this->t('Allow multiple values'),
|
||||
'#description' => $this->t('If selected, users can enter multiple values in the form of 1+2+3 (for OR) or 1,2,3 (for AND).'),
|
||||
'#default_value' => !empty($this->options['break_phrase']),
|
||||
'#fieldset' => 'more',
|
||||
'#group' => 'options][more',
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -102,6 +102,13 @@ abstract class ArgumentDefaultPluginBase extends PluginBase {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getCacheTags() {
|
||||
return [];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -7,8 +7,9 @@
|
|||
|
||||
namespace Drupal\views\Plugin\views\argument_default;
|
||||
|
||||
use Drupal\Core\Cache\Cache;
|
||||
use Drupal\Core\Cache\CacheableDependencyInterface;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\views\Plugin\CacheablePluginInterface;
|
||||
|
||||
/**
|
||||
* The fixed argument default handler.
|
||||
|
@ -20,7 +21,7 @@ use Drupal\views\Plugin\CacheablePluginInterface;
|
|||
* title = @Translation("Fixed")
|
||||
* )
|
||||
*/
|
||||
class Fixed extends ArgumentDefaultPluginBase implements CacheablePluginInterface {
|
||||
class Fixed extends ArgumentDefaultPluginBase implements CacheableDependencyInterface {
|
||||
|
||||
protected function defineOptions() {
|
||||
$options = parent::defineOptions();
|
||||
|
@ -48,8 +49,8 @@ class Fixed extends ArgumentDefaultPluginBase implements CacheablePluginInterfac
|
|||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function isCacheable() {
|
||||
return TRUE;
|
||||
public function getCacheMaxAge() {
|
||||
return Cache::PERMANENT;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -7,8 +7,9 @@
|
|||
|
||||
namespace Drupal\views\Plugin\views\argument_default;
|
||||
|
||||
use Drupal\Core\Cache\Cache;
|
||||
use Drupal\Core\Cache\CacheableDependencyInterface;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\views\Plugin\CacheablePluginInterface;
|
||||
|
||||
/**
|
||||
* A query parameter argument default handler.
|
||||
|
@ -20,7 +21,7 @@ use Drupal\views\Plugin\CacheablePluginInterface;
|
|||
* title = @Translation("Query parameter")
|
||||
* )
|
||||
*/
|
||||
class QueryParameter extends ArgumentDefaultPluginBase implements CacheablePluginInterface {
|
||||
class QueryParameter extends ArgumentDefaultPluginBase implements CacheableDependencyInterface {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
|
@ -87,8 +88,8 @@ class QueryParameter extends ArgumentDefaultPluginBase implements CacheablePlugi
|
|||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function isCacheable() {
|
||||
return TRUE;
|
||||
public function getCacheMaxAge() {
|
||||
return Cache::PERMANENT;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -7,10 +7,11 @@
|
|||
|
||||
namespace Drupal\views\Plugin\views\argument_default;
|
||||
|
||||
use Drupal\Core\Cache\Cache;
|
||||
use Drupal\Core\Cache\CacheableDependencyInterface;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\Path\AliasManagerInterface;
|
||||
use Drupal\Core\Path\CurrentPathStack;
|
||||
use Drupal\views\Plugin\CacheablePluginInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
|
||||
|
@ -24,7 +25,7 @@ use Symfony\Component\HttpFoundation\Request;
|
|||
* title = @Translation("Raw value from URL")
|
||||
* )
|
||||
*/
|
||||
class Raw extends ArgumentDefaultPluginBase implements CacheablePluginInterface {
|
||||
class Raw extends ArgumentDefaultPluginBase implements CacheableDependencyInterface {
|
||||
|
||||
/**
|
||||
* The alias manager.
|
||||
|
@ -116,8 +117,8 @@ class Raw extends ArgumentDefaultPluginBase implements CacheablePluginInterface
|
|||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function isCacheable() {
|
||||
return TRUE;
|
||||
public function getCacheMaxAge() {
|
||||
return Cache::PERMANENT;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
namespace Drupal\views\Plugin\views\cache;
|
||||
|
||||
use Drupal\Core\Cache\Cache;
|
||||
use Drupal\Core\Cache\CacheableMetadata;
|
||||
use Drupal\views\Plugin\views\PluginBase;
|
||||
use Drupal\Core\Database\Query\Select;
|
||||
use Drupal\views\ResultRow;
|
||||
|
@ -211,7 +212,7 @@ abstract class CachePluginBase extends PluginBase {
|
|||
'items_per_page' => $this->view->getItemsPerPage(),
|
||||
'offset' => $this->view->getOffset(),
|
||||
];
|
||||
$key_data += \Drupal::service('cache_contexts_manager')->convertTokensToKeys($this->displayHandler->getCacheMetadata()['contexts'])->getKeys();
|
||||
$key_data += \Drupal::service('cache_contexts_manager')->convertTokensToKeys($this->displayHandler->getCacheMetadata()->getCacheContexts())->getKeys();
|
||||
|
||||
$this->resultsKey = $this->view->storage->id() . ':' . $this->displayHandler->display['id'] . ':results:' . hash('sha256', serialize($key_data));
|
||||
}
|
||||
|
@ -288,12 +289,10 @@ abstract class CachePluginBase extends PluginBase {
|
|||
/**
|
||||
* Alters the cache metadata of a display upon saving a view.
|
||||
*
|
||||
* @param bool $is_cacheable
|
||||
* Whether the display is cacheable.
|
||||
* @param string[] $cache_contexts
|
||||
* The cache contexts the display varies by.
|
||||
* @param \Drupal\Core\Cache\CacheableMetadata $cache_metadata
|
||||
* The cache metadata.
|
||||
*/
|
||||
public function alterCacheMetadata(&$is_cacheable, array &$cache_contexts) {
|
||||
public function alterCacheMetadata(CacheableMetadata $cache_metadata) {
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
namespace Drupal\views\Plugin\views\cache;
|
||||
|
||||
use Drupal\Core\Datetime\DateFormatter;
|
||||
use Drupal\Core\Datetime\DateFormatterInterface;
|
||||
use Drupal\Core\Cache\Cache;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
|
@ -34,7 +34,7 @@ class Time extends CachePluginBase {
|
|||
/**
|
||||
* The date formatter service.
|
||||
*
|
||||
* @var \Drupal\Core\Datetime\DateFormatter
|
||||
* @var \Drupal\Core\Datetime\DateFormatterInterface
|
||||
*/
|
||||
protected $dateFormatter;
|
||||
|
||||
|
@ -54,12 +54,12 @@ class Time extends CachePluginBase {
|
|||
* The plugin_id for the plugin instance.
|
||||
* @param mixed $plugin_definition
|
||||
* The plugin implementation definition.
|
||||
* @param \Drupal\Core\Datetime\DateFormatter $date_formatter
|
||||
* @param \Drupal\Core\Datetime\DateFormatterInterface $date_formatter
|
||||
* The date formatter service.
|
||||
* @param \Symfony\Component\HttpFoundation\Request $request
|
||||
* The current request.
|
||||
*/
|
||||
public function __construct(array $configuration, $plugin_id, $plugin_definition, DateFormatter $date_formatter, Request $request) {
|
||||
public function __construct(array $configuration, $plugin_id, $plugin_definition, DateFormatterInterface $date_formatter, Request $request) {
|
||||
$this->dateFormatter = $date_formatter;
|
||||
$this->request = $request;
|
||||
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
|
||||
namespace Drupal\views\Plugin\views\display;
|
||||
|
||||
use Drupal\Component\Utility\SafeMarkup;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\views\ViewExecutable;
|
||||
|
||||
|
@ -92,7 +91,7 @@ class Attachment extends DisplayPluginBase {
|
|||
elseif (count($displays) == 1) {
|
||||
$display = array_shift($displays);
|
||||
if ($display = $this->view->storage->getDisplay($display)) {
|
||||
$attach_to = SafeMarkup::checkPlain($display['display_title']);
|
||||
$attach_to = $display['display_title'];
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -204,7 +203,7 @@ class Attachment extends DisplayPluginBase {
|
|||
'#title' => $this->t('Displays'),
|
||||
'#type' => 'checkboxes',
|
||||
'#description' => $this->t('Select which display or displays this should attach to.'),
|
||||
'#options' => $displays,
|
||||
'#options' => array_map('\Drupal\Component\Utility\Html::escape', $displays),
|
||||
'#default_value' => $this->getOption('displays'),
|
||||
);
|
||||
break;
|
||||
|
|
|
@ -196,7 +196,7 @@ class Block extends DisplayPluginBase {
|
|||
$form['block_category'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#autocomplete_route_name' => 'block.category_autocomplete',
|
||||
'#description' => $this->t('The category this block will appear under on the <a href="@href">blocks placement page</a>.', array('@href' => \Drupal::url('block.admin_display'))),
|
||||
'#description' => $this->t('The category this block will appear under on the <a href=":href">blocks placement page</a>.', array(':href' => \Drupal::url('block.admin_display'))),
|
||||
'#default_value' => $this->getOption('block_category'),
|
||||
);
|
||||
break;
|
||||
|
|
|
@ -9,10 +9,10 @@ namespace Drupal\views\Plugin\views\display;
|
|||
|
||||
use Drupal\Component\Plugin\DependentPluginInterface;
|
||||
use Drupal\Component\Utility\Html;
|
||||
use Drupal\Component\Utility\Unicode;
|
||||
use Drupal\Component\Utility\SafeMarkup;
|
||||
use Drupal\Core\Cache\Cache;
|
||||
use Drupal\Core\Cache\CacheableMetadata;
|
||||
use Drupal\Core\Cache\CacheableDependencyInterface;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\Language\LanguageInterface;
|
||||
use Drupal\Core\Plugin\PluginDependencyTrait;
|
||||
|
@ -20,7 +20,6 @@ use Drupal\Core\Session\AccountInterface;
|
|||
use Drupal\Core\Theme\Registry;
|
||||
use Drupal\Core\Url;
|
||||
use Drupal\views\Form\ViewsForm;
|
||||
use Drupal\views\Plugin\CacheablePluginInterface;
|
||||
use Drupal\views\Plugin\views\area\AreaPluginBase;
|
||||
use Drupal\views\ViewExecutable;
|
||||
use Drupal\views\Plugin\views\PluginBase;
|
||||
|
@ -1130,7 +1129,7 @@ abstract class DisplayPluginBase extends PluginBase implements DisplayPluginInte
|
|||
);
|
||||
}
|
||||
|
||||
$display_comment = Unicode::substr($this->getOption('display_comment'), 0, 10);
|
||||
$display_comment = views_ui_truncate($this->getOption('display_comment'), 80);
|
||||
$options['display_comment'] = array(
|
||||
'category' => 'other',
|
||||
'title' => $this->t('Administrative comment'),
|
||||
|
@ -1455,7 +1454,7 @@ abstract class DisplayPluginBase extends PluginBase implements DisplayPluginInte
|
|||
$form['css_class'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => $this->t('CSS class name(s)'),
|
||||
'#description' => $this->t('Seperate multiples classes by spaces.'),
|
||||
'#description' => $this->t('Separate multiple classes by spaces.'),
|
||||
'#default_value' => $this->getOption('css_class'),
|
||||
);
|
||||
break;
|
||||
|
@ -1544,8 +1543,8 @@ abstract class DisplayPluginBase extends PluginBase implements DisplayPluginInte
|
|||
$access_plugin = $this->getPlugin('access');
|
||||
if ($access_plugin->usesOptions()) {
|
||||
$form['markup'] = array(
|
||||
'#prefix' => '<div class="form-item description">',
|
||||
'#markup' => $this->t('You may also adjust the !settings for the currently selected access restriction.', array('!settings' => $this->optionLink(t('settings'), 'access_options'))),
|
||||
'#prefix' => '<div class="js-form-item form-item description">',
|
||||
'#markup' => $this->t('You may also adjust the @settings for the currently selected access restriction.', array('@settings' => $this->optionLink($this->t('settings'), 'access_options'))),
|
||||
'#suffix' => '</div>',
|
||||
);
|
||||
}
|
||||
|
@ -1581,9 +1580,9 @@ abstract class DisplayPluginBase extends PluginBase implements DisplayPluginInte
|
|||
$cache_plugin = $this->getPlugin('cache');
|
||||
if ($cache_plugin->usesOptions()) {
|
||||
$form['markup'] = array(
|
||||
'#prefix' => '<div class="form-item description">',
|
||||
'#prefix' => '<div class="js-form-item form-item description">',
|
||||
'#suffix' => '</div>',
|
||||
'#markup' => $this->t('You may also adjust the !settings for the currently selected cache mechanism.', array('!settings' => $this->optionLink(t('settings'), 'cache_options'))),
|
||||
'#markup' => $this->t('You may also adjust the @settings for the currently selected cache mechanism.', array('@settings' => $this->optionLink($this->t('settings'), 'cache_options'))),
|
||||
);
|
||||
}
|
||||
break;
|
||||
|
@ -1653,9 +1652,9 @@ abstract class DisplayPluginBase extends PluginBase implements DisplayPluginInte
|
|||
|
||||
if ($style_plugin->usesOptions()) {
|
||||
$form['markup'] = array(
|
||||
'#prefix' => '<div class="form-item description">',
|
||||
'#prefix' => '<div class="js-form-item form-item description">',
|
||||
'#suffix' => '</div>',
|
||||
'#markup' => $this->t('You may also adjust the !settings for the currently selected style.', array('!settings' => $this->optionLink(t('settings'), 'style_options'))),
|
||||
'#markup' => $this->t('You may also adjust the @settings for the currently selected style.', array('@settings' => $this->optionLink($this->t('settings'), 'style_options'))),
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -1701,9 +1700,9 @@ abstract class DisplayPluginBase extends PluginBase implements DisplayPluginInte
|
|||
|
||||
if ($row_plugin_instance->usesOptions()) {
|
||||
$form['markup'] = array(
|
||||
'#prefix' => '<div class="form-item description">',
|
||||
'#prefix' => '<div class="js-form-item form-item description">',
|
||||
'#suffix' => '</div>',
|
||||
'#markup' => $this->t('You may also adjust the !settings for the currently selected row style.', array('!settings' => $this->optionLink(t('settings'), 'row_options'))),
|
||||
'#markup' => $this->t('You may also adjust the @settings for the currently selected row style.', array('@settings' => $this->optionLink($this->t('settings'), 'row_options'))),
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -1726,17 +1725,24 @@ abstract class DisplayPluginBase extends PluginBase implements DisplayPluginInte
|
|||
);
|
||||
|
||||
$options = array();
|
||||
$count = 0; // This lets us prepare the key as we want it printed.
|
||||
foreach ($this->view->display_handler->getHandlers('argument') as $handler) {
|
||||
$options[t('Arguments')]['%' . ++$count] = $this->t('@argument title', array('@argument' => $handler->adminLabel()));
|
||||
$options[t('Arguments')]['!' . $count] = $this->t('@argument input', array('@argument' => $handler->adminLabel()));
|
||||
$optgroup_arguments = (string) t('Arguments');
|
||||
foreach ($this->view->display_handler->getHandlers('argument') as $arg => $handler) {
|
||||
$options[$optgroup_arguments]["{{ arguments.$arg }}"] = $this->t('@argument title', array('@argument' => $handler->adminLabel()));
|
||||
$options[$optgroup_arguments]["{{ raw_arguments.$arg }}"] = $this->t('@argument input', array('@argument' => $handler->adminLabel()));
|
||||
}
|
||||
|
||||
// Default text.
|
||||
// We have some options, so make a list.
|
||||
$output = '';
|
||||
$description = [];
|
||||
$description[] = [
|
||||
'#markup' => $this->t('A Drupal path or external URL the more link will point to. Note that this will override the link display setting above.'),
|
||||
];
|
||||
if (!empty($options)) {
|
||||
$output = $this->t('<p>The following tokens are available for this link.</p>');
|
||||
$description[] = [
|
||||
'#prefix' => '<p>',
|
||||
'#markup' => $this->t('The following tokens are available for this link. You may use Twig syntax in this field.'),
|
||||
'#suffix' => '</p>',
|
||||
];
|
||||
foreach (array_keys($options) as $type) {
|
||||
if (!empty($options[$type])) {
|
||||
$items = array();
|
||||
|
@ -1746,9 +1752,8 @@ abstract class DisplayPluginBase extends PluginBase implements DisplayPluginInte
|
|||
$item_list = array(
|
||||
'#theme' => 'item_list',
|
||||
'#items' => $items,
|
||||
'#list_type' => $type,
|
||||
);
|
||||
$output .= drupal_render($item_list);
|
||||
$description[] = $item_list;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1757,7 +1762,7 @@ abstract class DisplayPluginBase extends PluginBase implements DisplayPluginInte
|
|||
'#type' => 'textfield',
|
||||
'#title' => $this->t('Custom URL'),
|
||||
'#default_value' => $this->getOption('link_url'),
|
||||
'#description' => $this->t('A Drupal path or external URL the more link will point to. Note that this will override the link display setting above.') . $output,
|
||||
'#description' => $description,
|
||||
'#states' => array(
|
||||
'visible' => array(
|
||||
':input[name="link_display"]' => array('value' => 'custom_url'),
|
||||
|
@ -1768,7 +1773,7 @@ abstract class DisplayPluginBase extends PluginBase implements DisplayPluginInte
|
|||
case 'exposed_block':
|
||||
$form['#title'] .= $this->t('Put the exposed form in a block');
|
||||
$form['description'] = array(
|
||||
'#markup' => '<div class="description form-item">' . $this->t('If set, any exposed widgets will not appear with this view. Instead, a block will be made available to the Drupal block administration system, and the exposed form will appear there. Note that this block must be enabled manually, Views will not enable it for you.') . '</div>',
|
||||
'#markup' => '<div class="js-form-item form-item description">' . $this->t('If set, any exposed widgets will not appear with this view. Instead, a block will be made available to the Drupal block administration system, and the exposed form will appear there. Note that this block must be enabled manually, Views will not enable it for you.') . '</div>',
|
||||
);
|
||||
$form['exposed_block'] = array(
|
||||
'#type' => 'radios',
|
||||
|
@ -1796,9 +1801,9 @@ abstract class DisplayPluginBase extends PluginBase implements DisplayPluginInte
|
|||
$exposed_form_plugin = $this->getPlugin('exposed_form');
|
||||
if ($exposed_form_plugin->usesOptions()) {
|
||||
$form['markup'] = array(
|
||||
'#prefix' => '<div class="form-item description">',
|
||||
'#prefix' => '<div class="js-form-item form-item description">',
|
||||
'#suffix' => '</div>',
|
||||
'#markup' => $this->t('You may also adjust the !settings for the currently selected style.', array('!settings' => $this->optionLink(t('settings'), 'exposed_form_options'))),
|
||||
'#markup' => $this->t('You may also adjust the @settings for the currently selected style.', array('@settings' => $this->optionLink($this->t('settings'), 'exposed_form_options'))),
|
||||
);
|
||||
}
|
||||
break;
|
||||
|
@ -1832,9 +1837,9 @@ abstract class DisplayPluginBase extends PluginBase implements DisplayPluginInte
|
|||
$pager_plugin = $this->getPlugin('pager');
|
||||
if ($pager_plugin->usesOptions()) {
|
||||
$form['markup'] = array(
|
||||
'#prefix' => '<div class="form-item description">',
|
||||
'#prefix' => '<div class="js-form-item form-item description">',
|
||||
'#suffix' => '</div>',
|
||||
'#markup' => $this->t('You may also adjust the !settings for the currently selected pager.', array('!settings' => $this->optionLink(t('settings'), 'pager_options'))),
|
||||
'#markup' => $this->t('You may also adjust the @settings for the currently selected pager.', array('@settings' => $this->optionLink($this->t('settings'), 'pager_options'))),
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -2144,9 +2149,9 @@ abstract class DisplayPluginBase extends PluginBase implements DisplayPluginInte
|
|||
$cache = $this->getPlugin('cache');
|
||||
|
||||
(new CacheableMetadata())
|
||||
->setCacheTags($this->view->getCacheTags())
|
||||
->setCacheTags(Cache::mergeTags($this->view->getCacheTags(), isset($this->display['cache_metadata']['tags']) ? $this->display['cache_metadata']['tags'] : []))
|
||||
->setCacheContexts(isset($this->display['cache_metadata']['contexts']) ? $this->display['cache_metadata']['contexts'] : [])
|
||||
->setCacheMaxAge($cache->getCacheMaxAge())
|
||||
->setCacheMaxAge(Cache::mergeMaxAges($cache->getCacheMaxAge(), isset($this->display['cache_metadata']['max-age']) ? $this->display['cache_metadata']['max-age'] : Cache::PERMANENT))
|
||||
->merge(CacheableMetadata::createFromRenderArray($element))
|
||||
->applyTo($element);
|
||||
}
|
||||
|
@ -2218,7 +2223,9 @@ abstract class DisplayPluginBase extends PluginBase implements DisplayPluginInte
|
|||
public function renderArea($area, $empty = FALSE) {
|
||||
$return = array();
|
||||
foreach ($this->getHandlers($area) as $key => $area_handler) {
|
||||
$return[$key] = $area_handler->render($empty);
|
||||
if ($area_render = $area_handler->render($empty)) {
|
||||
$return[$key] = $area_render;
|
||||
}
|
||||
}
|
||||
return $return;
|
||||
}
|
||||
|
@ -2264,18 +2271,13 @@ abstract class DisplayPluginBase extends PluginBase implements DisplayPluginInte
|
|||
* {@inheritdoc}
|
||||
*/
|
||||
public function calculateCacheMetadata () {
|
||||
$is_cacheable = TRUE;
|
||||
$cache_contexts = [];
|
||||
$cache_metadata = new CacheableMetadata();
|
||||
|
||||
// Iterate over ordinary views plugins.
|
||||
foreach (Views::getPluginTypes('plugin') as $plugin_type) {
|
||||
$plugin = $this->getPlugin($plugin_type);
|
||||
if ($plugin instanceof CacheablePluginInterface) {
|
||||
$cache_contexts = array_merge($cache_contexts, $plugin->getCacheContexts());
|
||||
$is_cacheable &= $plugin->isCacheable();
|
||||
}
|
||||
else {
|
||||
$is_cacheable = FALSE;
|
||||
if ($plugin instanceof CacheableDependencyInterface) {
|
||||
$cache_metadata = $cache_metadata->merge(CacheableMetadata::createFromObject($plugin));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2284,19 +2286,18 @@ abstract class DisplayPluginBase extends PluginBase implements DisplayPluginInte
|
|||
foreach (array_keys(Views::getHandlerTypes()) as $handler_type) {
|
||||
$handlers = $this->getHandlers($handler_type);
|
||||
foreach ($handlers as $handler) {
|
||||
if ($handler instanceof CacheablePluginInterface) {
|
||||
$cache_contexts = array_merge($cache_contexts, $handler->getCacheContexts());
|
||||
$is_cacheable &= $handler->isCacheable();
|
||||
if ($handler instanceof CacheableDependencyInterface) {
|
||||
$cache_metadata = $cache_metadata->merge(CacheableMetadata::createFromObject($handler));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** @var \Drupal\views\Plugin\views\cache\CachePluginBase $cache_plugin */
|
||||
if ($cache_plugin = $this->getPlugin('cache')) {
|
||||
$cache_plugin->alterCacheMetadata($is_cacheable, $cache_contexts);
|
||||
$cache_plugin->alterCacheMetadata($cache_metadata);
|
||||
}
|
||||
|
||||
return [(bool) $is_cacheable, $cache_contexts];
|
||||
return $cache_metadata;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -2304,9 +2305,18 @@ abstract class DisplayPluginBase extends PluginBase implements DisplayPluginInte
|
|||
*/
|
||||
public function getCacheMetadata() {
|
||||
if (!isset($this->display['cache_metadata'])) {
|
||||
list($this->display['cache_metadata']['cacheable'], $this->display['cache_metadata']['contexts']) = $this->calculateCacheMetadata();
|
||||
$cache_metadata = $this->calculateCacheMetadata();
|
||||
$this->display['cache_metadata']['max-age'] = $cache_metadata->getCacheMaxAge();
|
||||
$this->display['cache_metadata']['contexts'] = $cache_metadata->getCacheContexts();
|
||||
$this->display['cache_metadata']['tags'] = $cache_metadata->getCacheTags();
|
||||
}
|
||||
return $this->display['cache_metadata'];
|
||||
else {
|
||||
$cache_metadata = (new CacheableMetadata())
|
||||
->setCacheMaxAge($this->display['cache_metadata']['max-age'])
|
||||
->setCacheContexts($this->display['cache_metadata']['contexts'])
|
||||
->setCacheTags($this->display['cache_metadata']['tags']);
|
||||
}
|
||||
return $cache_metadata;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -2380,19 +2390,9 @@ abstract class DisplayPluginBase extends PluginBase implements DisplayPluginInte
|
|||
}
|
||||
|
||||
/**
|
||||
* Returns the display type that this display requires.
|
||||
*
|
||||
* This can be used for filtering views plugins. E.g. if a plugin category of
|
||||
* 'foo' is specified, only plugins with no 'types' declared or 'types'
|
||||
* containing 'foo'. If you have a type of bar, this plugin will not be used.
|
||||
* This is applicable for style, row, access, cache, and exposed_form plugins.
|
||||
*
|
||||
* @return string
|
||||
* The required display type. Defaults to 'normal'.
|
||||
*
|
||||
* @see \Drupal\views\Views::fetchPluginNames()
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getType() {
|
||||
public function getType() {
|
||||
return 'normal';
|
||||
}
|
||||
|
||||
|
|
|
@ -429,20 +429,16 @@ interface DisplayPluginInterface {
|
|||
/**
|
||||
* Calculates the display's cache metadata by inspecting each handler/plugin.
|
||||
*
|
||||
* @return array
|
||||
* Returns an array:
|
||||
* - first value: (boolean) Whether the display is cacheable.
|
||||
* - second value: (string[]) The cache contexts the display varies by.
|
||||
* @return \Drupal\Core\Cache\CacheableMetadata
|
||||
* The cache metadata.
|
||||
*/
|
||||
public function calculateCacheMetadata();
|
||||
|
||||
/**
|
||||
* Gets the cache metadata.
|
||||
*
|
||||
* @return array
|
||||
* Returns an array:
|
||||
* - first value: (boolean) Whether the display is cacheable.
|
||||
* - second value: (string[]) The cache contexts the display varies by.
|
||||
* @return \Drupal\Core\Cache\CacheableMetadata
|
||||
* The cache metadata.
|
||||
*/
|
||||
public function getCacheMetadata();
|
||||
|
||||
|
@ -495,6 +491,21 @@ interface DisplayPluginInterface {
|
|||
*/
|
||||
function preview();
|
||||
|
||||
/**
|
||||
* Returns the display type that this display requires.
|
||||
*
|
||||
* This can be used for filtering views plugins. E.g. if a plugin category of
|
||||
* 'foo' is specified, only plugins with no 'types' declared or 'types'
|
||||
* containing 'foo'. If you have a type of bar, this plugin will not be used.
|
||||
* This is applicable for style, row, access, cache, and exposed_form plugins.
|
||||
*
|
||||
* @return string
|
||||
* The required display type. Defaults to 'normal'.
|
||||
*
|
||||
* @see \Drupal\views\Views::fetchPluginNames()
|
||||
*/
|
||||
public function getType();
|
||||
|
||||
/**
|
||||
* Make sure the display and all associated handlers are valid.
|
||||
*
|
||||
|
|
180
core/modules/views/src/Plugin/views/display/EntityReference.php
Normal file
180
core/modules/views/src/Plugin/views/display/EntityReference.php
Normal file
|
@ -0,0 +1,180 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\views\Plugin\views\display\EntityReference.
|
||||
*/
|
||||
|
||||
namespace Drupal\views\Plugin\views\display;
|
||||
|
||||
/**
|
||||
* The plugin that handles an EntityReference display.
|
||||
*
|
||||
* "entity_reference_display" is a custom property, used with
|
||||
* \Drupal\views\Views::getApplicableViews() to retrieve all views with a
|
||||
* 'Entity Reference' display.
|
||||
*
|
||||
* @ingroup views_display_plugins
|
||||
*
|
||||
* @ViewsDisplay(
|
||||
* id = "entity_reference",
|
||||
* title = @Translation("Entity Reference"),
|
||||
* admin = @Translation("Entity Reference Source"),
|
||||
* help = @Translation("Selects referenceable entities for an entity reference field."),
|
||||
* theme = "views_view",
|
||||
* register_theme = FALSE,
|
||||
* uses_menu_links = FALSE,
|
||||
* entity_reference_display = TRUE
|
||||
* )
|
||||
*/
|
||||
class EntityReference extends DisplayPluginBase {
|
||||
|
||||
/**
|
||||
* Overrides \Drupal\views\Plugin\views\display\DisplayPluginBase::$useAJAX.
|
||||
*/
|
||||
protected $usesAJAX = FALSE;
|
||||
|
||||
/**
|
||||
* Overrides \Drupal\views\Plugin\views\display\DisplayPluginBase::$usesPager.
|
||||
*/
|
||||
protected $usesPager = FALSE;
|
||||
|
||||
/**
|
||||
* Overrides \Drupal\views\Plugin\views\display\DisplayPluginBase::$usesAttachments.
|
||||
*/
|
||||
protected $usesAttachments = FALSE;
|
||||
|
||||
/**
|
||||
* Overrides \Drupal\views\Plugin\views\display\DisplayPluginBase::defineOptions().
|
||||
*/
|
||||
protected function defineOptions() {
|
||||
$options = parent::defineOptions();
|
||||
|
||||
// Force the style plugin to 'entity_reference_style' and the row plugin to
|
||||
// 'fields'.
|
||||
$options['style']['contains']['type'] = array('default' => 'entity_reference');
|
||||
$options['defaults']['default']['style'] = FALSE;
|
||||
$options['row']['contains']['type'] = array('default' => 'entity_reference');
|
||||
$options['defaults']['default']['row'] = FALSE;
|
||||
|
||||
// Make sure the query is not cached.
|
||||
$options['defaults']['default']['cache'] = FALSE;
|
||||
|
||||
// Set the display title to an empty string (not used in this display type).
|
||||
$options['title']['default'] = '';
|
||||
$options['defaults']['default']['title'] = FALSE;
|
||||
|
||||
return $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides \Drupal\views\Plugin\views\display\DisplayPluginBase::optionsSummary().
|
||||
*
|
||||
* Disable 'cache' and 'title' so it won't be changed.
|
||||
*/
|
||||
public function optionsSummary(&$categories, &$options) {
|
||||
parent::optionsSummary($categories, $options);
|
||||
unset($options['query']);
|
||||
unset($options['title']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides \Drupal\views\Plugin\views\display\DisplayPluginBase::getType().
|
||||
*/
|
||||
public function getType() {
|
||||
return 'entity_reference';
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides \Drupal\views\Plugin\views\display\DisplayPluginBase::execute().
|
||||
*/
|
||||
public function execute() {
|
||||
return $this->view->render($this->display['id']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides \Drupal\views\Plugin\views\display\DisplayPluginBase::render().
|
||||
*/
|
||||
public function render() {
|
||||
if (!empty($this->view->result) && $this->view->style_plugin->evenEmpty()) {
|
||||
return $this->view->style_plugin->render($this->view->result);
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides \Drupal\views\Plugin\views\display\DisplayPluginBase::usesExposed().
|
||||
*/
|
||||
public function usesExposed() {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides \Drupal\views\Plugin\views\display\DisplayPluginBase::query().
|
||||
*/
|
||||
public function query() {
|
||||
if (!empty($this->view->live_preview)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Make sure the id field is included in the results.
|
||||
$id_field = $this->view->storage->get('base_field');
|
||||
$this->id_field_alias = $this->view->query->addField($this->view->storage->get('base_table'), $id_field);
|
||||
|
||||
$options = $this->getOption('entity_reference_options');
|
||||
|
||||
// Restrict the autocomplete options based on what's been typed already.
|
||||
if (isset($options['match'])) {
|
||||
$style_options = $this->getOption('style');
|
||||
$value = db_like($options['match']) . '%';
|
||||
if ($options['match_operator'] != 'STARTS_WITH') {
|
||||
$value = '%' . $value;
|
||||
}
|
||||
|
||||
// Multiple search fields are OR'd together.
|
||||
$conditions = db_or();
|
||||
|
||||
// Build the condition using the selected search fields.
|
||||
foreach ($style_options['options']['search_fields'] as $field_id) {
|
||||
if (!empty($field_id)) {
|
||||
// Get the table and field names for the checked field.
|
||||
$field_alias = $this->view->query->addField($this->view->field[$field_id]->table, $field_id);
|
||||
$field = $this->view->query->fields[$field_alias];
|
||||
// Add an OR condition for the field.
|
||||
$conditions->condition($field['table'] . '.' . $field['field'], $value, 'LIKE');
|
||||
}
|
||||
}
|
||||
|
||||
$this->view->query->addWhere(0, $conditions);
|
||||
}
|
||||
|
||||
// Add an IN condition for validation.
|
||||
if (!empty($options['ids'])) {
|
||||
$this->view->query->addWhere(0, $id_field, $options['ids']);
|
||||
}
|
||||
|
||||
$this->view->setItemsPerPage($options['limit']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides \Drupal\views\Plugin\views\display\DisplayPluginBase::validate().
|
||||
*/
|
||||
public function validate() {
|
||||
$errors = parent::validate();
|
||||
// Verify that search fields are set up.
|
||||
$style = $this->getOption('style');
|
||||
if (!isset($style['options']['search_fields'])) {
|
||||
$errors[] = $this->t('Display "@display" needs a selected search fields to work properly. See the settings for the Entity Reference list format.', array('@display' => $this->display['display_title']));
|
||||
}
|
||||
else {
|
||||
// Verify that the search fields used actually exist.
|
||||
$fields = array_keys($this->handlers['field']);
|
||||
foreach ($style['options']['search_fields'] as $field_alias => $enabled) {
|
||||
if ($enabled && !in_array($field_alias, $fields)) {
|
||||
$errors[] = $this->t('Display "@display" uses field %field as search field, but the field is no longer present. See the settings for the Entity Reference list format.', array('@display' => $this->display['display_title'], '%field' => $field_alias));
|
||||
}
|
||||
}
|
||||
}
|
||||
return $errors;
|
||||
}
|
||||
}
|
|
@ -7,7 +7,6 @@
|
|||
|
||||
namespace Drupal\views\Plugin\views\display;
|
||||
|
||||
use Drupal\Component\Utility\SafeMarkup;
|
||||
use Drupal\Core\Cache\CacheableMetadata;
|
||||
use Drupal\Core\Cache\CacheableResponse;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
|
@ -49,7 +48,7 @@ class Feed extends PathPluginBase implements ResponseDisplayPluginInterface {
|
|||
/**
|
||||
* Overrides \Drupal\views\Plugin\views\display\DisplayPluginBase::getType().
|
||||
*/
|
||||
protected function getType() {
|
||||
public function getType() {
|
||||
return 'feed';
|
||||
}
|
||||
|
||||
|
@ -204,7 +203,7 @@ class Feed extends PathPluginBase implements ResponseDisplayPluginInterface {
|
|||
$display = array_shift($displays);
|
||||
$displays = $this->view->storage->get('display');
|
||||
if (!empty($displays[$display])) {
|
||||
$attach_to = SafeMarkup::checkPlain($displays[$display]['display_title']);
|
||||
$attach_to = $displays[$display]['display_title'];
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -256,7 +255,7 @@ class Feed extends PathPluginBase implements ResponseDisplayPluginInterface {
|
|||
'#title' => $this->t('Displays'),
|
||||
'#type' => 'checkboxes',
|
||||
'#description' => $this->t('The feed icon will be available only to the selected displays.'),
|
||||
'#options' => $displays,
|
||||
'#options' => array_map('\Drupal\Component\Utility\Html::escape', $displays),
|
||||
'#default_value' => $this->getOption('displays'),
|
||||
);
|
||||
break;
|
||||
|
|
|
@ -366,7 +366,7 @@ class Page extends PathPluginBase {
|
|||
}
|
||||
|
||||
$form['tab_markup'] = array(
|
||||
'#markup' => '<div class="form-item description">' . $this->t('When providing a menu item as a tab, Drupal needs to know what the parent menu item of that tab will be. Sometimes the parent will already exist, but other times you will need to have one created. The path of a parent item will always be the same path with the last part left off. i.e, if the path to this view is <em>foo/bar/baz</em>, the parent path would be <em>foo/bar</em>.') . '</div>',
|
||||
'#markup' => '<div class="js-form-item form-item description">' . $this->t('When providing a menu item as a tab, Drupal needs to know what the parent menu item of that tab will be. Sometimes the parent will already exist, but other times you will need to have one created. The path of a parent item will always be the same path with the last part left off. i.e, if the path to this view is <em>foo/bar/baz</em>, the parent path would be <em>foo/bar</em>.') . '</div>',
|
||||
);
|
||||
|
||||
$form['tab_options'] = array(
|
||||
|
|
|
@ -7,11 +7,12 @@
|
|||
|
||||
namespace Drupal\views\Plugin\views\exposed_form;
|
||||
|
||||
use Drupal\Component\Utility\SafeMarkup;
|
||||
use Drupal\Component\Utility\Html;
|
||||
use Drupal\Core\Cache\Cache;
|
||||
use Drupal\Core\Cache\CacheableDependencyInterface;
|
||||
use Drupal\Core\Form\FormState;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\views\Form\ViewsExposedForm;
|
||||
use Drupal\views\Plugin\CacheablePluginInterface;
|
||||
use Drupal\views\ViewExecutable;
|
||||
use Drupal\views\Plugin\views\display\DisplayPluginBase;
|
||||
use Drupal\views\Plugin\views\PluginBase;
|
||||
|
@ -35,7 +36,7 @@ use Drupal\views\Plugin\views\PluginBase;
|
|||
/**
|
||||
* Base class for Views exposed filter form plugins.
|
||||
*/
|
||||
abstract class ExposedFormPluginBase extends PluginBase implements CacheablePluginInterface {
|
||||
abstract class ExposedFormPluginBase extends PluginBase implements CacheableDependencyInterface {
|
||||
|
||||
/**
|
||||
* Overrides Drupal\views\Plugin\Plugin::$usesOptions.
|
||||
|
@ -211,7 +212,7 @@ abstract class ExposedFormPluginBase extends PluginBase implements CacheablePlug
|
|||
$exposed_sorts = array();
|
||||
foreach ($this->view->sort as $id => $handler) {
|
||||
if ($handler->canExpose() && $handler->isExposed()) {
|
||||
$exposed_sorts[$id] = SafeMarkup::checkPlain($handler->options['expose']['label']);
|
||||
$exposed_sorts[$id] = Html::escape($handler->options['expose']['label']);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -336,8 +337,8 @@ abstract class ExposedFormPluginBase extends PluginBase implements CacheablePlug
|
|||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function isCacheable() {
|
||||
return TRUE;
|
||||
public function getCacheMaxAge() {
|
||||
return Cache::PERMANENT;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -364,6 +365,13 @@ abstract class ExposedFormPluginBase extends PluginBase implements CacheablePlug
|
|||
return $contexts;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getCacheTags() {
|
||||
return [];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -73,6 +73,9 @@ class InputRequired extends ExposedFormPluginBase {
|
|||
}
|
||||
|
||||
public function preRender($values) {
|
||||
// Display the "text on demand" if needed. This is a site builder-defined
|
||||
// text to display instead of results until the user selects and applies
|
||||
// an exposed filter.
|
||||
if (!$this->exposedFilterApplied()) {
|
||||
$options = array(
|
||||
'id' => 'area',
|
||||
|
@ -81,14 +84,22 @@ class InputRequired extends ExposedFormPluginBase {
|
|||
'label' => '',
|
||||
'relationship' => 'none',
|
||||
'group_type' => 'group',
|
||||
'content' => $this->options['text_input_required'],
|
||||
'format' => $this->options['text_input_required_format'],
|
||||
// We need to set the "Display even if view has no result" option to
|
||||
// TRUE as the input required exposed form plugin will always force an
|
||||
// empty result if no exposed filters are applied.
|
||||
'empty' => TRUE,
|
||||
'content' => [
|
||||
// @see \Drupal\views\Plugin\views\area\Text::render()
|
||||
'value' => $this->options['text_input_required'],
|
||||
'format' => $this->options['text_input_required_format'],
|
||||
],
|
||||
);
|
||||
$handler = Views::handlerManager('area')->getHandler($options);
|
||||
$handler->init($this->view, $this->displayHandler, $options);
|
||||
$this->displayHandler->handlers['empty'] = array(
|
||||
'area' => $handler,
|
||||
);
|
||||
// Override the existing empty result message (if applicable).
|
||||
$this->displayHandler->setOption('empty', array('text' => $options));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ namespace Drupal\views\Plugin\views\field;
|
|||
|
||||
use Drupal\Component\Utility\Xss as UtilityXss;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\views\Render\ViewsRenderPipelineMarkup;
|
||||
use Drupal\views\ResultRow;
|
||||
use Drupal\views\ViewExecutable;
|
||||
use Drupal\views\Plugin\views\display\DisplayPluginBase;
|
||||
|
@ -118,7 +119,8 @@ class Boolean extends FieldPluginBase {
|
|||
}
|
||||
|
||||
if ($this->options['type'] == 'custom') {
|
||||
return $value ? UtilityXss::filterAdmin($this->options['type_custom_true']) : UtilityXss::filterAdmin($this->options['type_custom_false']);
|
||||
$custom_value = $value ? $this->options['type_custom_true'] : $this->options['type_custom_false'];
|
||||
return ViewsRenderPipelineMarkup::create(UtilityXss::filterAdmin($custom_value));
|
||||
}
|
||||
elseif (isset($this->formats[$this->options['type']])) {
|
||||
return $value ? $this->formats[$this->options['type']][0] : $this->formats[$this->options['type']][1];
|
||||
|
|
|
@ -11,7 +11,7 @@ use Drupal\Core\Entity\EntityStorageInterface;
|
|||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\views\ResultRow;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
use Drupal\Core\Datetime\DateFormatter;
|
||||
use Drupal\Core\Datetime\DateFormatterInterface;
|
||||
|
||||
/**
|
||||
* A handler to provide proper displays for dates.
|
||||
|
@ -25,7 +25,7 @@ class Date extends FieldPluginBase {
|
|||
/**
|
||||
* The date formatter service.
|
||||
*
|
||||
* @var \Drupal\Core\Datetime\DateFormatter
|
||||
* @var \Drupal\Core\Datetime\DateFormatterInterface
|
||||
*/
|
||||
protected $dateFormatter;
|
||||
|
||||
|
@ -45,12 +45,12 @@ class Date extends FieldPluginBase {
|
|||
* The plugin ID for the plugin instance.
|
||||
* @param mixed $plugin_definition
|
||||
* The plugin implementation definition.
|
||||
* @param \Drupal\Core\Datetime\DateFormatter $date_formatter
|
||||
* @param \Drupal\Core\Datetime\DateFormatterInterface $date_formatter
|
||||
* The date formatter service.
|
||||
* @param \Drupal\Core\Entity\EntityStorageInterface $date_format_storage
|
||||
* The date format storage.
|
||||
*/
|
||||
public function __construct(array $configuration, $plugin_id, $plugin_definition, DateFormatter $date_formatter, EntityStorageInterface $date_format_storage) {
|
||||
public function __construct(array $configuration, $plugin_id, $plugin_definition, DateFormatterInterface $date_formatter, EntityStorageInterface $date_format_storage) {
|
||||
parent::__construct($configuration, $plugin_id, $plugin_definition);
|
||||
|
||||
$this->dateFormatter = $date_formatter;
|
||||
|
|
|
@ -9,7 +9,9 @@ namespace Drupal\views\Plugin\views\field;
|
|||
|
||||
use Drupal\Core\Entity\EntityManagerInterface;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\Language\LanguageManagerInterface;
|
||||
use Drupal\Core\Routing\RedirectDestinationTrait;
|
||||
use Drupal\views\Entity\Render\EntityTranslationRenderTrait;
|
||||
use Drupal\views\ResultRow;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
|
@ -22,6 +24,7 @@ use Symfony\Component\DependencyInjection\ContainerInterface;
|
|||
*/
|
||||
class EntityOperations extends FieldPluginBase {
|
||||
|
||||
use EntityTranslationRenderTrait;
|
||||
use RedirectDestinationTrait;
|
||||
|
||||
/**
|
||||
|
@ -31,6 +34,13 @@ class EntityOperations extends FieldPluginBase {
|
|||
*/
|
||||
protected $entityManager;
|
||||
|
||||
/**
|
||||
* The language manager.
|
||||
*
|
||||
* @var \Drupal\Core\Language\LanguageManagerInterface
|
||||
*/
|
||||
protected $languageManager;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
|
@ -42,10 +52,14 @@ class EntityOperations extends FieldPluginBase {
|
|||
* The plugin implementation definition.
|
||||
* @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager
|
||||
* The entity manager.
|
||||
* @param \Drupal\Core\Language\LanguageManagerInterface $language_manager
|
||||
* The language manager.
|
||||
*/
|
||||
public function __construct(array $configuration, $plugin_id, array $plugin_definition, EntityManagerInterface $entity_manager) {
|
||||
public function __construct(array $configuration, $plugin_id, array $plugin_definition, EntityManagerInterface $entity_manager, LanguageManagerInterface $language_manager) {
|
||||
parent::__construct($configuration, $plugin_id, $plugin_definition);
|
||||
|
||||
$this->entityManager = $entity_manager;
|
||||
$this->languageManager = $language_manager;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -56,7 +70,8 @@ class EntityOperations extends FieldPluginBase {
|
|||
$configuration,
|
||||
$plugin_id,
|
||||
$plugin_definition,
|
||||
$container->get('entity.manager')
|
||||
$container->get('entity.manager'),
|
||||
$container->get('language_manager')
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -98,7 +113,7 @@ class EntityOperations extends FieldPluginBase {
|
|||
* {@inheritdoc}
|
||||
*/
|
||||
public function render(ResultRow $values) {
|
||||
$entity = $this->getEntity($values);
|
||||
$entity = $this->getEntityTranslation($this->getEntity($values), $values);
|
||||
$operations = $this->entityManager->getListBuilder($entity->getEntityTypeId())->getOperations($entity);
|
||||
if ($this->options['destination']) {
|
||||
foreach ($operations as &$operation) {
|
||||
|
@ -120,8 +135,39 @@ class EntityOperations extends FieldPluginBase {
|
|||
* {@inheritdoc}
|
||||
*/
|
||||
public function query() {
|
||||
// There is nothing to ensure or add for this handler, so we purposefully do
|
||||
// nothing here and do not call parent::query() either.
|
||||
// We purposefully do not call parent::query() because we do not want the
|
||||
// default query behavior for Views fields. Instead, let the entity
|
||||
// translation renderer provide the correct query behavior.
|
||||
if ($this->languageManager->isMultilingual()) {
|
||||
$this->getEntityTranslationRenderer()->query($this->query, $this->relationship);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getEntityTypeId() {
|
||||
return $this->getEntityType();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getEntityManager() {
|
||||
return $this->entityManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getLanguageManager() {
|
||||
return $this->languageManager;
|
||||
}
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getView() {
|
||||
return $this->view;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
namespace Drupal\views\Plugin\views\field;
|
||||
|
||||
use Drupal\Component\Utility\Xss;
|
||||
use Drupal\Core\Cache\Cache;
|
||||
use Drupal\Core\Cache\CacheableDependencyInterface;
|
||||
use Drupal\Core\Entity\EntityInterface;
|
||||
use Drupal\Core\Entity\EntityManagerInterface;
|
||||
use Drupal\Core\Field\FieldStorageDefinitionInterface;
|
||||
|
@ -22,7 +24,6 @@ use Drupal\Core\Render\RendererInterface;
|
|||
use Drupal\Core\Session\AccountInterface;
|
||||
use Drupal\views\FieldAPIHandlerTrait;
|
||||
use Drupal\views\Entity\Render\EntityFieldRenderer;
|
||||
use Drupal\views\Plugin\CacheablePluginInterface;
|
||||
use Drupal\views\Plugin\views\display\DisplayPluginBase;
|
||||
use Drupal\views\ResultRow;
|
||||
use Drupal\views\ViewExecutable;
|
||||
|
@ -37,7 +38,7 @@ use Symfony\Component\DependencyInjection\ContainerInterface;
|
|||
*
|
||||
* @ViewsField("field")
|
||||
*/
|
||||
class Field extends FieldPluginBase implements CacheablePluginInterface, MultiItemsFieldHandlerInterface {
|
||||
class Field extends FieldPluginBase implements CacheableDependencyInterface, MultiItemsFieldHandlerInterface {
|
||||
use FieldAPIHandlerTrait;
|
||||
|
||||
/**
|
||||
|
@ -961,8 +962,8 @@ class Field extends FieldPluginBase implements CacheablePluginInterface, MultiIt
|
|||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function isCacheable() {
|
||||
return FALSE;
|
||||
public function getCacheMaxAge() {
|
||||
return Cache::PERMANENT;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -972,6 +973,18 @@ class Field extends FieldPluginBase implements CacheablePluginInterface, MultiIt
|
|||
return $this->getEntityFieldRenderer()->getCacheContexts();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getCacheTags() {
|
||||
$field_definition = $this->getFieldDefinition();
|
||||
$field_storage_definition = $this->getFieldStorageDefinition();
|
||||
return Cache::mergeTags(
|
||||
$field_definition instanceof CacheableDependencyInterface ? $field_definition->getCacheTags() : [],
|
||||
$field_storage_definition instanceof CacheableDependencyInterface ? $field_storage_definition->getCacheTags() : []
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the table mapping for the entity type of the field.
|
||||
*
|
||||
|
|
|
@ -167,9 +167,9 @@ interface FieldHandlerInterface extends ViewsHandlerInterface {
|
|||
* @param \Drupal\views\ResultRow $values
|
||||
* The values retrieved from a single row of a view's query result.
|
||||
*
|
||||
* @return string|\Drupal\Component\Utility\SafeStringInterface
|
||||
* @return string|\Drupal\Component\Render\MarkupInterface
|
||||
* The rendered output. If the output is safe it will be wrapped in an
|
||||
* object that implements SafeStringInterface. If it is empty or unsafe it
|
||||
* object that implements MarkupInterface. If it is empty or unsafe it
|
||||
* will be a string.
|
||||
*
|
||||
*/
|
||||
|
@ -204,9 +204,9 @@ interface FieldHandlerInterface extends ViewsHandlerInterface {
|
|||
* @param \Drupal\views\ResultRow $values
|
||||
* The values retrieved from a single row of a view's query result.
|
||||
*
|
||||
* @return string|\Drupal\Component\Utility\SafeStringInterface
|
||||
* @return string|\Drupal\Component\Render\MarkupInterface
|
||||
* The advanced rendered output. If the output is safe it will be wrapped in
|
||||
* an object that implements SafeStringInterface. If it is empty or unsafe
|
||||
* an object that implements MarkupInterface. If it is empty or unsafe
|
||||
* it will be a string.
|
||||
*
|
||||
*/
|
||||
|
@ -240,9 +240,9 @@ interface FieldHandlerInterface extends ViewsHandlerInterface {
|
|||
* - ellipsis: Show an ellipsis (…) at the end of the trimmed string.
|
||||
* - html: Make sure that the html is correct.
|
||||
*
|
||||
* @return string|\Drupal\Component\Utility\SafeStringInterface
|
||||
* @return string|\Drupal\Component\Render\MarkupInterface
|
||||
* The rendered output. If the output is safe it will be wrapped in an
|
||||
* object that implements SafeStringInterface. If it is empty or unsafe it
|
||||
* object that implements MarkupInterface. If it is empty or unsafe it
|
||||
* will be a string.
|
||||
*/
|
||||
public function renderText($alter);
|
||||
|
@ -268,10 +268,10 @@ interface FieldHandlerInterface extends ViewsHandlerInterface {
|
|||
* @param \Drupal\views\ResultRow $values
|
||||
* Holds single row of a view's result set.
|
||||
*
|
||||
* @return string|\Drupal\Component\Utility\SafeStringInterface
|
||||
* @return string|\Drupal\Component\Render\MarkupInterface
|
||||
* Returns rendered output of the given theme implementation. If the output
|
||||
* is safe it will be wrapped in an object that implements
|
||||
* SafeStringInterface. If it is empty or unsafe it will be a string.
|
||||
* MarkupInterface. If it is empty or unsafe it will be a string.
|
||||
*/
|
||||
function theme(ResultRow $values);
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@ namespace Drupal\views\Plugin\views\field;
|
|||
use Drupal\Component\Utility\Html;
|
||||
use Drupal\Component\Utility\NestedArray;
|
||||
use Drupal\Component\Utility\SafeMarkup;
|
||||
use Drupal\Component\Utility\SafeStringInterface;
|
||||
use Drupal\Component\Render\MarkupInterface;
|
||||
use Drupal\Component\Utility\Unicode;
|
||||
use Drupal\Component\Utility\UrlHelper;
|
||||
use Drupal\Component\Utility\Xss;
|
||||
|
@ -20,7 +20,7 @@ use Drupal\Core\Render\Renderer;
|
|||
use Drupal\Core\Url as CoreUrl;
|
||||
use Drupal\views\Plugin\views\HandlerBase;
|
||||
use Drupal\views\Plugin\views\display\DisplayPluginBase;
|
||||
use Drupal\views\Render\ViewsRenderPipelineSafeString;
|
||||
use Drupal\views\Render\ViewsRenderPipelineMarkup;
|
||||
use Drupal\views\ResultRow;
|
||||
use Drupal\views\ViewExecutable;
|
||||
|
||||
|
@ -333,7 +333,7 @@ abstract class FieldPluginBase extends HandlerBase implements FieldHandlerInterf
|
|||
* {@inheritdoc}
|
||||
*/
|
||||
public function tokenizeValue($value, $row_index = NULL) {
|
||||
if (strpos($value, '{{') !== FALSE || strpos($value, '!') !== FALSE || strpos($value, '%') !== FALSE) {
|
||||
if (strpos($value, '{{') !== FALSE) {
|
||||
$fake_item = array(
|
||||
'alter_text' => TRUE,
|
||||
'text' => $value,
|
||||
|
@ -716,7 +716,7 @@ abstract class FieldPluginBase extends HandlerBase implements FieldHandlerInterf
|
|||
'#title' => $this->t('Text'),
|
||||
'#type' => 'textarea',
|
||||
'#default_value' => $this->options['alter']['text'],
|
||||
'#description' => $this->t('The text to display for this field. You may include HTML or <a href="@url">Twig</a>. You may enter data from this view as per the "Replacement patterns" below.', array('@url' => CoreUrl::fromUri('http://twig.sensiolabs.org/documentation')->toString())),
|
||||
'#description' => $this->t('The text to display for this field. You may include HTML or <a href=":url">Twig</a>. You may enter data from this view as per the "Replacement patterns" below.', array(':url' => CoreUrl::fromUri('http://twig.sensiolabs.org/documentation')->toString())),
|
||||
'#states' => array(
|
||||
'visible' => array(
|
||||
':input[name="options[alter][alter_text]"]' => array('checked' => TRUE),
|
||||
|
@ -862,19 +862,20 @@ abstract class FieldPluginBase extends HandlerBase implements FieldHandlerInterf
|
|||
|
||||
// Setup the tokens for fields.
|
||||
$previous = $this->getPreviousFieldLabels();
|
||||
$optgroup_arguments = (string) t('Arguments');
|
||||
$optgroup_fields = (string) t('Fields');
|
||||
foreach ($previous as $id => $label) {
|
||||
$options[t('Fields')]["{{ $id }}"] = substr(strrchr($label, ":"), 2 );
|
||||
$options[$optgroup_fields]["{{ $id }}"] = substr(strrchr($label, ":"), 2 );
|
||||
}
|
||||
// Add the field to the list of options.
|
||||
$options[t('Fields')]["{{ {$this->options['id']} }}"] = substr(strrchr($this->adminLabel(), ":"), 2 );
|
||||
$options[$optgroup_fields]["{{ {$this->options['id']} }}"] = substr(strrchr($this->adminLabel(), ":"), 2 );
|
||||
|
||||
$count = 0; // This lets us prepare the key as we want it printed.
|
||||
foreach ($this->view->display_handler->getHandlers('argument') as $arg => $handler) {
|
||||
$options[t('Arguments')]['%' . ++$count] = $this->t('@argument title', array('@argument' => $handler->adminLabel()));
|
||||
$options[t('Arguments')]['!' . $count] = $this->t('@argument input', array('@argument' => $handler->adminLabel()));
|
||||
$options[$optgroup_arguments]["{{ arguments.$arg }}"] = $this->t('@argument title', array('@argument' => $handler->adminLabel()));
|
||||
$options[$optgroup_arguments]["{{ raw_arguments.$arg }}"] = $this->t('@argument input', array('@argument' => $handler->adminLabel()));
|
||||
}
|
||||
|
||||
$this->documentSelfTokens($options[t('Fields')]);
|
||||
$this->documentSelfTokens($options[$optgroup_fields]);
|
||||
|
||||
// Default text.
|
||||
|
||||
|
@ -896,7 +897,6 @@ abstract class FieldPluginBase extends HandlerBase implements FieldHandlerInterf
|
|||
$item_list = array(
|
||||
'#theme' => 'item_list',
|
||||
'#items' => $items,
|
||||
'#list_type' => $type,
|
||||
);
|
||||
$output[] = $item_list;
|
||||
}
|
||||
|
@ -1177,7 +1177,7 @@ abstract class FieldPluginBase extends HandlerBase implements FieldHandlerInterf
|
|||
$this->last_render = $value;
|
||||
}
|
||||
|
||||
// String cast is necessary to test emptiness of SafeStringInterface
|
||||
// String cast is necessary to test emptiness of MarkupInterface
|
||||
// objects.
|
||||
if (empty((string) $this->last_render)) {
|
||||
if ($this->isValueEmpty($this->last_render, $this->options['empty_zero'], FALSE)) {
|
||||
|
@ -1196,8 +1196,8 @@ abstract class FieldPluginBase extends HandlerBase implements FieldHandlerInterf
|
|||
* {@inheritdoc}
|
||||
*/
|
||||
public function isValueEmpty($value, $empty_zero, $no_skip_empty = TRUE) {
|
||||
// Convert SafeStringInterface to a string for checking.
|
||||
if ($value instanceof SafeStringInterface) {
|
||||
// Convert MarkupInterface to a string for checking.
|
||||
if ($value instanceof MarkupInterface) {
|
||||
$value = (string) $value;
|
||||
}
|
||||
if (!isset($value)) {
|
||||
|
@ -1251,7 +1251,7 @@ abstract class FieldPluginBase extends HandlerBase implements FieldHandlerInterf
|
|||
// If we got here then $alter contains the value of "No results text"
|
||||
// and so there is nothing left to do.
|
||||
if ($value_is_safe) {
|
||||
$value = ViewsRenderPipelineSafeString::create($value);
|
||||
$value = ViewsRenderPipelineMarkup::create($value);
|
||||
}
|
||||
return $value;
|
||||
}
|
||||
|
@ -1260,7 +1260,7 @@ abstract class FieldPluginBase extends HandlerBase implements FieldHandlerInterf
|
|||
$value = strip_tags($value, $alter['preserve_tags']);
|
||||
}
|
||||
|
||||
$suffix = '';
|
||||
$more_link = '';
|
||||
if (!empty($alter['trim']) && !empty($alter['max_length'])) {
|
||||
$length = strlen($value);
|
||||
$value = $this->renderTrimText($alter, $value);
|
||||
|
@ -1271,7 +1271,8 @@ abstract class FieldPluginBase extends HandlerBase implements FieldHandlerInterf
|
|||
$more_link_path = $this->options['alter']['more_link_path'];
|
||||
$more_link_path = strip_tags(Html::decodeEntities($this->viewsTokenReplace($more_link_path, $tokens)));
|
||||
|
||||
// Make sure that paths which were run through _url() work as well.
|
||||
// Make sure that paths which were run through URL generation work as
|
||||
// well.
|
||||
$base_path = base_path();
|
||||
// Checks whether the path starts with the base_path.
|
||||
if (strpos($more_link_path, $base_path) === 0) {
|
||||
|
@ -1280,9 +1281,7 @@ abstract class FieldPluginBase extends HandlerBase implements FieldHandlerInterf
|
|||
|
||||
// @todo Views should expect and store a leading /. See
|
||||
// https://www.drupal.org/node/2423913.
|
||||
$more_link = \Drupal::l($more_link_text, CoreUrl::fromUserInput('/' . $more_link_path, array('attributes' => array('class' => array('views-more-link')))));
|
||||
|
||||
$suffix .= " " . $more_link;
|
||||
$more_link = ' ' . $this->linkGenerator()->generate($more_link_text, CoreUrl::fromUserInput('/' . $more_link_path, array('attributes' => array('class' => array('views-more-link')))));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1290,10 +1289,8 @@ abstract class FieldPluginBase extends HandlerBase implements FieldHandlerInterf
|
|||
$value = nl2br($value);
|
||||
}
|
||||
|
||||
// Preserve whether or not the string is safe. Since $suffix comes from
|
||||
// \Drupal::l(), it is safe to append.
|
||||
if ($value_is_safe) {
|
||||
$value = ViewsRenderPipelineSafeString::create($value . $suffix);
|
||||
$value = ViewsRenderPipelineMarkup::create($value);
|
||||
}
|
||||
$this->last_render_text = $value;
|
||||
|
||||
|
@ -1304,15 +1301,16 @@ abstract class FieldPluginBase extends HandlerBase implements FieldHandlerInterf
|
|||
$value = $this->renderAsLink($alter, $value, $tokens);
|
||||
}
|
||||
|
||||
// Preserve whether or not the string is safe. Since $suffix comes from
|
||||
// \Drupal::l(), it is safe to append.
|
||||
if ($value_is_safe) {
|
||||
return ViewsRenderPipelineSafeString::create($value . $suffix);
|
||||
// Preserve whether or not the string is safe. Since $more_link comes from
|
||||
// \Drupal::l(), it is safe to append. Use SafeMarkup::isSafe() here because
|
||||
// renderAsLink() can return both safe and unsafe values.
|
||||
if (SafeMarkup::isSafe($value)) {
|
||||
return ViewsRenderPipelineMarkup::create($value . $more_link);
|
||||
}
|
||||
else {
|
||||
// If the string is not already marked safe, it is still OK to return it
|
||||
// because it will be sanitized by Twig.
|
||||
return $value . $suffix;
|
||||
return $value . $more_link;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1394,8 +1392,8 @@ abstract class FieldPluginBase extends HandlerBase implements FieldHandlerInterf
|
|||
$path = preg_replace(['/(\%7B){2}(\%20)*/', '/(\%20)*(\%7D){2}/'], ['{{','}}'], $path);
|
||||
|
||||
// Use strip tags as there should never be HTML in the path.
|
||||
// However, we need to preserve special characters like " that
|
||||
// were removed by SafeMarkup::checkPlain().
|
||||
// However, we need to preserve special characters like " that are escaped
|
||||
// by \Drupal\Component\Utility\Html::escape().
|
||||
$path = strip_tags(Html::decodeEntities($this->viewsTokenReplace($path, $tokens)));
|
||||
|
||||
if (!empty($alter['path_case']) && $alter['path_case'] != 'none' && !$alter['url']->isRouted()) {
|
||||
|
@ -1481,8 +1479,7 @@ abstract class FieldPluginBase extends HandlerBase implements FieldHandlerInterf
|
|||
$options['attributes']['rel'] = $rel;
|
||||
}
|
||||
|
||||
// Not sure if this SafeMarkup::checkPlain() is needed here?
|
||||
$target = SafeMarkup::checkPlain(trim($this->viewsTokenReplace($alter['target'], $tokens)));
|
||||
$target = trim($this->viewsTokenReplace($alter['target'], $tokens));
|
||||
if (!empty($target)) {
|
||||
$options['attributes']['target'] = $target;
|
||||
}
|
||||
|
@ -1501,7 +1498,8 @@ abstract class FieldPluginBase extends HandlerBase implements FieldHandlerInterf
|
|||
// parsed values.
|
||||
if (isset($alter['query'])) {
|
||||
// Convert the query to a string, perform token replacement, and then
|
||||
// convert back to an array form for _l().
|
||||
// convert back to an array form for
|
||||
// \Drupal\Core\Utility\LinkGeneratorInterface::generate().
|
||||
$options['query'] = UrlHelper::buildQuery($alter['query']);
|
||||
$options['query'] = $this->viewsTokenReplace($options['query'], $tokens);
|
||||
$query = array();
|
||||
|
@ -1532,19 +1530,20 @@ abstract class FieldPluginBase extends HandlerBase implements FieldHandlerInterf
|
|||
|
||||
// Build the link based on our altered Url object, adding on the optional
|
||||
// prefix and suffix
|
||||
$value = '';
|
||||
$render = [
|
||||
'#type' => 'link',
|
||||
'#title' => $text,
|
||||
'#url' => $final_url,
|
||||
];
|
||||
|
||||
if (!empty($alter['prefix'])) {
|
||||
$value .= Xss::filterAdmin($this->viewsTokenReplace($alter['prefix'], $tokens));
|
||||
$render['#prefix'] = $this->viewsTokenReplace($alter['prefix'], $tokens);
|
||||
}
|
||||
|
||||
$value .= $this->linkGenerator()->generate($text, $final_url);
|
||||
|
||||
if (!empty($alter['suffix'])) {
|
||||
$value .= Xss::filterAdmin($this->viewsTokenReplace($alter['suffix'], $tokens));
|
||||
$render['#suffix'] = $this->viewsTokenReplace($alter['suffix'], $tokens);
|
||||
}
|
||||
return $this->getRenderer()->render($render);
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1557,7 +1556,7 @@ abstract class FieldPluginBase extends HandlerBase implements FieldHandlerInterf
|
|||
}
|
||||
$count = 0;
|
||||
foreach ($this->displayHandler->getHandlers('argument') as $arg => $handler) {
|
||||
$token = '%' . ++$count;
|
||||
$token = "{{ arguments.$arg }}";
|
||||
if (!isset($tokens[$token])) {
|
||||
$tokens[$token] = '';
|
||||
}
|
||||
|
@ -1565,7 +1564,8 @@ abstract class FieldPluginBase extends HandlerBase implements FieldHandlerInterf
|
|||
// Use strip tags as there should never be HTML in the path.
|
||||
// However, we need to preserve special characters like " that
|
||||
// were removed by SafeMarkup::checkPlain().
|
||||
$tokens['!' . $count] = isset($this->view->args[$count - 1]) ? strip_tags(Html::decodeEntities($this->view->args[$count - 1])) : '';
|
||||
$tokens["{{ raw_arguments.$arg }}"] = isset($this->view->args[$count]) ? strip_tags(Html::decodeEntities($this->view->args[$count])) : '';
|
||||
$count++;
|
||||
}
|
||||
|
||||
// Get flattened set of tokens for any array depth in query parameters.
|
||||
|
@ -1661,8 +1661,8 @@ abstract class FieldPluginBase extends HandlerBase implements FieldHandlerInterf
|
|||
}
|
||||
else {
|
||||
// Create a token key based on array element structure.
|
||||
$token_string = !empty($parent_keys) ? implode('_', $parent_keys) . '_' . $param : $param;
|
||||
$tokens['%' . $token_string] = strip_tags(Html::decodeEntities($val));
|
||||
$token_string = !empty($parent_keys) ? implode('.', $parent_keys) . '.' . $param : $param;
|
||||
$tokens['{{ arguments.' . $token_string . ' }}'] = strip_tags(Html::decodeEntities($val));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -83,7 +83,7 @@ class MachineName extends FieldPluginBase {
|
|||
public function render(ResultRow $values) {
|
||||
$value = $values->{$this->field_alias};
|
||||
if (!empty($this->options['machine_name']) || !isset($this->valueOptions[$value])) {
|
||||
$result = SafeMarkup::checkPlain($value);
|
||||
$result = $this->sanitizeValue($value);
|
||||
}
|
||||
else {
|
||||
$result = $this->valueOptions[$value];
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
namespace Drupal\views\Plugin\views\field;
|
||||
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\StringTranslation\PluralTranslatableMarkup;
|
||||
use Drupal\views\ResultRow;
|
||||
|
||||
/**
|
||||
|
@ -174,7 +175,7 @@ class NumericField extends FieldPluginBase {
|
|||
// If we should format as plural, take the (possibly) translated plural
|
||||
// setting and format with the current language.
|
||||
if (!empty($this->options['format_plural'])) {
|
||||
$value = $this->formatPluralTranslated($value, $this->options['format_plural_string']);
|
||||
$value = PluralTranslatableMarkup::createFromTranslatedString($value, $this->options['format_plural_string']);
|
||||
}
|
||||
|
||||
return $this->sanitizeValue($this->options['prefix'], 'xss')
|
||||
|
|
|
@ -78,17 +78,24 @@ abstract class PrerenderList extends FieldPluginBase implements MultiItemsFieldH
|
|||
public function renderItems($items) {
|
||||
if (!empty($items)) {
|
||||
if ($this->options['type'] == 'separator') {
|
||||
return implode($this->sanitizeValue($this->options['separator'], 'xss_admin'), $items);
|
||||
$render = [
|
||||
'#type' => 'inline_template',
|
||||
'#template' => '{{ items|safe_join(separator) }}',
|
||||
'#context' => [
|
||||
'items' => $items,
|
||||
'separator' => $this->sanitizeValue($this->options['separator'], 'xss_admin')
|
||||
]
|
||||
];
|
||||
}
|
||||
else {
|
||||
$item_list = array(
|
||||
$render = array(
|
||||
'#theme' => 'item_list',
|
||||
'#items' => $items,
|
||||
'#title' => NULL,
|
||||
'#list_type' => $this->options['type'],
|
||||
);
|
||||
return drupal_render($item_list);
|
||||
}
|
||||
return drupal_render($render);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
|
||||
namespace Drupal\views\Plugin\views\field;
|
||||
|
||||
use Drupal\Component\Utility\SafeMarkup;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\views\ResultRow;
|
||||
|
||||
|
@ -76,11 +75,11 @@ class Serialized extends FieldPluginBase {
|
|||
$value = $values->{$this->field_alias};
|
||||
|
||||
if ($this->options['format'] == 'unserialized') {
|
||||
return SafeMarkup::checkPlain(print_r(unserialize($value), TRUE));
|
||||
return $this->sanitizeValue(print_r(unserialize($value), TRUE));
|
||||
}
|
||||
elseif ($this->options['format'] == 'key' && !empty($this->options['key'])) {
|
||||
$value = (array) unserialize($value);
|
||||
return SafeMarkup::checkPlain($value[$this->options['key']]);
|
||||
return $this->sanitizeValue($value[$this->options['key']]);
|
||||
}
|
||||
|
||||
return $value;
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
namespace Drupal\views\Plugin\views\field;
|
||||
|
||||
use Drupal\Core\Datetime\DateFormatter;
|
||||
use Drupal\Core\Datetime\DateFormatterInterface;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\views\ResultRow;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
@ -24,7 +24,7 @@ class TimeInterval extends FieldPluginBase {
|
|||
/**
|
||||
* The date formatter service.
|
||||
*
|
||||
* @var \Drupal\Core\Datetime\DateFormatter
|
||||
* @var \Drupal\Core\Datetime\DateFormatterInterface
|
||||
*/
|
||||
protected $dateFormatter;
|
||||
|
||||
|
@ -37,10 +37,10 @@ class TimeInterval extends FieldPluginBase {
|
|||
* The plugin_id for the plugin instance.
|
||||
* @param mixed $plugin_definition
|
||||
* The plugin implementation definition.
|
||||
* @param \Drupal\Core\Datetime\DateFormatter $date_formatter
|
||||
* @param \Drupal\Core\Datetime\DateFormatterInterface $date_formatter
|
||||
* The date formatter service.
|
||||
*/
|
||||
public function __construct(array $configuration, $plugin_id, $plugin_definition, DateFormatter $date_formatter) {
|
||||
public function __construct(array $configuration, $plugin_id, $plugin_definition, DateFormatterInterface $date_formatter) {
|
||||
$this->dateFormatter = $date_formatter;
|
||||
parent::__construct($configuration, $plugin_id, $plugin_definition);
|
||||
}
|
||||
|
|
|
@ -37,7 +37,7 @@ class Date extends NumericFilter {
|
|||
'#title' => $this->t('Value type'),
|
||||
'#options' => array(
|
||||
'date' => $this->t('A date in any machine readable format. CCYY-MM-DD HH:MM:SS is preferred.'),
|
||||
'offset' => $this->t('An offset from the current time such as "!example1" or "!example2"', array('!example1' => '+1 day', '!example2' => '-2 hours -30 minutes')),
|
||||
'offset' => $this->t('An offset from the current time such as "@example1" or "@example2"', array('@example1' => '+1 day', '@example2' => '-2 hours -30 minutes')),
|
||||
),
|
||||
'#default_value' => !empty($this->value['type']) ? $this->value['type'] : 'date',
|
||||
);
|
||||
|
|
|
@ -1,25 +0,0 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\views\Plugin\views\filter\FieldList.
|
||||
*/
|
||||
|
||||
namespace Drupal\views\Plugin\views\filter;
|
||||
|
||||
/**
|
||||
* Filter handler which uses list-fields as options.
|
||||
*
|
||||
* @ingroup views_filter_handlers
|
||||
*
|
||||
* @ViewsFilter("field_list")
|
||||
*/
|
||||
class FieldList extends ManyToOne {
|
||||
|
||||
public function getValueOptions() {
|
||||
$field_storage_definitions = \Drupal::entityManager()->getFieldStorageDefinitions($this->definition['entity_type']);
|
||||
$field_storage = $field_storage_definitions[$this->definition['field_name']];
|
||||
$this->valueOptions = list_allowed_values($field_storage);
|
||||
}
|
||||
|
||||
}
|
|
@ -7,14 +7,14 @@
|
|||
|
||||
namespace Drupal\views\Plugin\views\filter;
|
||||
|
||||
use Drupal\Core\Cache\Cache;
|
||||
use Drupal\Core\Cache\CacheableDependencyInterface;
|
||||
use Drupal\Core\Form\FormHelper;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\Render\Element;
|
||||
use Drupal\user\RoleInterface;
|
||||
use Drupal\views\Plugin\CacheablePluginInterface;
|
||||
use Drupal\views\Plugin\views\HandlerBase;
|
||||
use Drupal\Component\Utility\Html;
|
||||
use Drupal\Component\Utility\SafeMarkup;
|
||||
use Drupal\views\Plugin\views\display\DisplayPluginBase;
|
||||
use Drupal\views\ViewExecutable;
|
||||
|
||||
|
@ -47,7 +47,7 @@ use Drupal\views\ViewExecutable;
|
|||
/**
|
||||
* Base class for Views filters handler plugins.
|
||||
*/
|
||||
abstract class FilterPluginBase extends HandlerBase implements CacheablePluginInterface {
|
||||
abstract class FilterPluginBase extends HandlerBase implements CacheableDependencyInterface {
|
||||
|
||||
/**
|
||||
* Contains the actual value of the field,either configured in the views ui
|
||||
|
@ -172,7 +172,7 @@ abstract class FilterPluginBase extends HandlerBase implements CacheablePluginIn
|
|||
* Display the filter on the administrative summary
|
||||
*/
|
||||
public function adminSummary() {
|
||||
return SafeMarkup::checkPlain((string) $this->operator) . ' ' . SafeMarkup::checkPlain((string) $this->value);
|
||||
return $this->operator . ' ' . $this->value;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -595,7 +595,7 @@ abstract class FilterPluginBase extends HandlerBase implements CacheablePluginIn
|
|||
'#default_value' => $this->options['expose']['remember'],
|
||||
);
|
||||
|
||||
$role_options = array_map('\Drupal\Component\Utility\SafeMarkup::checkPlain', user_role_names());
|
||||
$role_options = array_map('\Drupal\Component\Utility\Html::escape', user_role_names());
|
||||
$form['expose']['remember_roles'] = array(
|
||||
'#type' => 'checkboxes',
|
||||
'#title' => $this->t('User roles'),
|
||||
|
@ -1180,7 +1180,7 @@ abstract class FilterPluginBase extends HandlerBase implements CacheablePluginIn
|
|||
}
|
||||
else {
|
||||
// Cast the label to a string since it can be an object.
|
||||
// @see \Drupal\Core\StringTranslation\TranslationWrapper
|
||||
// @see \Drupal\Core\StringTranslation\TranslatableMarkup
|
||||
$options[$value] = strip_tags(Html::decodeEntities((string) $label));
|
||||
}
|
||||
}
|
||||
|
@ -1465,8 +1465,8 @@ abstract class FilterPluginBase extends HandlerBase implements CacheablePluginIn
|
|||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function isCacheable() {
|
||||
return TRUE;
|
||||
public function getCacheMaxAge() {
|
||||
return Cache::PERMANENT;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1483,6 +1483,13 @@ abstract class FilterPluginBase extends HandlerBase implements CacheablePluginIn
|
|||
return $cache_contexts;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getCacheTags() {
|
||||
return [];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
|
||||
namespace Drupal\views\Plugin\views\filter;
|
||||
|
||||
use Drupal\Component\Utility\SafeMarkup;
|
||||
use Drupal\Component\Utility\Unicode;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\views\Plugin\views\display\DisplayPluginBase;
|
||||
|
@ -330,17 +329,19 @@ class InOperator extends FilterPluginBase {
|
|||
$info = $this->operators();
|
||||
|
||||
$this->getValueOptions();
|
||||
// Some filter_in_operator usage uses optgroups forms, so flatten it.
|
||||
$flat_options = OptGroup::flattenOptions($this->valueOptions);
|
||||
|
||||
if (!is_array($this->value)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$operator = SafeMarkup::checkPlain($info[$this->operator]['short']);
|
||||
$operator = $info[$this->operator]['short'];
|
||||
$values = '';
|
||||
if (in_array($this->operator, $this->operatorValues(1))) {
|
||||
// Remove every element which is not known.
|
||||
foreach ($this->value as $value) {
|
||||
if (!isset($this->valueOptions[$value])) {
|
||||
if (!isset($flat_options[$value])) {
|
||||
unset($this->value[$value]);
|
||||
}
|
||||
}
|
||||
|
@ -351,13 +352,13 @@ class InOperator extends FilterPluginBase {
|
|||
else if (count($this->value) == 1) {
|
||||
// If any, use the 'single' short name of the operator instead.
|
||||
if (isset($info[$this->operator]['short_single'])) {
|
||||
$operator = SafeMarkup::checkPlain($info[$this->operator]['short_single']);
|
||||
$operator = $info[$this->operator]['short_single'];
|
||||
}
|
||||
|
||||
$keys = $this->value;
|
||||
$value = array_shift($keys);
|
||||
if (isset($this->valueOptions[$value])) {
|
||||
$values = SafeMarkup::checkPlain($this->valueOptions[$value]);
|
||||
if (isset($flat_options[$value])) {
|
||||
$values = $flat_options[$value];
|
||||
}
|
||||
else {
|
||||
$values = '';
|
||||
|
@ -372,8 +373,8 @@ class InOperator extends FilterPluginBase {
|
|||
$values = Unicode::truncate($values, 8, FALSE, TRUE);
|
||||
break;
|
||||
}
|
||||
if (isset($this->valueOptions[$value])) {
|
||||
$values .= SafeMarkup::checkPlain($this->valueOptions[$value]);
|
||||
if (isset($flat_options[$value])) {
|
||||
$values .= $flat_options[$value];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
|
||||
namespace Drupal\views\Plugin\views\filter;
|
||||
|
||||
use Drupal\Component\Utility\SafeMarkup;
|
||||
use Drupal\Core\Database\Database;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
|
||||
|
@ -292,12 +291,12 @@ class NumericFilter extends FilterPluginBase {
|
|||
}
|
||||
|
||||
$options = $this->operatorOptions('short');
|
||||
$output = SafeMarkup::checkPlain($options[$this->operator]);
|
||||
$output = $options[$this->operator];
|
||||
if (in_array($this->operator, $this->operatorValues(2))) {
|
||||
$output .= ' ' . $this->t('@min and @max', array('@min' => $this->value['min'], '@max' => $this->value['max']));
|
||||
}
|
||||
elseif (in_array($this->operator, $this->operatorValues(1))) {
|
||||
$output .= ' ' . SafeMarkup::checkPlain($this->value['value']);
|
||||
$output .= ' ' . $this->value['value'];
|
||||
}
|
||||
return $output;
|
||||
}
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
|
||||
namespace Drupal\views\Plugin\views\filter;
|
||||
|
||||
use Drupal\Component\Utility\SafeMarkup;
|
||||
use Drupal\Core\Database\Database;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
|
||||
|
@ -162,10 +161,10 @@ class StringFilter extends FilterPluginBase {
|
|||
$options = $this->operatorOptions('short');
|
||||
$output = '';
|
||||
if (!empty($options[$this->operator])) {
|
||||
$output = SafeMarkup::checkPlain($options[$this->operator]);
|
||||
$output = $options[$this->operator];
|
||||
}
|
||||
if (in_array($this->operator, $this->operatorValues(1))) {
|
||||
$output .= ' ' . SafeMarkup::checkPlain($this->value);
|
||||
$output .= ' ' . $this->value;
|
||||
}
|
||||
return $output;
|
||||
}
|
||||
|
|
|
@ -34,8 +34,8 @@ class Full extends SqlBase {
|
|||
// Use the same default quantity that core uses by default.
|
||||
$options['quantity'] = array('default' => 9);
|
||||
|
||||
$options['tags']['contains']['first'] = array('default' => $this->t('« first'));
|
||||
$options['tags']['contains']['last'] = array('default' => $this->t('last »'));
|
||||
$options['tags']['contains']['first'] = array('default' => $this->t('« First'));
|
||||
$options['tags']['contains']['last'] = array('default' => $this->t('Last »'));
|
||||
|
||||
return $options;
|
||||
}
|
||||
|
|
|
@ -7,13 +7,14 @@
|
|||
|
||||
namespace Drupal\views\Plugin\views\pager;
|
||||
|
||||
use Drupal\Core\Cache\Cache;
|
||||
use Drupal\Core\Cache\CacheableDependencyInterface;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\views\Plugin\CacheablePluginInterface;
|
||||
|
||||
/**
|
||||
* A common base class for sql based pager.
|
||||
*/
|
||||
abstract class SqlBase extends PagerPluginBase implements CacheablePluginInterface {
|
||||
abstract class SqlBase extends PagerPluginBase implements CacheableDependencyInterface {
|
||||
|
||||
protected function defineOptions() {
|
||||
$options = parent::defineOptions();
|
||||
|
@ -35,8 +36,8 @@ abstract class SqlBase extends PagerPluginBase implements CacheablePluginInterfa
|
|||
);
|
||||
$options['tags'] = array(
|
||||
'contains' => array(
|
||||
'previous' => array('default' => $this->t('‹ previous')),
|
||||
'next' => array('default' => $this->t('next ›')),
|
||||
'previous' => array('default' => $this->t('‹ Previous')),
|
||||
'next' => array('default' => $this->t('Next ›')),
|
||||
),
|
||||
);
|
||||
return $options;
|
||||
|
@ -374,8 +375,8 @@ abstract class SqlBase extends PagerPluginBase implements CacheablePluginInterfa
|
|||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function isCacheable() {
|
||||
return TRUE;
|
||||
public function getCacheMaxAge() {
|
||||
return Cache::PERMANENT;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -387,4 +388,11 @@ abstract class SqlBase extends PagerPluginBase implements CacheablePluginInterfa
|
|||
return ['url.query_args'];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getCacheTags() {
|
||||
return [];
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -8,8 +8,8 @@
|
|||
namespace Drupal\views\Plugin\views\query;
|
||||
|
||||
use Drupal\Core\Cache\Cache;
|
||||
use Drupal\Core\Cache\CacheableDependencyInterface;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\views\Plugin\CacheablePluginInterface;
|
||||
use Drupal\views\Plugin\views\PluginBase;
|
||||
use Drupal\views\Plugin\views\display\DisplayPluginBase;
|
||||
use Drupal\views\ViewExecutable;
|
||||
|
@ -37,7 +37,7 @@ use Drupal\views\Views;
|
|||
/**
|
||||
* Base plugin class for Views queries.
|
||||
*/
|
||||
abstract class QueryPluginBase extends PluginBase implements CacheablePluginInterface {
|
||||
abstract class QueryPluginBase extends PluginBase implements CacheableDependencyInterface {
|
||||
|
||||
/**
|
||||
* A pager plugin that should be provided by the display.
|
||||
|
@ -320,9 +320,8 @@ abstract class QueryPluginBase extends PluginBase implements CacheablePluginInte
|
|||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function isCacheable() {
|
||||
// This plugin can't really determine that.
|
||||
return TRUE;
|
||||
public function getCacheMaxAge() {
|
||||
return Cache::PERMANENT;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -345,13 +344,6 @@ abstract class QueryPluginBase extends PluginBase implements CacheablePluginInte
|
|||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getCacheMaxAge() {
|
||||
return Cache::PERMANENT;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -97,7 +97,7 @@ abstract class RelationshipPluginBase extends HandlerBase {
|
|||
// aren't get another default value.
|
||||
if (!empty($this->definition['label'])) {
|
||||
// Cast the label to a string since it is an object.
|
||||
// @see \Drupal\Core\StringTranslation\TranslationWrapper
|
||||
// @see \Drupal\Core\StringTranslation\TranslatableMarkup
|
||||
$label = (string) $this->definition['label'];
|
||||
}
|
||||
else {
|
||||
|
|
61
core/modules/views/src/Plugin/views/row/EntityReference.php
Normal file
61
core/modules/views/src/Plugin/views/row/EntityReference.php
Normal file
|
@ -0,0 +1,61 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\views\Plugin\views\row\EntityReference.
|
||||
*/
|
||||
|
||||
namespace Drupal\views\Plugin\views\row;
|
||||
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
|
||||
/**
|
||||
* EntityReference row plugin.
|
||||
*
|
||||
* @ingroup views_row_plugins
|
||||
*
|
||||
* @ViewsRow(
|
||||
* id = "entity_reference",
|
||||
* title = @Translation("Entity Reference inline fields"),
|
||||
* help = @Translation("Displays the fields with an optional template."),
|
||||
* theme = "views_view_fields",
|
||||
* register_theme = FALSE,
|
||||
* display_types = {"entity_reference"}
|
||||
* )
|
||||
*/
|
||||
class EntityReference extends Fields {
|
||||
|
||||
/**
|
||||
* Overrides \Drupal\views\Plugin\views\row\Fields::defineOptions().
|
||||
*/
|
||||
protected function defineOptions() {
|
||||
$options = parent::defineOptions();
|
||||
$options['separator'] = array('default' => '-');
|
||||
|
||||
return $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides \Drupal\views\Plugin\views\row\Fields::buildOptionsForm().
|
||||
*/
|
||||
public function buildOptionsForm(&$form, FormStateInterface $form_state) {
|
||||
parent::buildOptionsForm($form, $form_state);
|
||||
|
||||
// Expand the description of the 'Inline field' checkboxes.
|
||||
$form['inline']['#description'] .= '<br />' . $this->t("<strong>Note:</strong> In 'Entity Reference' displays, all fields will be displayed inline unless an explicit selection of inline fields is made here." );
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function preRender($row) {
|
||||
// Force all fields to be inline by default.
|
||||
if (empty($this->options['inline'])) {
|
||||
$fields = $this->view->getHandlers('field', $this->displayHandler->display['id']);
|
||||
$names = array_keys($fields);
|
||||
$this->options['inline'] = array_combine($names, $names);
|
||||
}
|
||||
|
||||
return parent::preRender($row);
|
||||
}
|
||||
}
|
|
@ -7,7 +7,6 @@
|
|||
|
||||
namespace Drupal\views\Plugin\views\row;
|
||||
|
||||
use Drupal\Component\Utility\SafeMarkup;
|
||||
use Drupal\Core\Entity\EntityManagerInterface;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\Language\LanguageManagerInterface;
|
||||
|
@ -160,7 +159,7 @@ class EntityRow extends RowPluginBase {
|
|||
public function summaryTitle() {
|
||||
$options = \Drupal::entityManager()->getViewModeOptions($this->entityTypeId);
|
||||
if (isset($options[$this->options['view_mode']])) {
|
||||
return SafeMarkup::checkPlain($options[$this->options['view_mode']]);
|
||||
return $options[$this->options['view_mode']];
|
||||
}
|
||||
else {
|
||||
return $this->t('No view mode selected');
|
||||
|
|
|
@ -7,15 +7,15 @@
|
|||
|
||||
namespace Drupal\views\Plugin\views\sort;
|
||||
|
||||
use Drupal\Core\Cache\CacheableDependencyInterface;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\views\Plugin\CacheablePluginInterface;
|
||||
|
||||
/**
|
||||
* Handle a random sort.
|
||||
*
|
||||
* @ViewsSort("random")
|
||||
*/
|
||||
class Random extends SortPluginBase implements CacheablePluginInterface {
|
||||
class Random extends SortPluginBase implements CacheableDependencyInterface {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
|
@ -26,8 +26,6 @@ class Random extends SortPluginBase implements CacheablePluginInterface {
|
|||
|
||||
public function query() {
|
||||
$this->query->addOrderBy('rand');
|
||||
// @todo Replace this once https://www.drupal.org/node/2464427 is in.
|
||||
$this->view->element['#cache']['max-age'] = 0;
|
||||
}
|
||||
|
||||
public function buildOptionsForm(&$form, FormStateInterface $form_state) {
|
||||
|
@ -38,8 +36,8 @@ class Random extends SortPluginBase implements CacheablePluginInterface {
|
|||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function isCacheable() {
|
||||
return FALSE;
|
||||
public function getCacheMaxAge() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -49,4 +47,11 @@ class Random extends SortPluginBase implements CacheablePluginInterface {
|
|||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getCacheTags() {
|
||||
return [];
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -7,8 +7,9 @@
|
|||
|
||||
namespace Drupal\views\Plugin\views\sort;
|
||||
|
||||
use Drupal\Core\Cache\Cache;
|
||||
use Drupal\Core\Cache\CacheableDependencyInterface;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\views\Plugin\CacheablePluginInterface;
|
||||
use Drupal\views\Plugin\views\HandlerBase;
|
||||
|
||||
/**
|
||||
|
@ -27,7 +28,7 @@ use Drupal\views\Plugin\views\HandlerBase;
|
|||
/**
|
||||
* Base sort handler that has no options and performs a simple sort.
|
||||
*/
|
||||
abstract class SortPluginBase extends HandlerBase implements CacheablePluginInterface {
|
||||
abstract class SortPluginBase extends HandlerBase implements CacheableDependencyInterface {
|
||||
|
||||
/**
|
||||
* Determine if a sort can be exposed.
|
||||
|
@ -227,10 +228,10 @@ abstract class SortPluginBase extends HandlerBase implements CacheablePluginInte
|
|||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function isCacheable() {
|
||||
public function getCacheMaxAge() {
|
||||
// The result of a sort does not depend on outside information, so by
|
||||
// default it is cacheable.
|
||||
return TRUE;
|
||||
return Cache::PERMANENT;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -245,6 +246,13 @@ abstract class SortPluginBase extends HandlerBase implements CacheablePluginInte
|
|||
return $cache_contexts;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getCacheTags() {
|
||||
return [];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
108
core/modules/views/src/Plugin/views/style/EntityReference.php
Normal file
108
core/modules/views/src/Plugin/views/style/EntityReference.php
Normal file
|
@ -0,0 +1,108 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\views\Plugin\views\style\EntityReference.
|
||||
*/
|
||||
|
||||
namespace Drupal\views\Plugin\views\style;
|
||||
|
||||
use Drupal\Component\Utility\Xss;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
|
||||
/**
|
||||
* EntityReference style plugin.
|
||||
*
|
||||
* @ingroup views_style_plugins
|
||||
*
|
||||
* @ViewsStyle(
|
||||
* id = "entity_reference",
|
||||
* title = @Translation("Entity Reference list"),
|
||||
* help = @Translation("Returns results as a PHP array of labels and rendered rows."),
|
||||
* theme = "views_view_unformatted",
|
||||
* register_theme = FALSE,
|
||||
* display_types = {"entity_reference"}
|
||||
* )
|
||||
*/
|
||||
class EntityReference extends StylePluginBase {
|
||||
|
||||
/**
|
||||
* Overrides \Drupal\views\Plugin\views\style\StylePluginBase::usesRowPlugin.
|
||||
*/
|
||||
protected $usesRowPlugin = TRUE;
|
||||
|
||||
/**
|
||||
* Overrides \Drupal\views\Plugin\views\style\StylePluginBase::usesFields.
|
||||
*/
|
||||
protected $usesFields = TRUE;
|
||||
|
||||
/**
|
||||
* Overrides \Drupal\views\Plugin\views\style\StylePluginBase::usesGrouping.
|
||||
*/
|
||||
protected $usesGrouping = FALSE;
|
||||
|
||||
/**
|
||||
* Overrides \Drupal\views\Plugin\views\style\StylePluginBase\StylePluginBase::defineOptions().
|
||||
*/
|
||||
protected function defineOptions() {
|
||||
$options = parent::defineOptions();
|
||||
$options['search_fields'] = array('default' => array());
|
||||
|
||||
return $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides \Drupal\views\Plugin\views\style\StylePluginBase\StylePluginBase::buildOptionsForm().
|
||||
*/
|
||||
public function buildOptionsForm(&$form, FormStateInterface $form_state) {
|
||||
parent::buildOptionsForm($form, $form_state);
|
||||
|
||||
$options = $this->displayHandler->getFieldLabels(TRUE);
|
||||
$form['search_fields'] = array(
|
||||
'#type' => 'checkboxes',
|
||||
'#title' => $this->t('Search fields'),
|
||||
'#options' => $options,
|
||||
'#required' => TRUE,
|
||||
'#default_value' => $this->options['search_fields'],
|
||||
'#description' => $this->t('Select the field(s) that will be searched when using the autocomplete widget.'),
|
||||
'#weight' => -3,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides \Drupal\views\Plugin\views\style\StylePluginBase\StylePluginBase::render().
|
||||
*/
|
||||
public function render() {
|
||||
if (!empty($this->view->live_preview)) {
|
||||
return parent::render();
|
||||
}
|
||||
|
||||
// Group the rows according to the grouping field, if specified.
|
||||
$sets = $this->renderGrouping($this->view->result, $this->options['grouping']);
|
||||
|
||||
// Grab the alias of the 'id' field added by
|
||||
// entity_reference_plugin_display.
|
||||
$id_field_alias = $this->view->storage->get('base_field');
|
||||
|
||||
// @todo We don't display grouping info for now. Could be useful for select
|
||||
// widget, though.
|
||||
$results = array();
|
||||
foreach ($sets as $records) {
|
||||
foreach ($records as $values) {
|
||||
$results[$values->{$id_field_alias}] = $this->view->rowPlugin->render($values);
|
||||
// Sanitize HTML, remove line breaks and extra whitespace.
|
||||
$results[$values->{$id_field_alias}]['#post_render'][] = function ($html, array $elements) {
|
||||
return Xss::filterAdmin(preg_replace('/\s\s+/', ' ', str_replace("\n", '', $html)));
|
||||
};
|
||||
}
|
||||
}
|
||||
return $results;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function evenEmpty() {
|
||||
return TRUE;
|
||||
}
|
||||
}
|
|
@ -14,7 +14,7 @@ use Drupal\Core\Render\Element;
|
|||
use Drupal\views\Plugin\views\display\DisplayPluginBase;
|
||||
use Drupal\views\Plugin\views\PluginBase;
|
||||
use Drupal\views\Plugin\views\wizard\WizardInterface;
|
||||
use Drupal\views\Render\ViewsRenderPipelineSafeString;
|
||||
use Drupal\views\Render\ViewsRenderPipelineMarkup;
|
||||
use Drupal\views\ViewExecutable;
|
||||
|
||||
/**
|
||||
|
@ -194,7 +194,7 @@ abstract class StylePluginBase extends PluginBase {
|
|||
public function usesTokens() {
|
||||
if ($this->usesRowClass()) {
|
||||
$class = $this->options['row_class'];
|
||||
if (strpos($class, '{{') !== FALSE || strpos($class, '!') !== FALSE || strpos($class, '%') !== FALSE) {
|
||||
if (strpos($class, '{{') !== FALSE) {
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
@ -231,7 +231,7 @@ abstract class StylePluginBase extends PluginBase {
|
|||
* Take a value and apply token replacement logic to it.
|
||||
*/
|
||||
public function tokenizeValue($value, $row_index) {
|
||||
if (strpos($value, '{{') !== FALSE || strpos($value, '!') !== FALSE || strpos($value, '%') !== FALSE) {
|
||||
if (strpos($value, '{{') !== FALSE) {
|
||||
// Row tokens might be empty, for example for node row style.
|
||||
$tokens = isset($this->rowTokens[$row_index]) ? $this->rowTokens[$row_index] : array();
|
||||
if (!empty($this->view->build_info['substitutions'])) {
|
||||
|
@ -583,7 +583,7 @@ abstract class StylePluginBase extends PluginBase {
|
|||
$group_content = $this->view->field[$field]->options['label'] . ': ' . $group_content;
|
||||
}
|
||||
if ($rendered) {
|
||||
$grouping = $group_content;
|
||||
$grouping = (string) $group_content;
|
||||
if ($rendered_strip) {
|
||||
$group_content = $grouping = strip_tags(htmlspecialchars_decode($group_content));
|
||||
}
|
||||
|
@ -684,7 +684,17 @@ abstract class StylePluginBase extends PluginBase {
|
|||
'#cache_properties' => $field_ids,
|
||||
];
|
||||
$renderer->addCacheableDependency($data, $this->view->storage);
|
||||
$renderer->renderPlain($data);
|
||||
// Views may be rendered both inside and outside a render context:
|
||||
// - HTML views are rendered inside a render context: then we want to
|
||||
// use ::render(), so that attachments and cacheability are bubbled.
|
||||
// - non-HTML views are rendered outside a render context: then we
|
||||
// want to use ::renderPlain(), so that no bubbling happens
|
||||
if ($renderer->hasRenderContext()) {
|
||||
$renderer->render($data);
|
||||
}
|
||||
else {
|
||||
$renderer->renderPlain($data);
|
||||
}
|
||||
|
||||
// Extract field output from the render array and post process it.
|
||||
$fields = $this->view->field;
|
||||
|
@ -708,7 +718,7 @@ abstract class StylePluginBase extends PluginBase {
|
|||
foreach ($this->rendered_fields[$index] as &$rendered_field) {
|
||||
// Placeholders and rendered fields have been processed by the
|
||||
// render system and are therefore safe.
|
||||
$rendered_field = ViewsRenderPipelineSafeString::create(str_replace($placeholders, $values, $rendered_field));
|
||||
$rendered_field = ViewsRenderPipelineMarkup::create(str_replace($placeholders, $values, $rendered_field));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -745,7 +755,7 @@ abstract class StylePluginBase extends PluginBase {
|
|||
* @param string $field
|
||||
* The ID of the field.
|
||||
*
|
||||
* @return \Drupal\Component\Utility\SafeStringInterface|null
|
||||
* @return \Drupal\Component\Render\MarkupInterface|null
|
||||
* The output of the field, or NULL if it was empty.
|
||||
*/
|
||||
public function getField($index, $field) {
|
||||
|
|
|
@ -9,8 +9,8 @@ namespace Drupal\views\Plugin\views\style;
|
|||
|
||||
use Drupal\Component\Plugin\Discovery\DiscoveryInterface;
|
||||
use Drupal\Component\Utility\Html;
|
||||
use Drupal\Core\Cache\CacheableDependencyInterface;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\views\Plugin\CacheablePluginInterface;
|
||||
use Drupal\views\Plugin\views\wizard\WizardInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
|
@ -28,7 +28,7 @@ use Symfony\Component\HttpFoundation\Request;
|
|||
* display_types = {"normal"}
|
||||
* )
|
||||
*/
|
||||
class Table extends StylePluginBase implements CacheablePluginInterface {
|
||||
class Table extends StylePluginBase implements CacheableDependencyInterface {
|
||||
|
||||
/**
|
||||
* Does the style plugin for itself support to add fields to it's output.
|
||||
|
@ -413,7 +413,7 @@ class Table extends StylePluginBase implements CacheablePluginInterface {
|
|||
);
|
||||
|
||||
$form['description_markup'] = array(
|
||||
'#markup' => '<div class="description form-item">' . $this->t('Place fields into columns; you may combine multiple fields into the same column. If you do, the separator in the column specified will be used to separate the fields. Check the sortable box to make that column click sortable, and check the default sort radio to determine which column will be sorted by default, if any. You may control column order and field labels in the fields section.') . '</div>',
|
||||
'#markup' => '<div class="js-form-item form-item description">' . $this->t('Place fields into columns; you may combine multiple fields into the same column. If you do, the separator in the column specified will be used to separate the fields. Check the sortable box to make that column click sortable, and check the default sort radio to determine which column will be sorted by default, if any. You may control column order and field labels in the fields section.') . '</div>',
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -432,8 +432,8 @@ class Table extends StylePluginBase implements CacheablePluginInterface {
|
|||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function isCacheable() {
|
||||
return TRUE;
|
||||
public function getCacheMaxAge() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -454,4 +454,11 @@ class Table extends StylePluginBase implements CacheablePluginInterface {
|
|||
return $contexts;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getCacheTags() {
|
||||
return [];
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -2,13 +2,13 @@
|
|||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\views\Render\ViewsRenderPipelineSafeString.
|
||||
* Contains \Drupal\views\Render\ViewsRenderPipelineMarkup.
|
||||
*/
|
||||
|
||||
namespace Drupal\views\Render;
|
||||
|
||||
use Drupal\Component\Utility\SafeStringInterface;
|
||||
use Drupal\Component\Utility\SafeStringTrait;
|
||||
use Drupal\Component\Render\MarkupInterface;
|
||||
use Drupal\Component\Render\MarkupTrait;
|
||||
|
||||
/**
|
||||
* Defines an object that passes safe strings through the Views render system.
|
||||
|
@ -21,8 +21,8 @@ use Drupal\Component\Utility\SafeStringTrait;
|
|||
* This object is marked as internal because it should only be used in the
|
||||
* Views render pipeline.
|
||||
*
|
||||
* @see \Drupal\Core\Render\SafeString
|
||||
* @see \Drupal\Core\Render\Markup
|
||||
*/
|
||||
final class ViewsRenderPipelineSafeString implements SafeStringInterface, \Countable {
|
||||
use SafeStringTrait;
|
||||
final class ViewsRenderPipelineMarkup implements MarkupInterface, \Countable {
|
||||
use MarkupTrait;
|
||||
}
|
|
@ -60,6 +60,8 @@ class ViewPageController {
|
|||
$build = $class::buildBasicRenderable($view_id, $display_id, $args, $route);
|
||||
Page::setPageRenderArray($build);
|
||||
|
||||
views_add_contextual_links($build, 'page', $display_id, $build);
|
||||
|
||||
return $build;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@ use Drupal\Component\Utility\Unicode;
|
|||
use Drupal\Core\Field\FieldStorageDefinitionInterface;
|
||||
use Drupal\Core\Language\LanguageInterface;
|
||||
use Drupal\Core\Url;
|
||||
use Drupal\entity_reference\Tests\EntityReferenceTestTrait;
|
||||
use Drupal\field\Tests\EntityReference\EntityReferenceTestTrait;
|
||||
use Drupal\views\Views;
|
||||
|
||||
/**
|
||||
|
@ -47,6 +47,8 @@ class DefaultViewsTest extends ViewTestBase {
|
|||
protected function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
$this->drupalPlaceBlock('page_title_block');
|
||||
|
||||
// Create Basic page node type.
|
||||
$this->drupalCreateContentType(array('type' => 'page', 'name' => 'Basic page'));
|
||||
|
||||
|
|
|
@ -70,7 +70,7 @@ class FieldEntityTranslationTest extends ViewTestBase {
|
|||
]);
|
||||
$node->save();
|
||||
|
||||
$translation = $node->getTranslation('es');
|
||||
$translation = $node->addTranslation('es');
|
||||
$translation->title->value = 'example ES';
|
||||
$translation->sticky->value = true;
|
||||
$translation->save();
|
||||
|
|
|
@ -84,7 +84,7 @@ class FilterEntityBundleTest extends ViewTestBase {
|
|||
'node'
|
||||
],
|
||||
];
|
||||
$this->assertIdentical($expected, $view->calculateDependencies());
|
||||
$this->assertIdentical($expected, $view->getDependencies());
|
||||
|
||||
$this->executeView($view);
|
||||
|
||||
|
|
|
@ -25,7 +25,7 @@ class RowEntityRenderersTest extends ViewKernelTestBase {
|
|||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = array('field', 'filter', 'text', 'node', 'user', 'language', 'entity_reference', 'views_test_language');
|
||||
public static $modules = ['field', 'filter', 'text', 'node', 'user', 'language', 'views_test_language'];
|
||||
|
||||
/**
|
||||
* Views used by this test.
|
||||
|
|
|
@ -32,7 +32,7 @@ class ViewEntityDependenciesTest extends ViewKernelTestBase {
|
|||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = ['node', 'comment', 'user', 'field', 'text', 'entity_reference', 'search'];
|
||||
public static $modules = ['node', 'comment', 'user', 'field', 'text', 'search'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
|
@ -83,9 +83,9 @@ class ViewEntityDependenciesTest extends ViewKernelTestBase {
|
|||
}
|
||||
|
||||
/**
|
||||
* Tests the calculateDependencies method.
|
||||
* Tests the getDependencies method.
|
||||
*/
|
||||
public function testCalculateDependencies() {
|
||||
public function testGetDependencies() {
|
||||
$expected = [];
|
||||
$expected['test_field_get_entity'] = [
|
||||
'module' => [
|
||||
|
@ -135,10 +135,10 @@ class ViewEntityDependenciesTest extends ViewKernelTestBase {
|
|||
foreach ($this::$testViews as $view_id) {
|
||||
$view = Views::getView($view_id);
|
||||
|
||||
$dependencies = $view->calculateDependencies();
|
||||
$dependencies = $view->getDependencies();
|
||||
$this->assertEqual($expected[$view_id], $dependencies);
|
||||
$config = $this->config('views.view.' . $view_id);
|
||||
\Drupal::service('config.storage.staging')->write($view_id, $config->get());
|
||||
\Drupal::service('config.storage.sync')->write($view_id, $config->get());
|
||||
}
|
||||
|
||||
// Ensure that dependencies are calculated on the display level.
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
|
||||
namespace Drupal\views\Tests;
|
||||
|
||||
use Drupal\Component\Render\MarkupInterface;
|
||||
use Drupal\field\Entity\FieldConfig;
|
||||
use Drupal\field\Tests\Views\FieldTestBase;
|
||||
|
||||
/**
|
||||
|
@ -26,9 +28,19 @@ class FieldApiDataTest extends FieldTestBase {
|
|||
'field_name' => $field_names[0],
|
||||
'entity_type' => 'node',
|
||||
'bundle' => 'page',
|
||||
'label' => 'The giraffe" label'
|
||||
);
|
||||
entity_create('field_config', $field)->save();
|
||||
|
||||
// Attach the same field to a different bundle with a different label.
|
||||
$this->drupalCreateContentType(['type' => 'article']);
|
||||
FieldConfig::create([
|
||||
'field_name' => $field_names[0],
|
||||
'entity_type' => 'node',
|
||||
'bundle' => 'article',
|
||||
'label' => 'The giraffe2" label'
|
||||
])->save();
|
||||
|
||||
// Now create some example nodes/users for the view result.
|
||||
for ($i = 0; $i < 5; $i++) {
|
||||
$edit = array(
|
||||
|
@ -86,6 +98,12 @@ class FieldApiDataTest extends FieldTestBase {
|
|||
$this->assertTrue($data[$current_table][$field_storage->getName()]['field']['click sortable'], 'String field is click sortable.');
|
||||
// Click sort should only be on the primary field.
|
||||
$this->assertTrue(empty($data[$revision_table][$field_storage->getName()]['field']['click sortable']), 'Non-primary fields are not click sortable');
|
||||
|
||||
$this->assertTrue($data[$current_table][$field_storage->getName()]['help'] instanceof MarkupInterface);
|
||||
$this->assertEqual($data[$current_table][$field_storage->getName()]['help'], 'Appears in: page, article. Also known as: Content: The giraffe2" label');
|
||||
|
||||
$this->assertTrue($data[$current_table][$field_storage->getName() . '_value']['help'] instanceof MarkupInterface);
|
||||
$this->assertEqual($data[$current_table][$field_storage->getName() . '_value']['help'], 'Appears in: page, article. Also known as: Content: The giraffe" label (field_name_0)');
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -85,7 +85,18 @@ class GlossaryTest extends ViewTestBase {
|
|||
],
|
||||
[
|
||||
'config:views.view.glossary',
|
||||
// Listed for letter 'a'
|
||||
'node:' . $nodes_by_char['a'][0]->id(), 'node:' . $nodes_by_char['a'][1]->id(), 'node:' . $nodes_by_char['a'][2]->id(),
|
||||
// Link for letter 'd'.
|
||||
'node:1',
|
||||
// Link for letter 'p'.
|
||||
'node:16',
|
||||
// Link for letter 'r'.
|
||||
'node:2',
|
||||
// Link for letter 'l'.
|
||||
'node:21',
|
||||
// Link for letter 'u'.
|
||||
'node:6',
|
||||
'node_list',
|
||||
'user:0',
|
||||
'user_list',
|
||||
|
|
|
@ -191,7 +191,7 @@ class AreaEntityTest extends ViewKernelTestBase {
|
|||
public function doTestCalculateDependencies() {
|
||||
$view = View::load('test_entity_area');
|
||||
|
||||
$dependencies = $view->calculateDependencies();
|
||||
$dependencies = $view->calculateDependencies()->getDependencies();
|
||||
// Ensure that both config and content entity dependencies are calculated.
|
||||
$this->assertEqual([
|
||||
'config' => ['block.block.test_block'],
|
||||
|
|
|
@ -115,6 +115,41 @@ class AreaTest extends HandlerTestBase {
|
|||
$this->assertTrue(strpos($output, '<script') === FALSE, 'Script tags were escaped');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that the header and footer areas are not rendered if empty.
|
||||
*/
|
||||
public function testRenderEmptyHeaderFooter() {
|
||||
$view = Views::getView('test_example_area');
|
||||
$view->initHandlers();
|
||||
|
||||
// Set example empty text.
|
||||
$view->empty['test_example']->options['string'] = '<p>' . $this->randomMachineName() . '</p>';
|
||||
|
||||
$xpath = '//div[contains(@class, :class)]';
|
||||
|
||||
// Verify that the empty header and footer sections have not been rendered.
|
||||
$output = $view->preview();
|
||||
$html = $this->container->get('renderer')->renderRoot($output);
|
||||
$this->setRawContent($html);
|
||||
$this->assertEqual(0, count($this->xpath($xpath, [':class' => 'view-header'])));
|
||||
$this->assertEqual(0, count($this->xpath($xpath, [':class' => 'view-footer'])));
|
||||
|
||||
// Set example header text.
|
||||
$view->header['test_example']->options['string'] = '<p>' . $this->randomMachineName() . '</p>';
|
||||
$view->header['test_example']->options['empty'] = TRUE;
|
||||
|
||||
// Set example footer text.
|
||||
$view->footer['test_example']->options['string'] = '<p>' . $this->randomMachineName() . '</p>';
|
||||
$view->footer['test_example']->options['empty'] = TRUE;
|
||||
|
||||
// Verify that the header and footer sections have been rendered.
|
||||
$output = $view->preview();
|
||||
$html = $this->container->get('renderer')->renderRoot($output);
|
||||
$this->setRawContent($html);
|
||||
$this->assertEqual(1, count($this->xpath($xpath, [':class' => 'view-header'])));
|
||||
$this->assertEqual(1, count($this->xpath($xpath, [':class' => 'view-footer'])));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the access for an area.
|
||||
*/
|
||||
|
|
|
@ -41,7 +41,7 @@ class AreaViewTest extends ViewKernelTestBase {
|
|||
$view = Views::getView('test_area_view');
|
||||
|
||||
// Tests \Drupal\views\Plugin\views\area\View::calculateDependencies().
|
||||
$this->assertIdentical(['config' => ['views.view.test_simple_argument']], $view->calculateDependencies());
|
||||
$this->assertIdentical(['config' => ['views.view.test_simple_argument']], $view->getDependencies());
|
||||
|
||||
$this->executeView($view);
|
||||
$output = $view->render();
|
||||
|
|
|
@ -31,6 +31,16 @@ class FieldDropButtonTest extends HandlerTestBase {
|
|||
*/
|
||||
public static $modules = array('node');
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
$admin_user = $this->drupalCreateUser(['access content overview', 'administer nodes', 'bypass node access']);
|
||||
$this->drupalLogin($admin_user);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests dropbutton field.
|
||||
*/
|
||||
|
@ -48,6 +58,14 @@ class FieldDropButtonTest extends HandlerTestBase {
|
|||
$result = $this->xpath('//ul[contains(@class, dropbutton)]/li/a[contains(@href, :path) and text()=:title]', array(':path' => '/node/' . $node->id(), ':title' => t('Custom Text')));
|
||||
$this->assertEqual(count($result), 1, 'Just one custom link was found.');
|
||||
}
|
||||
|
||||
// Check if the dropbutton.js library is available.
|
||||
$this->drupalGet('admin/content');
|
||||
$this->assertRaw('dropbutton.js');
|
||||
// Check if the dropbutton.js library is available on a cached page to
|
||||
// ensure that bubbleable metadata is not lost in the views render workflow.
|
||||
$this->drupalGet('admin/content');
|
||||
$this->assertRaw('dropbutton.js');
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -9,6 +9,8 @@ namespace Drupal\views\Tests\Handler;
|
|||
|
||||
use Drupal\Core\Url;
|
||||
use Drupal\entity_test\Entity\EntityTest;
|
||||
use Drupal\language\Entity\ConfigurableLanguage;
|
||||
use Drupal\node\Entity\Node;
|
||||
|
||||
/**
|
||||
* Tests the core Drupal\views\Plugin\views\field\EntityOperations handler.
|
||||
|
@ -29,30 +31,62 @@ class FieldEntityOperationsTest extends HandlerTestBase {
|
|||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = array('entity_test');
|
||||
public static $modules = array('node', 'language');
|
||||
|
||||
function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
// Create Article content type.
|
||||
$this->drupalCreateContentType(['type' => 'article', 'name' => 'Article']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests entity operations field.
|
||||
*/
|
||||
public function testEntityOperations() {
|
||||
// Create some test entities.
|
||||
// Add languages and refresh the container so the entity manager will have
|
||||
// fresh data.
|
||||
ConfigurableLanguage::createFromLangcode('hu')->save();
|
||||
ConfigurableLanguage::createFromLangcode('es')->save();
|
||||
$this->rebuildContainer();
|
||||
|
||||
// Create some test entities. Every other entity is Hungarian while all
|
||||
// have a Spanish translation.
|
||||
$entities = array();
|
||||
for ($i = 0; $i < 5; $i++) {
|
||||
EntityTest::create(array(
|
||||
'name' => $this->randomString(),
|
||||
))->save();
|
||||
$entity = Node::create([
|
||||
'title' => $this->randomString(),
|
||||
'type' => 'article',
|
||||
'langcode' => $i % 2 === 0 ? 'hu' : 'en',
|
||||
]);
|
||||
$entity->save();
|
||||
$translation = $entity->addTranslation('es');
|
||||
$translation->set('title', $entity->getTitle() . ' in Spanish');
|
||||
$translation->save();
|
||||
$entities[$i] = $entity;
|
||||
}
|
||||
$entities = EntityTest::loadMultiple();
|
||||
|
||||
$admin_user = $this->drupalCreateUser(array('access administration pages', 'administer entity_test content'));
|
||||
$this->drupalLogin($admin_user);
|
||||
$admin_user = $this->drupalCreateUser(array('access administration pages', 'administer nodes', 'bypass node access'));
|
||||
$this->drupalLogin($this->rootUser);
|
||||
$this->drupalGet('test-entity-operations');
|
||||
|
||||
/** @var $entity \Drupal\entity_test\Entity\EntityTest */
|
||||
foreach ($entities as $entity) {
|
||||
$operations = \Drupal::entityManager()->getListBuilder('entity_test')->getOperations($entity);
|
||||
foreach ($operations as $operation) {
|
||||
$expected_destination = Url::fromUri('internal:/test-entity-operations')->toString();
|
||||
$result = $this->xpath('//ul[contains(@class, dropbutton)]/li/a[contains(@href, :path) and text()=:title]', array(':path' => $operation['url']->toString() . '?destination=' . $expected_destination, ':title' => $operation['title']));
|
||||
$this->assertEqual(count($result), 1, t('Found entity @operation link with destination parameter.', array('@operation' => $operation['title'])));
|
||||
/** @var \Drupal\Core\Language\LanguageInterface $language */
|
||||
foreach ($entity->getTranslationLanguages() as $language) {
|
||||
$entity = $entity->getTranslation($language->getId());
|
||||
$operations = \Drupal::entityManager()->getListBuilder('node')->getOperations($entity);
|
||||
$this->assertTrue(count($operations) > 0, 'There are operations.');
|
||||
foreach ($operations as $operation) {
|
||||
$expected_destination = Url::fromUri('internal:/test-entity-operations')->toString();
|
||||
$result = $this->xpath('//ul[contains(@class, dropbutton)]/li/a[@href=:path and text()=:title]', array(':path' => $operation['url']->toString() . '?destination=' . $expected_destination, ':title' => $operation['title']));
|
||||
$this->assertEqual(count($result), 1, t('Found entity @operation link with destination parameter.', array('@operation' => $operation['title'])));
|
||||
// Entities which were created in Hungarian should link to the Hungarian
|
||||
// edit form, others to the English one (which has no path prefix here).
|
||||
$base_path = \Drupal::request()->getBasePath();
|
||||
$parts = explode('/', str_replace($base_path, '', $operation['url']->toString()));
|
||||
$expected_prefix = ($language->getId() != 'en' ? $language->getId() : 'node');
|
||||
$this->assertEqual($parts[1], $expected_prefix, 'Entity operation links to the correct language for the entity.');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -83,6 +83,7 @@ class FieldFieldTest extends ViewKernelTestBase {
|
|||
$this->testUsers[$i] = User::create([
|
||||
'name' => 'test ' . $i,
|
||||
'timezone' => User::getAllowedTimezones()[$i],
|
||||
'created' => REQUEST_TIME - rand(0, 3600)
|
||||
]);
|
||||
$this->testUsers[$i]->save();
|
||||
}
|
||||
|
@ -371,31 +372,47 @@ class FieldFieldTest extends ViewKernelTestBase {
|
|||
public function testComplexRender() {
|
||||
$executable = Views::getView('test_field_field_complex_test');
|
||||
$executable->execute();
|
||||
$date_formatter = \Drupal::service('date.formatter');
|
||||
|
||||
$this->assertEqual($this->testUsers[0]->getTimeZone(), $executable->getStyle()->getField(0, 'timezone'));
|
||||
$this->assertEqual("1, 3", $executable->getStyle()->getField(0, 'field_test_multiple'));
|
||||
$this->assertEqual("1", $executable->getStyle()->getField(0, 'field_test_multiple_1'));
|
||||
$this->assertEqual("3", $executable->getStyle()->getField(0, 'field_test_multiple_2'));
|
||||
$this->assertEqual($date_formatter->format($this->testUsers[0]->getCreatedTime(), 'custom', 'Y'), $executable->getStyle()->getField(0, 'created'));
|
||||
$this->assertEqual($date_formatter->format($this->testUsers[0]->getCreatedTime(), 'custom', 'H:i:s'), $executable->getStyle()->getField(0, 'created_1'));
|
||||
$this->assertEqual($date_formatter->format($this->testUsers[0]->getCreatedTime(), 'fallback'), $executable->getStyle()->getField(0, 'created_2'));
|
||||
|
||||
$this->assertEqual($this->testUsers[1]->getTimeZone(), $executable->getStyle()->getField(1, 'timezone'));
|
||||
$this->assertEqual("7, 0", $executable->getStyle()->getField(1, 'field_test_multiple'));
|
||||
$this->assertEqual("7", $executable->getStyle()->getField(1, 'field_test_multiple_1'));
|
||||
$this->assertEqual("0", $executable->getStyle()->getField(1, 'field_test_multiple_2'));
|
||||
$this->assertEqual($date_formatter->format($this->testUsers[1]->getCreatedTime(), 'custom', 'Y'), $executable->getStyle()->getField(1, 'created'));
|
||||
$this->assertEqual($date_formatter->format($this->testUsers[1]->getCreatedTime(), 'custom', 'H:i:s'), $executable->getStyle()->getField(1, 'created_1'));
|
||||
$this->assertEqual($date_formatter->format($this->testUsers[1]->getCreatedTime(), 'fallback'), $executable->getStyle()->getField(1, 'created_2'));
|
||||
|
||||
$this->assertEqual($this->testUsers[2]->getTimeZone(), $executable->getStyle()->getField(2, 'timezone'));
|
||||
$this->assertEqual("3, 5", $executable->getStyle()->getField(2, 'field_test_multiple'));
|
||||
$this->assertEqual("3", $executable->getStyle()->getField(2, 'field_test_multiple_1'));
|
||||
$this->assertEqual("5", $executable->getStyle()->getField(2, 'field_test_multiple_2'));
|
||||
$this->assertEqual($date_formatter->format($this->testUsers[2]->getCreatedTime(), 'custom', 'Y'), $executable->getStyle()->getField(2, 'created'));
|
||||
$this->assertEqual($date_formatter->format($this->testUsers[2]->getCreatedTime(), 'custom', 'H:i:s'), $executable->getStyle()->getField(2, 'created_1'));
|
||||
$this->assertEqual($date_formatter->format($this->testUsers[2]->getCreatedTime(), 'fallback'), $executable->getStyle()->getField(2, 'created_2'));
|
||||
|
||||
$this->assertEqual($this->testUsers[3]->getTimeZone(), $executable->getStyle()->getField(3, 'timezone'));
|
||||
$this->assertEqual("9, 9", $executable->getStyle()->getField(3, 'field_test_multiple'));
|
||||
$this->assertEqual("9", $executable->getStyle()->getField(3, 'field_test_multiple_1'));
|
||||
$this->assertEqual("9", $executable->getStyle()->getField(3, 'field_test_multiple_2'));
|
||||
$this->assertEqual($date_formatter->format($this->testUsers[3]->getCreatedTime(), 'custom', 'Y'), $executable->getStyle()->getField(3, 'created'));
|
||||
$this->assertEqual($date_formatter->format($this->testUsers[3]->getCreatedTime(), 'custom', 'H:i:s'), $executable->getStyle()->getField(3, 'created_1'));
|
||||
$this->assertEqual($date_formatter->format($this->testUsers[3]->getCreatedTime(), 'fallback'), $executable->getStyle()->getField(3, 'created_2'));
|
||||
|
||||
$this->assertEqual($this->testUsers[4]->getTimeZone(), $executable->getStyle()->getField(4, 'timezone'));
|
||||
$this->assertEqual("9, 0", $executable->getStyle()->getField(4, 'field_test_multiple'));
|
||||
$this->assertEqual("9", $executable->getStyle()->getField(4, 'field_test_multiple_1'));
|
||||
$this->assertEqual("0", $executable->getStyle()->getField(4, 'field_test_multiple_2'));
|
||||
$this->assertEqual($date_formatter->format($this->testUsers[4]->getCreatedTime(), 'custom', 'Y'), $executable->getStyle()->getField(4, 'created'));
|
||||
$this->assertEqual($date_formatter->format($this->testUsers[4]->getCreatedTime(), 'custom', 'H:i:s'), $executable->getStyle()->getField(4, 'created_1'));
|
||||
$this->assertEqual($date_formatter->format($this->testUsers[4]->getCreatedTime(), 'fallback'), $executable->getStyle()->getField(4, 'created_2'));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -27,7 +27,7 @@ class FieldKernelTest extends ViewKernelTestBase {
|
|||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $testViews = array('test_view', 'test_field_tokens', 'test_field_output');
|
||||
public static $testViews = array('test_view', 'test_field_tokens', 'test_field_argument_tokens', 'test_field_output');
|
||||
|
||||
/**
|
||||
* Map column names.
|
||||
|
@ -105,8 +105,9 @@ class FieldKernelTest extends ViewKernelTestBase {
|
|||
* The value to search for.
|
||||
* @param string $message
|
||||
* (optional) A message to display with the assertion. Do not translate
|
||||
* messages: use format_string() to embed variables in the message text, not
|
||||
* t(). If left blank, a default message will be displayed.
|
||||
* messages: use \Drupal\Component\Utility\SafeMarkup::format() to embed
|
||||
* variables in the message text, not t(). If left blank, a default message
|
||||
* will be displayed.
|
||||
* @param string $group
|
||||
* (optional) The group this message is in, which is displayed in a column
|
||||
* in test output. Use 'Debug' to indicate this is debugging output. Do not
|
||||
|
@ -129,8 +130,9 @@ class FieldKernelTest extends ViewKernelTestBase {
|
|||
* The value to search for.
|
||||
* @param string $message
|
||||
* (optional) A message to display with the assertion. Do not translate
|
||||
* messages: use format_string() to embed variables in the message text, not
|
||||
* t(). If left blank, a default message will be displayed.
|
||||
* messages: use \Drupal\Component\Utility\SafeMarkup::format() to embed
|
||||
* variables in the message text, not t(). If left blank, a default message
|
||||
* will be displayed.
|
||||
* @param string $group
|
||||
* (optional) The group this message is in, which is displayed in a column
|
||||
* in test output. Use 'Debug' to indicate this is debugging output. Do not
|
||||
|
@ -171,6 +173,44 @@ class FieldKernelTest extends ViewKernelTestBase {
|
|||
$this->assertSubString($output, $random_text);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the arguments tokens on field level.
|
||||
*/
|
||||
public function testArgumentTokens() {
|
||||
/** @var \Drupal\Core\Render\RendererInterface $renderer */
|
||||
$renderer = \Drupal::service('renderer');
|
||||
|
||||
$view = Views::getView('test_field_argument_tokens');
|
||||
$this->executeView($view, ['{{ { "#pre_render": ["views_test_data_test_pre_render_function"]} }}']);
|
||||
|
||||
$name_field_0 = $view->field['name'];
|
||||
|
||||
// Test the old style tokens.
|
||||
$name_field_0->options['alter']['alter_text'] = TRUE;
|
||||
$name_field_0->options['alter']['text'] = '%1 !1';
|
||||
|
||||
$row = $view->result[0];
|
||||
$output = $renderer->executeInRenderContext(new RenderContext(), function () use ($name_field_0, $row) {
|
||||
return $name_field_0->advancedRender($row);
|
||||
});
|
||||
|
||||
$this->assertFalse(strpos((string) $output, 'views_test_data_test_pre_render_function executed') !== FALSE, 'Ensure that the pre_render function was not executed');
|
||||
$this->assertEqual('%1 !1', (string) $output, "Ensure that old style placeholders aren't replaced");
|
||||
|
||||
// This time use new style tokens but ensure that we still don't allow
|
||||
// arbitrary code execution.
|
||||
$name_field_0->options['alter']['alter_text'] = TRUE;
|
||||
$name_field_0->options['alter']['text'] = '{{ arguments.null }} {{ raw_arguments.null }}';
|
||||
|
||||
$row = $view->result[0];
|
||||
$output = $renderer->executeInRenderContext(new RenderContext(), function () use ($name_field_0, $row) {
|
||||
return $name_field_0->advancedRender($row);
|
||||
});
|
||||
|
||||
$this->assertFalse(strpos((string) $output, 'views_test_data_test_pre_render_function executed') !== FALSE, 'Ensure that the pre_render function was not executed');
|
||||
$this->assertEqual('{{ { "#pre_render": ["views_test_data_test_pre_render_function"]} }} {{ { "#pre_render": ["views_test_data_test_pre_render_function"]} }}', (string) $output, 'Ensure that new style placeholders are replaced');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the field tokens, row level and field level.
|
||||
*/
|
||||
|
@ -202,25 +242,25 @@ class FieldKernelTest extends ViewKernelTestBase {
|
|||
$output = $renderer->executeInRenderContext(new RenderContext(), function () use ($name_field_0, $row) {
|
||||
return $name_field_0->advancedRender($row);
|
||||
});
|
||||
$this->assertEqual($output, $expected_output_0, format_string('Test token replacement: "!token" gave "!output"', [
|
||||
'!token' => $name_field_0->options['alter']['text'],
|
||||
'!output' => $output,
|
||||
$this->assertEqual($output, $expected_output_0, format_string('Test token replacement: "@token" gave "@output"', [
|
||||
'@token' => $name_field_0->options['alter']['text'],
|
||||
'@output' => $output,
|
||||
]));
|
||||
|
||||
$output = $renderer->executeInRenderContext(new RenderContext(), function () use ($name_field_1, $row) {
|
||||
return $name_field_1->advancedRender($row);
|
||||
});
|
||||
$this->assertEqual($output, $expected_output_1, format_string('Test token replacement: "!token" gave "!output"', [
|
||||
'!token' => $name_field_1->options['alter']['text'],
|
||||
'!output' => $output,
|
||||
$this->assertEqual($output, $expected_output_1, format_string('Test token replacement: "@token" gave "@output"', [
|
||||
'@token' => $name_field_1->options['alter']['text'],
|
||||
'@output' => $output,
|
||||
]));
|
||||
|
||||
$output = $renderer->executeInRenderContext(new RenderContext(), function () use ($name_field_2, $row) {
|
||||
return $name_field_2->advancedRender($row);
|
||||
});
|
||||
$this->assertEqual($output, $expected_output_2, format_string('Test token replacement: "!token" gave "!output"', [
|
||||
'!token' => $name_field_2->options['alter']['text'],
|
||||
'!output' => $output,
|
||||
$this->assertEqual($output, $expected_output_2, format_string('Test token replacement: "@token" gave "@output"', [
|
||||
'@token' => $name_field_2->options['alter']['text'],
|
||||
'@output' => $output,
|
||||
]));
|
||||
}
|
||||
|
||||
|
@ -233,10 +273,10 @@ class FieldKernelTest extends ViewKernelTestBase {
|
|||
$output = $renderer->executeInRenderContext(new RenderContext(), function () use ($job_field, $row) {
|
||||
return $job_field->advancedRender($row);
|
||||
});
|
||||
$this->assertSubString($output, $random_text, format_string('Make sure the self token (!token => !value) appears in the output (!output)', [
|
||||
'!value' => $random_text,
|
||||
'!output' => $output,
|
||||
'!token' => $job_field->options['alter']['text'],
|
||||
$this->assertSubString($output, $random_text, format_string('Make sure the self token (@token => @value) appears in the output (@output)', [
|
||||
'@value' => $random_text,
|
||||
'@output' => $output,
|
||||
'@token' => $job_field->options['alter']['text'],
|
||||
]));
|
||||
|
||||
// Verify the token format used in D7 and earlier does not get substituted.
|
||||
|
@ -247,10 +287,10 @@ class FieldKernelTest extends ViewKernelTestBase {
|
|||
$output = $renderer->executeInRenderContext(new RenderContext(), function () use ($job_field, $row) {
|
||||
return $job_field->advancedRender($row);
|
||||
});
|
||||
$this->assertEqual($output, $old_token, format_string('Make sure the old token style (!token => !value) is not changed in the output (!output)', [
|
||||
'!value' => $random_text,
|
||||
'!output' => $output,
|
||||
'!token' => $job_field->options['alter']['text'],
|
||||
$this->assertEqual($output, $old_token, format_string('Make sure the old token style (@token => @value) is not changed in the output (@output)', [
|
||||
'@value' => $random_text,
|
||||
'@output' => $output,
|
||||
'@token' => $job_field->options['alter']['text'],
|
||||
]));
|
||||
|
||||
// Verify HTML tags are allowed in rewrite templates while token
|
||||
|
@ -280,9 +320,9 @@ class FieldKernelTest extends ViewKernelTestBase {
|
|||
$output = $renderer->executeInRenderContext(new RenderContext(), function () use ($job_field, $row) {
|
||||
return $job_field->advancedRender($row);
|
||||
});
|
||||
$this->assertEqual($output, $random_text, format_string('Make sure a script tag in the template (!template) is removed, leaving only the replaced token in the output (!output)', [
|
||||
'!output' => $output,
|
||||
'!template' => $rewrite_template,
|
||||
$this->assertEqual($output, $random_text, format_string('Make sure a script tag in the template (@template) is removed, leaving only the replaced token in the output (@output)', [
|
||||
'@output' => $output,
|
||||
'@template' => $rewrite_template,
|
||||
]));
|
||||
}
|
||||
|
||||
|
|
|
@ -11,6 +11,7 @@ use Drupal\Component\Utility\Html;
|
|||
use Drupal\Component\Utility\Unicode;
|
||||
use Drupal\Component\Utility\UrlHelper;
|
||||
use Drupal\Core\Render\RenderContext;
|
||||
use Drupal\Core\Url;
|
||||
use Drupal\system\Tests\Cache\AssertPageCacheContextsAndTagsTrait;
|
||||
use Drupal\views\Views;
|
||||
|
||||
|
@ -87,7 +88,7 @@ class FieldWebTest extends HandlerTestBase {
|
|||
$ids = $this->clickSortLoadIdsFromOutput();
|
||||
$this->assertEqual($ids, range(1, 5));
|
||||
|
||||
$this->clickLink(t('ID'));
|
||||
$this->clickLink(t('ID Sort descending'));
|
||||
// Check that the output has the expected order (desc).
|
||||
$ids = $this->clickSortLoadIdsFromOutput();
|
||||
$this->assertEqual($ids, range(5, 1, -1));
|
||||
|
@ -262,7 +263,7 @@ class FieldWebTest extends HandlerTestBase {
|
|||
|
||||
// @todo The route-based URL generator strips out NULL attributes.
|
||||
// $expected_result = \Drupal::url('entity.node.canonical', ['node' => '123'], ['query' => ['foo' => NULL], 'fragment' => 'bar', 'absolute' => $absolute]);
|
||||
$expected_result = \Drupal::urlGenerator()->generateFromPath('node/123', array('query' => array('foo' => NULL), 'fragment' => 'bar', 'absolute' => $absolute));
|
||||
$expected_result = Url::fromUserInput('/node/123', array('query' => array('foo' => NULL), 'fragment' => 'bar', 'absolute' => $absolute))->toString();
|
||||
$alter['path'] = 'node/123?foo#bar';
|
||||
$result = $renderer->executeInRenderContext(new RenderContext(), function () use ($id_field, $row) {
|
||||
return $id_field->theme($row);
|
||||
|
@ -564,14 +565,14 @@ class FieldWebTest extends HandlerTestBase {
|
|||
$output = $renderer->executeInRenderContext(new RenderContext(), function () use ($name_field, $row) {
|
||||
return $name_field->advancedRender($row);
|
||||
});
|
||||
$this->assertSubString($output, $trimmed_name, format_string('Make sure the trimmed output (!trimmed) appears in the rendered output (!output).', array('!trimmed' => $trimmed_name, '!output' => $output)));
|
||||
$this->assertNotSubString($output, $row->views_test_data_name, format_string("Make sure the untrimmed value (!untrimmed) shouldn't appear in the rendered output (!output).", array('!untrimmed' => $row->views_test_data_name, '!output' => $output)));
|
||||
$this->assertSubString($output, $trimmed_name, format_string('Make sure the trimmed output (@trimmed) appears in the rendered output (@output).', array('@trimmed' => $trimmed_name, '@output' => $output)));
|
||||
$this->assertNotSubString($output, $row->views_test_data_name, format_string("Make sure the untrimmed value (@untrimmed) shouldn't appear in the rendered output (@output).", array('@untrimmed' => $row->views_test_data_name, '@output' => $output)));
|
||||
|
||||
$name_field->options['alter']['max_length'] = 9;
|
||||
$output = $renderer->executeInRenderContext(new RenderContext(), function () use ($name_field, $row) {
|
||||
return $name_field->advancedRender($row);
|
||||
});
|
||||
$this->assertSubString($output, $trimmed_name, format_string('Make sure the untrimmed (!untrimmed) output appears in the rendered output (!output).', array('!trimmed' => $trimmed_name, '!output' => $output)));
|
||||
$this->assertSubString($output, $trimmed_name, format_string('Make sure the untrimmed (@untrimmed) output appears in the rendered output (@output).', array('@trimmed' => $trimmed_name, '@output' => $output)));
|
||||
|
||||
// Take word_boundary into account for the tests.
|
||||
$name_field->options['alter']['max_length'] = 5;
|
||||
|
@ -615,10 +616,10 @@ class FieldWebTest extends HandlerTestBase {
|
|||
});
|
||||
|
||||
if ($tuple['trimmed']) {
|
||||
$this->assertNotSubString($output, $tuple['value'], format_string('The untrimmed value (!untrimmed) should not appear in the trimmed output (!output).', array('!untrimmed' => $tuple['value'], '!output' => $output)));
|
||||
$this->assertNotSubString($output, $tuple['value'], format_string('The untrimmed value (@untrimmed) should not appear in the trimmed output (@output).', array('@untrimmed' => $tuple['value'], '@output' => $output)));
|
||||
}
|
||||
if (!empty($tuple['trimmed_value'])) {
|
||||
$this->assertSubString($output, $tuple['trimmed_value'], format_string('The trimmed value (!trimmed) should appear in the trimmed output (!output).', array('!trimmed' => $tuple['trimmed_value'], '!output' => $output)));
|
||||
$this->assertSubString($output, $tuple['trimmed_value'], format_string('The trimmed value (@trimmed) should appear in the trimmed output (@output).', array('@trimmed' => $tuple['trimmed_value'], '@output' => $output)));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -178,14 +178,14 @@ class ModuleTest extends ViewKernelTestBase {
|
|||
foreach ($all_views as $id => $view) {
|
||||
$expected_options[$id] = $view->label();
|
||||
}
|
||||
$this->assertIdentical($expected_options, Views::getViewsAsOptions(TRUE), 'Expected options array was returned.');
|
||||
$this->assertIdentical($expected_options, $this->castSafeStrings(Views::getViewsAsOptions(TRUE)), 'Expected options array was returned.');
|
||||
|
||||
// Test the default.
|
||||
$this->assertIdentical($this->formatViewOptions($all_views), Views::getViewsAsOptions(), 'Expected options array for all views was returned.');
|
||||
$this->assertIdentical($this->formatViewOptions($all_views), $this->castSafeStrings(Views::getViewsAsOptions()), 'Expected options array for all views was returned.');
|
||||
// Test enabled views.
|
||||
$this->assertIdentical($this->formatViewOptions($expected_enabled), Views::getViewsAsOptions(FALSE, 'enabled'), 'Expected enabled options array was returned.');
|
||||
$this->assertIdentical($this->formatViewOptions($expected_enabled), $this->castSafeStrings(Views::getViewsAsOptions(FALSE, 'enabled')), 'Expected enabled options array was returned.');
|
||||
// Test disabled views.
|
||||
$this->assertIdentical($this->formatViewOptions($expected_disabled), Views::getViewsAsOptions(FALSE, 'disabled'), 'Expected disabled options array was returned.');
|
||||
$this->assertIdentical($this->formatViewOptions($expected_disabled), $this->castSafeStrings(Views::getViewsAsOptions(FALSE, 'disabled')), 'Expected disabled options array was returned.');
|
||||
|
||||
// Test the sort parameter.
|
||||
$all_views_sorted = $all_views;
|
||||
|
@ -201,10 +201,10 @@ class ModuleTest extends ViewKernelTestBase {
|
|||
$expected_opt_groups = array();
|
||||
foreach ($all_views as $view) {
|
||||
foreach ($view->get('display') as $display) {
|
||||
$expected_opt_groups[$view->id()][$view->id() . ':' . $display['id']] = 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, Views::getViewsAsOptions(FALSE, 'all', NULL, TRUE), 'Expected option array for an option group returned.');
|
||||
$this->assertIdentical($expected_opt_groups, $this->castSafeStrings(Views::getViewsAsOptions(FALSE, 'all', NULL, TRUE)), 'Expected option array for an option group returned.');
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -347,7 +347,7 @@ class ModuleTest extends ViewKernelTestBase {
|
|||
$expected_options = array();
|
||||
foreach ($views as $view) {
|
||||
foreach ($view->get('display') as $display) {
|
||||
$expected_options[$view->id() . ':' . $display['id']] = t('View: @view - Display: @display',
|
||||
$expected_options[$view->id() . ':' . $display['id']] = (string) t('View: @view - Display: @display',
|
||||
array('@view' => $view->id(), '@display' => $display['id']));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ namespace Drupal\views\Tests\Plugin;
|
|||
|
||||
use Drupal\views\Tests\ViewKernelTestBase;
|
||||
use Drupal\views\Views;
|
||||
use Drupal\views_test_data\Plugin\views\argument_validator\ArgumentValidatorTest as ArgumentValidatorTestPlugin;
|
||||
|
||||
/**
|
||||
* Tests Views argument validators.
|
||||
|
@ -22,7 +23,7 @@ class ArgumentValidatorTest extends ViewKernelTestBase {
|
|||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $testViews = array('test_view_argument_validate_numeric');
|
||||
public static $testViews = ['test_view_argument_validate_numeric', 'test_view'];
|
||||
|
||||
function testArgumentValidateNumeric() {
|
||||
$view = Views::getView('test_view_argument_validate_numeric');
|
||||
|
@ -33,4 +34,37 @@ class ArgumentValidatorTest extends ViewKernelTestBase {
|
|||
$this->assertTrue($view->argument['null']->validateArgument(12));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the argument validator test plugin.
|
||||
*
|
||||
* @see Drupal\views_test_data\Plugin\views\argument_validator\ArgumentValidatorTest
|
||||
*/
|
||||
public function testArgumentValidatorPlugin() {
|
||||
$view = Views::getView('test_view');
|
||||
|
||||
// Add a new argument and set the test plugin for the argument_validator.
|
||||
$options = [
|
||||
'specify_validation' => TRUE,
|
||||
'validate' => [
|
||||
'type' => 'argument_validator_test'
|
||||
]
|
||||
];
|
||||
$id = $view->addHandler('default', 'argument', 'views_test_data', 'name', $options);
|
||||
$view->initHandlers();
|
||||
|
||||
$test_value = $this->randomMachineName();
|
||||
|
||||
$argument = $view->argument[$id];
|
||||
$argument->options['validate_options']['test_value'] = $test_value;
|
||||
$this->assertFalse($argument->validateArgument($this->randomMachineName()), 'A random value does not validate.');
|
||||
// Reset internal flag.
|
||||
$argument->argument_validated = NULL;
|
||||
$this->assertTrue($argument->validateArgument($test_value), 'The right argument validates.');
|
||||
|
||||
$plugin = $argument->getPlugin('argument_validator');
|
||||
$this->assertTrue($plugin instanceof ArgumentValidatorTestPlugin, 'The correct argument validator plugin is used.');
|
||||
$this->assertFalse($plugin->validateArgument($this->randomMachineName()), 'A random value does not validate.');
|
||||
$this->assertTrue($plugin->validateArgument($test_value), 'The right argument validates.');
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
|
||||
namespace Drupal\views\Tests\Plugin;
|
||||
|
||||
use Drupal\Core\Cache\Cache;
|
||||
use Drupal\views\Tests\ViewKernelTestBase;
|
||||
|
||||
/**
|
||||
|
@ -38,7 +37,7 @@ class BlockDependenciesTest extends ViewKernelTestBase {
|
|||
*/
|
||||
public function testExposedBlock() {
|
||||
$block = $this->createBlock('views_exposed_filter_block:test_exposed_block-page_1');
|
||||
$dependencies = $block->calculateDependencies();
|
||||
$dependencies = $block->calculateDependencies()->getDependencies();
|
||||
$expected = array(
|
||||
'config' => array('views.view.test_exposed_block'),
|
||||
'module' => array('views'),
|
||||
|
@ -54,7 +53,7 @@ class BlockDependenciesTest extends ViewKernelTestBase {
|
|||
*/
|
||||
public function testViewsBlock() {
|
||||
$block = $this->createBlock('views_block:content_recent-block_1');
|
||||
$dependencies = $block->calculateDependencies();
|
||||
$dependencies = $block->calculateDependencies()->getDependencies();
|
||||
$expected = array(
|
||||
'config' => array('views.view.content_recent'),
|
||||
'module' => array('views'),
|
||||
|
@ -83,7 +82,6 @@ class BlockDependenciesTest extends ViewKernelTestBase {
|
|||
* - region: 'sidebar_first'.
|
||||
* - theme: The default theme.
|
||||
* - visibility: Empty array.
|
||||
* - cache: array('max_age' => Cache::PERMANENT).
|
||||
*
|
||||
* @return \Drupal\block\Entity\Block
|
||||
* The block entity.
|
||||
|
@ -97,9 +95,6 @@ class BlockDependenciesTest extends ViewKernelTestBase {
|
|||
'label' => $this->randomMachineName(8),
|
||||
'visibility' => array(),
|
||||
'weight' => 0,
|
||||
'cache' => array(
|
||||
'max_age' => Cache::PERMANENT,
|
||||
),
|
||||
);
|
||||
$values = [];
|
||||
foreach (array('region', 'id', 'theme', 'plugin', 'weight', 'visibility') as $key) {
|
||||
|
|
|
@ -34,6 +34,8 @@ class DisabledDisplayTest extends PluginTestBase {
|
|||
|
||||
$this->enableViewsTestModule();
|
||||
|
||||
$this->drupalPlaceBlock('page_title_block');
|
||||
|
||||
$admin_user = $this->drupalCreateUser(array('administer site configuration'));
|
||||
$this->drupalLogin($admin_user);
|
||||
}
|
||||
|
@ -58,7 +60,7 @@ class DisabledDisplayTest extends PluginTestBase {
|
|||
|
||||
// Enabled page display should return content.
|
||||
$this->drupalGet('test-disabled-display');
|
||||
$result = $this->xpath('//h1');
|
||||
$result = $this->xpath('//h1[@class="page-title"]');
|
||||
$this->assertEqual($result[0], 'test_disabled_display', 'The enabled page_1 display is accessible.');
|
||||
|
||||
// Disabled page view should 404.
|
||||
|
@ -77,7 +79,7 @@ class DisabledDisplayTest extends PluginTestBase {
|
|||
|
||||
// Check that the originally disabled page_2 display is now enabled.
|
||||
$this->drupalGet('test-disabled-display-2');
|
||||
$result = $this->xpath('//h1');
|
||||
$result = $this->xpath('//h1[@class="page-title"]');
|
||||
$this->assertEqual($result[0], 'test_disabled_display', 'The enabled page_2 display is accessible.');
|
||||
|
||||
// Disable each disabled display and save the view.
|
||||
|
|
|
@ -94,11 +94,10 @@ class DisplayPageTest extends ViewKernelTestBase {
|
|||
|
||||
// Check the controller defaults.
|
||||
foreach ($collection as $id => $route) {
|
||||
if (strpos($id, 'test_page_display_route') === 0) {
|
||||
$this->assertEqual($route->getDefault('_controller'), 'Drupal\views\Routing\ViewPageController::handle');
|
||||
$this->assertEqual($route->getDefault('view_id'), 'test_page_display_route');
|
||||
$this->assertEqual($route->getDefault('display_id'), str_replace('test_page_display_route.', '', $id));
|
||||
}
|
||||
$this->assertEqual($route->getDefault('_controller'), 'Drupal\views\Routing\ViewPageController::handle');
|
||||
$id_parts = explode('.', $id);
|
||||
$this->assertEqual($route->getDefault('view_id'), $id_parts[1]);
|
||||
$this->assertEqual($route->getDefault('display_id'), $id_parts[2]);
|
||||
}
|
||||
|
||||
// Check the generated patterns and default values.
|
||||
|
@ -145,14 +144,14 @@ class DisplayPageTest extends ViewKernelTestBase {
|
|||
*/
|
||||
public function testDependencies() {
|
||||
$view = Views::getView('test_page_display');
|
||||
$this->assertIdentical([], $view->calculateDependencies());
|
||||
$this->assertIdentical([], $view->getDependencies());
|
||||
|
||||
$view = Views::getView('test_page_display_route');
|
||||
$expected = [
|
||||
'content' => ['StaticTest'],
|
||||
'module' => ['views_test_data'],
|
||||
];
|
||||
$this->assertIdentical($expected, $view->calculateDependencies());
|
||||
$this->assertIdentical($expected, $view->getDependencies());
|
||||
|
||||
$view = Views::getView('test_page_display_menu');
|
||||
$expected = [
|
||||
|
@ -161,7 +160,7 @@ class DisplayPageTest extends ViewKernelTestBase {
|
|||
'system.menu.tools',
|
||||
],
|
||||
];
|
||||
$this->assertIdentical($expected, $view->calculateDependencies());
|
||||
$this->assertIdentical($expected, $view->getDependencies());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -57,7 +57,7 @@ class DisplayPageWebTest extends PluginTestBase {
|
|||
|
||||
$this->drupalGet('test_route_with_argument/1');
|
||||
$this->assertResponse(200);
|
||||
$this->assertCacheContexts(['languages:language_interface', 'route.name', 'theme', 'url']);
|
||||
$this->assertCacheContexts(['languages:language_interface', 'route', 'theme', 'url']);
|
||||
$result = $this->xpath('//span[@class="field-content"]');
|
||||
$this->assertEqual(count($result), 1, 'Ensure that just the filtered entry was returned.');
|
||||
$this->assertEqual((string) $result[0], 1, 'The passed ID was returned.');
|
||||
|
|
|
@ -193,6 +193,31 @@ class ExposedFormTest extends ViewTestBase {
|
|||
$this->assertEqual(count($rows), 5, 'All rows are displayed by default when input is provided.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the "on demand text" for the input required exposed form type.
|
||||
*/
|
||||
public function testTextInputRequired() {
|
||||
$view = Views::getView('test_exposed_form_buttons');
|
||||
$display = &$view->storage->getDisplay('default');
|
||||
$display['display_options']['exposed_form']['type'] = 'input_required';
|
||||
// Set up the "on demand text".
|
||||
// @see https://www.drupal.org/node/535868
|
||||
$on_demand_text = 'Select any filter and click Apply to see results.';
|
||||
$display['display_options']['exposed_form']['options']['text_input_required'] = $on_demand_text;
|
||||
$display['display_options']['exposed_form']['options']['text_input_required_format'] = filter_default_format();
|
||||
$view->save();
|
||||
|
||||
// Ensure that the "on demand text" is displayed when no exposed filters are
|
||||
// applied.
|
||||
$this->drupalGet('test_exposed_form_buttons');
|
||||
$this->assertText('Select any filter and click Apply to see results.');
|
||||
|
||||
// Ensure that the "on demand text" is not displayed when an exposed filter
|
||||
// is applied.
|
||||
$this->drupalGet('test_exposed_form_buttons', array('query' => array('type' => 'article')));
|
||||
$this->assertNoText($on_demand_text);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests exposed forms with exposed sort and items per page.
|
||||
*/
|
||||
|
@ -207,7 +232,6 @@ class ExposedFormTest extends ViewTestBase {
|
|||
'entity_test_view_grants',
|
||||
'theme',
|
||||
'url.query_args',
|
||||
'user.roles:authenticated',
|
||||
'languages:language_content'
|
||||
];
|
||||
|
||||
|
|
102
core/modules/views/src/Tests/Plugin/MenuLinkTest.php
Normal file
102
core/modules/views/src/Tests/Plugin/MenuLinkTest.php
Normal file
|
@ -0,0 +1,102 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\views\Tests\Plugin\MenuLinkTest.
|
||||
*/
|
||||
|
||||
namespace Drupal\views\Tests\Plugin;
|
||||
|
||||
use Drupal\menu_link_content\Entity\MenuLinkContent;
|
||||
use Drupal\views\Tests\ViewTestBase;
|
||||
|
||||
/**
|
||||
* Tests the menu links created in views.
|
||||
*
|
||||
* @group views
|
||||
*/
|
||||
class MenuLinkTest extends ViewTestBase {
|
||||
|
||||
/**
|
||||
* Views used by this test.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $testViews = ['test_menu_link'];
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = ['views', 'views_ui', 'user', 'node', 'menu_ui', 'block'];
|
||||
|
||||
/**
|
||||
* A user with permission to administer views, menus and view content.
|
||||
*
|
||||
* @var \Drupal\user\UserInterface
|
||||
*/
|
||||
protected $adminUser;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
$this->enableViewsTestModule();
|
||||
|
||||
$this->adminUser = $this->drupalCreateUser(['administer views', 'administer menu']);
|
||||
$this->drupalPlaceBlock('system_menu_block:main');
|
||||
$this->drupalCreateContentType(['type' => 'page']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that menu links using menu_link_content as parent are visible.
|
||||
*/
|
||||
public function testHierarchicalMenuLinkVisibility() {
|
||||
$this->drupalLogin($this->adminUser);
|
||||
|
||||
$node = $this->drupalCreateNode(['type' => 'page']);
|
||||
|
||||
// Create a primary level menu link to the node.
|
||||
$link = MenuLinkContent::create([
|
||||
'title' => 'Primary level node',
|
||||
'menu_name' => 'main',
|
||||
'bundle' => 'menu_link_content',
|
||||
'parent' => '',
|
||||
'link' => [['uri' => 'entity:node/' . $node->id()]],
|
||||
]);
|
||||
$link->save();
|
||||
|
||||
$parent_menu_value = 'main:menu_link_content:' . $link->uuid();
|
||||
|
||||
// Alter the view's menu link in view page to use the menu link from the
|
||||
// node as parent.
|
||||
$this->drupalPostForm("admin/structure/views/nojs/display/test_menu_link/page_1/menu", [
|
||||
'menu[type]' => 'normal',
|
||||
'menu[title]' => 'Secondary level view page',
|
||||
'menu[parent]' => $parent_menu_value,
|
||||
], 'Apply');
|
||||
|
||||
// Save view which has pending changes.
|
||||
$this->drupalPostForm(NULL, [], 'Save');
|
||||
|
||||
// Test if the node as parent menu item is selected in our views settings.
|
||||
$this->drupalGet('admin/structure/views/nojs/display/test_menu_link/page_1/menu');
|
||||
$this->assertOptionSelected('edit-menu-parent', $parent_menu_value);
|
||||
|
||||
$this->drupalGet('');
|
||||
|
||||
// Test if the primary menu item (node) is visible, and the secondary menu
|
||||
// item (view) is hidden.
|
||||
$this->assertText('Primary level node');
|
||||
$this->assertNoText('Secondary level view page');
|
||||
|
||||
// Go to the node page and ensure that both the first and second level items
|
||||
// are visible.
|
||||
$this->drupalGet($node->urlInfo());
|
||||
$this->assertText('Primary level node');
|
||||
$this->assertText('Secondary level view page');
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show more
Reference in a new issue