Update to Drupal 8.0.0 beta 14. For more information, see https://drupal.org/node/2544542
This commit is contained in:
parent
3b2511d96d
commit
81ccda77eb
2155 changed files with 54307 additions and 46870 deletions
|
@ -117,8 +117,8 @@ views.field.numeric:
|
|||
type: boolean
|
||||
label: 'Format plural'
|
||||
format_plural_string:
|
||||
type: label
|
||||
label: 'Singular and one or more plurals'
|
||||
type: plural_label
|
||||
label: 'Plural variants'
|
||||
prefix:
|
||||
type: label
|
||||
label: 'Prefix'
|
||||
|
|
|
@ -108,14 +108,15 @@
|
|||
* @method
|
||||
*/
|
||||
Drupal.views.ajaxView.prototype.attachExposedFormAjax = function () {
|
||||
var button = $('input[type=submit], input[type=image]', this.$exposed_form);
|
||||
button = button[0];
|
||||
|
||||
var self_settings = $.extend({}, this.element_settings, {
|
||||
base: $(button).attr('id'),
|
||||
element: button
|
||||
var that = this;
|
||||
this.exposedFormAjax = [];
|
||||
$('input[type=submit], input[type=image]', this.$exposed_form).each(function (index) {
|
||||
var self_settings = $.extend({}, that.element_settings, {
|
||||
base: $(this).attr('id'),
|
||||
element: this
|
||||
});
|
||||
that.exposedFormAjax[index] = Drupal.ajax(self_settings);
|
||||
});
|
||||
this.exposedFormAjax = Drupal.ajax(self_settings);
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -14,6 +14,8 @@ use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
|
|||
use Drupal\Core\Entity\EntityStorageInterface;
|
||||
use Drupal\Core\EventSubscriber\AjaxResponseSubscriber;
|
||||
use Drupal\Core\Path\CurrentPathStack;
|
||||
use Drupal\Core\Render\BubbleableMetadata;
|
||||
use Drupal\Core\Render\RenderContext;
|
||||
use Drupal\Core\Render\RendererInterface;
|
||||
use Drupal\Core\Routing\RedirectDestinationInterface;
|
||||
use Drupal\views\Ajax\ScrollTopCommand;
|
||||
|
@ -174,9 +176,18 @@ class ViewAjaxController implements ContainerInjectionInterface {
|
|||
// Reuse the same DOM id so it matches that in drupalSettings.
|
||||
$view->dom_id = $dom_id;
|
||||
|
||||
if ($preview = $view->preview($display_id, $args)) {
|
||||
$response->addCommand(new ReplaceCommand(".js-view-dom-id-$dom_id", $preview));
|
||||
$context = new RenderContext();
|
||||
$preview = $this->renderer->executeInRenderContext($context, function() use ($view, $display_id, $args) {
|
||||
return $view->preview($display_id, $args);
|
||||
});
|
||||
if (!$context->isEmpty()) {
|
||||
$bubbleable_metadata = $context->pop();
|
||||
BubbleableMetadata::createFromRenderArray($preview)
|
||||
->merge($bubbleable_metadata)
|
||||
->applyTo($preview);
|
||||
}
|
||||
$response->addCommand(new ReplaceCommand(".js-view-dom-id-$dom_id", $preview));
|
||||
|
||||
return $response;
|
||||
}
|
||||
else {
|
||||
|
|
|
@ -138,13 +138,18 @@ class EntityFieldRenderer extends RendererBase {
|
|||
$build = $this->build[$row->index][$field_id];
|
||||
unset($this->build[$row->index][$field_id]);
|
||||
}
|
||||
else {
|
||||
elseif (isset($this->build[$row->index])) {
|
||||
// In the uncommon case where a field gets rendered several times
|
||||
// (typically through direct Views API calls), the pre-computed render
|
||||
// array was removed by the unset() above. We have to manually rebuild
|
||||
// the render array for the row.
|
||||
$build = $this->buildFields([$row])[$row->index][$field_id];
|
||||
}
|
||||
else {
|
||||
// In case the relationship is optional, there might not be any fields
|
||||
// to render for this row.
|
||||
$build = [];
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Same logic as above, in the case where we are being called for a whole
|
||||
|
@ -199,8 +204,9 @@ class EntityFieldRenderer extends RendererBase {
|
|||
$entities_by_bundles = [];
|
||||
$field = $this->view->field[current($field_ids)];
|
||||
foreach ($values as $result_row) {
|
||||
$entity = $field->getEntity($result_row);
|
||||
$entities_by_bundles[$entity->bundle()][$result_row->index] = $this->getEntityTranslation($entity, $result_row);
|
||||
if ($entity = $field->getEntity($result_row)) {
|
||||
$entities_by_bundles[$entity->bundle()][$result_row->index] = $this->getEntityTranslation($entity, $result_row);
|
||||
}
|
||||
}
|
||||
|
||||
// Determine unique sets of fields that can be processed by the same
|
||||
|
|
|
@ -7,8 +7,9 @@
|
|||
|
||||
namespace Drupal\views\Plugin\Block;
|
||||
|
||||
use Drupal\Core\Config\Entity\Query\Query;
|
||||
use Drupal\Component\Utility\SafeMarkup;
|
||||
use Drupal\Component\Utility\Xss;
|
||||
use Drupal\Core\Config\Entity\Query\Query;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
|
@ -32,7 +33,8 @@ class ViewsBlock extends ViewsBlockBase {
|
|||
if ($output = $this->view->buildRenderable($this->displayID, [], FALSE)) {
|
||||
// Override the label to the dynamic title configured in the view.
|
||||
if (empty($this->configuration['views_label']) && $this->view->getTitle()) {
|
||||
$output['#title'] = Xss::filterAdmin($this->view->getTitle());
|
||||
// @todo https://www.drupal.org/node/2527360 remove call to SafeMarkup.
|
||||
$output['#title'] = SafeMarkup::xssFilter($this->view->getTitle(), Xss::getAdminTagList());
|
||||
}
|
||||
|
||||
// Before returning the block output, convert it to a renderable array
|
||||
|
|
|
@ -9,6 +9,7 @@ namespace Drupal\views\Plugin\Derivative;
|
|||
|
||||
use Drupal\Component\Plugin\Derivative\DeriverBase;
|
||||
use Drupal\Core\Plugin\Discovery\ContainerDeriverInterface;
|
||||
use Drupal\views\Plugin\views\display\DisplayMenuInterface;
|
||||
use Drupal\views\Views;
|
||||
use Drupal\Core\Entity\EntityStorageInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
@ -57,8 +58,10 @@ class ViewsMenuLink extends DeriverBase implements ContainerDeriverInterface {
|
|||
list($view_id, $display_id) = $data;
|
||||
/** @var \Drupal\views\ViewExecutable $executable */
|
||||
$executable = $this->viewStorage->load($view_id)->getExecutable();
|
||||
$executable->initDisplay();
|
||||
$display = $executable->displayHandlers->get($display_id);
|
||||
|
||||
if ($result = $executable->getMenuLinks($display_id)) {
|
||||
if (($display instanceof DisplayMenuInterface) && ($result = $display->getMenuLinks())) {
|
||||
foreach ($result as $link_id => $link) {
|
||||
$links[$link_id] = $link + $base_plugin_definition;
|
||||
}
|
||||
|
|
|
@ -721,7 +721,7 @@ abstract class HandlerBase extends PluginBase implements ViewsHandlerInterface {
|
|||
return $views_data['table']['entity type'];
|
||||
}
|
||||
else {
|
||||
throw new \Exception(SafeMarkup::format('No entity type for field @field on view @view', array('@field' => $this->options['id'], '@view' => $this->view->storage->id())));
|
||||
throw new \Exception("No entity type for field {$this->options['id']} on view {$this->view->storage->id()}");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@ 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;
|
||||
|
@ -333,23 +334,27 @@ abstract class PluginBase extends ComponentPluginBase implements ContainerFactor
|
|||
}
|
||||
|
||||
/**
|
||||
* Replaces Views' tokens in a given string. It is the responsibility of the
|
||||
* calling function to ensure $text and $token replacements are sanitized.
|
||||
* 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
|
||||
* String with possible tokens.
|
||||
* Unsanitized string with possible tokens.
|
||||
* @param $tokens
|
||||
* Array of token => replacement_value items.
|
||||
*
|
||||
* @return String
|
||||
*/
|
||||
protected function viewsTokenReplace($text, $tokens) {
|
||||
if (!strlen($text)) {
|
||||
// No need to run filterAdmin on an empty string.
|
||||
return '';
|
||||
}
|
||||
if (empty($tokens)) {
|
||||
return $text;
|
||||
return Xss::filterAdmin($text);
|
||||
}
|
||||
|
||||
// Separate Twig tokens from other tokens (e.g.: contextual filter tokens in
|
||||
|
@ -370,14 +375,22 @@ abstract class PluginBase extends ComponentPluginBase implements ContainerFactor
|
|||
// 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 && !empty($text)) {
|
||||
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,
|
||||
'#context' => $twig_tokens,
|
||||
'#post_render' => [
|
||||
function ($children, $elements) {
|
||||
return Xss::filterAdmin($children);
|
||||
}
|
||||
],
|
||||
);
|
||||
|
||||
return $this->getRenderer()->render($build);
|
||||
return (string) $this->getRenderer()->render($build);
|
||||
}
|
||||
else {
|
||||
return $text;
|
||||
|
|
|
@ -153,7 +153,7 @@ abstract class CachePluginBase extends PluginBase {
|
|||
* Clear out cached data for a view.
|
||||
*/
|
||||
public function cacheFlush() {
|
||||
Cache::invalidateTags($this->view->storage->getCacheTags());
|
||||
Cache::invalidateTags($this->view->storage->getCacheTagsToInvalidate());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -211,7 +211,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']);
|
||||
$key_data += \Drupal::service('cache_contexts_manager')->convertTokensToKeys($this->displayHandler->getCacheMetadata()['contexts'])->getKeys();
|
||||
|
||||
$this->resultsKey = $this->view->storage->id() . ':' . $this->displayHandler->display['id'] . ':results:' . hash('sha256', serialize($key_data));
|
||||
}
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\views\Plugin\views\display\DisplayMenuInterface.
|
||||
*/
|
||||
|
||||
namespace Drupal\views\Plugin\views\display;
|
||||
|
||||
/**
|
||||
* Defines an interface for displays that provide menu links.
|
||||
*/
|
||||
interface DisplayMenuInterface {
|
||||
|
||||
/**
|
||||
* Gets menu links, if this display provides some.
|
||||
*
|
||||
* @return array
|
||||
* The menu links registers for this display.
|
||||
*
|
||||
* @see \Drupal\views\Plugin\Derivative\ViewsMenuLink
|
||||
*/
|
||||
public function getMenuLinks();
|
||||
|
||||
}
|
|
@ -2112,13 +2112,6 @@ abstract class DisplayPluginBase extends PluginBase implements DisplayPluginInte
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getMenuLinks() {
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
@ -2472,18 +2465,6 @@ abstract class DisplayPluginBase extends PluginBase implements DisplayPluginInte
|
|||
public function newDisplay() {
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function remove() {
|
||||
$menu_links = $this->getMenuLinks();
|
||||
/** @var \Drupal\Core\Menu\MenuLinkManagerInterface $menu_link_manager */
|
||||
$menu_link_manager = \Drupal::service('plugin.manager.menu.link');
|
||||
foreach ($menu_links as $menu_link_id => $menu_link) {
|
||||
$menu_link_manager->removeDefinition("views_view:$menu_link_id");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
@ -2611,6 +2592,13 @@ abstract class DisplayPluginBase extends PluginBase implements DisplayPluginInte
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function remove() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Merges plugins default values.
|
||||
*
|
||||
|
|
|
@ -381,16 +381,6 @@ interface DisplayPluginInterface {
|
|||
*/
|
||||
public function renderMoreLink();
|
||||
|
||||
/**
|
||||
* Gets menu links, if this display provides some.
|
||||
*
|
||||
* @return array
|
||||
* The menu links registers for this display.
|
||||
*
|
||||
* @see \Drupal\views\Plugin\Derivative\ViewsMenuLink
|
||||
*/
|
||||
public function getMenuLinks();
|
||||
|
||||
/**
|
||||
* Renders this display.
|
||||
*/
|
||||
|
|
|
@ -71,4 +71,5 @@ interface DisplayRouterInterface extends DisplayPluginInterface {
|
|||
* @see \Drupal\views\Plugin\views\display\DisplayRouterInterface::alterRoutes()
|
||||
*/
|
||||
public function getAlteredRouteNames();
|
||||
|
||||
}
|
||||
|
|
|
@ -67,7 +67,7 @@ class Feed extends PathPluginBase implements ResponseDisplayPluginInterface {
|
|||
/** @var \Drupal\Core\Render\RendererInterface $renderer */
|
||||
$renderer = \Drupal::service('renderer');
|
||||
|
||||
$output = $renderer->renderRoot($build);
|
||||
$output = (string) $renderer->renderRoot($build);
|
||||
|
||||
if (empty($output)) {
|
||||
throw new NotFoundHttpException();
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
namespace Drupal\views\Plugin\views\display;
|
||||
|
||||
use Drupal\Component\Utility\SafeMarkup;
|
||||
use Drupal\Component\Utility\Xss;
|
||||
use Drupal\Core\Entity\EntityStorageInterface;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
|
@ -181,7 +182,8 @@ class Page extends PathPluginBase {
|
|||
// it should be dropped.
|
||||
if (is_array($render)) {
|
||||
$render += array(
|
||||
'#title' => Xss::filterAdmin($this->view->getTitle()),
|
||||
// @todo https://www.drupal.org/node/2527360 remove call to SafeMarkup.
|
||||
'#title' => SafeMarkup::xssFilter($this->view->getTitle(), Xss::getAdminTagList()),
|
||||
);
|
||||
}
|
||||
return $render;
|
||||
|
|
|
@ -29,7 +29,7 @@ use Symfony\Component\Routing\RouteCollection;
|
|||
*
|
||||
* @see \Drupal\views\EventSubscriber\RouteSubscriber
|
||||
*/
|
||||
abstract class PathPluginBase extends DisplayPluginBase implements DisplayRouterInterface {
|
||||
abstract class PathPluginBase extends DisplayPluginBase implements DisplayRouterInterface, DisplayMenuInterface {
|
||||
|
||||
use UrlGeneratorTrait;
|
||||
|
||||
|
@ -521,4 +521,16 @@ abstract class PathPluginBase extends DisplayPluginBase implements DisplayRouter
|
|||
return $this->state->get('views.view_route_names') ?: array();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function remove() {
|
||||
$menu_links = $this->getMenuLinks();
|
||||
/** @var \Drupal\Core\Menu\MenuLinkManagerInterface $menu_link_manager */
|
||||
$menu_link_manager = \Drupal::service('plugin.manager.menu.link');
|
||||
foreach ($menu_links as $menu_link_id => $menu_link) {
|
||||
$menu_link_manager->removeDefinition("views_view:$menu_link_id");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -321,7 +321,7 @@ abstract class ExposedFormPluginBase extends PluginBase implements CacheablePlug
|
|||
}
|
||||
|
||||
// Set the form to allow redirect.
|
||||
if (empty($this->view->live_preview)) {
|
||||
if (empty($this->view->live_preview) && !\Drupal::request()->isXmlHttpRequest()) {
|
||||
$form_state->disableRedirect(FALSE);
|
||||
}
|
||||
else {
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
|
||||
namespace Drupal\views\Plugin\views\field;
|
||||
|
||||
use Drupal\Component\Utility\SafeMarkup;
|
||||
use Drupal\Component\Utility\Xss as CoreXss;
|
||||
use Drupal\Core\Entity\EntityInterface;
|
||||
use Drupal\Core\Entity\EntityManagerInterface;
|
||||
|
@ -671,7 +670,7 @@ class Field extends FieldPluginBase implements CacheablePluginInterface, MultiIt
|
|||
if (!empty($items)) {
|
||||
$items = $this->prepareItemsByDelta($items);
|
||||
if ($this->options['multi_type'] == 'separator' || !$this->options['group_rows']) {
|
||||
$separator = $this->options['multi_type'] == 'separator' ? SafeMarkup::checkAdminXss($this->options['separator']) : '';
|
||||
$separator = $this->options['multi_type'] == 'separator' ? CoreXss::filterAdmin($this->options['separator']) : '';
|
||||
$build = [
|
||||
'#type' => 'inline_template',
|
||||
'#template' => '{{ items | safe_join(separator) }}',
|
||||
|
|
|
@ -16,6 +16,7 @@ use Drupal\Component\Utility\Xss;
|
|||
use Drupal\Core\Cache\Cache;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\Render\Renderer;
|
||||
use Drupal\Core\Render\SafeString;
|
||||
use Drupal\Core\Url as CoreUrl;
|
||||
use Drupal\views\Plugin\views\HandlerBase;
|
||||
use Drupal\views\Plugin\views\display\DisplayPluginBase;
|
||||
|
@ -394,7 +395,7 @@ abstract class FieldPluginBase extends HandlerBase implements FieldHandlerInterf
|
|||
if ($relationship_id == 'none') {
|
||||
return $values->_entity;
|
||||
}
|
||||
else {
|
||||
elseif (isset($values->_relationship_entities[$relationship_id])) {
|
||||
return $values->_relationship_entities[$relationship_id];
|
||||
}
|
||||
}
|
||||
|
@ -875,10 +876,16 @@ abstract class FieldPluginBase extends HandlerBase implements FieldHandlerInterf
|
|||
$this->documentSelfTokens($options[t('Fields')]);
|
||||
|
||||
// Default text.
|
||||
$output = '<p>' . $this->t('You must add some additional fields to this display before using this field. These fields may be marked as <em>Exclude from display</em> if you prefer. Note that due to rendering order, you cannot use fields that come after this field; if you need a field not listed here, rearrange your fields.') . '</p>';
|
||||
|
||||
$output = [];
|
||||
$output[] = [
|
||||
'#markup' => '<p>' . $this->t('You must add some additional fields to this display before using this field. These fields may be marked as <em>Exclude from display</em> if you prefer. Note that due to rendering order, you cannot use fields that come after this field; if you need a field not listed here, rearrange your fields.') . '</p>',
|
||||
];
|
||||
// We have some options, so make a list.
|
||||
if (!empty($options)) {
|
||||
$output = '<p>' . $this->t("The following replacement tokens are available for this field. Note that due to rendering order, you cannot use fields that come after this field; if you need a field not listed here, rearrange your fields.") . '</p>';
|
||||
$output[] = [
|
||||
'#markup' => '<p>' . $this->t("The following replacement tokens are available for this field. Note that due to rendering order, you cannot use fields that come after this field; if you need a field not listed here, rearrange your fields.") . '</p>',
|
||||
];
|
||||
foreach (array_keys($options) as $type) {
|
||||
if (!empty($options[$type])) {
|
||||
$items = array();
|
||||
|
@ -890,7 +897,7 @@ abstract class FieldPluginBase extends HandlerBase implements FieldHandlerInterf
|
|||
'#items' => $items,
|
||||
'#list_type' => $type,
|
||||
);
|
||||
$output .= $this->getRenderer()->render($item_list);
|
||||
$output[] = $item_list;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -901,7 +908,7 @@ abstract class FieldPluginBase extends HandlerBase implements FieldHandlerInterf
|
|||
$form['alter']['help'] = array(
|
||||
'#type' => 'details',
|
||||
'#title' => $this->t('Replacement patterns'),
|
||||
'#value' => SafeMarkup::set($output),
|
||||
'#value' => $output,
|
||||
'#states' => array(
|
||||
'visible' => array(
|
||||
array(
|
||||
|
@ -1131,7 +1138,7 @@ abstract class FieldPluginBase extends HandlerBase implements FieldHandlerInterf
|
|||
else {
|
||||
$value = $this->render($values);
|
||||
if (is_array($value)) {
|
||||
$value = $this->getRenderer()->render($value);
|
||||
$value = (string) $this->getRenderer()->render($value);
|
||||
}
|
||||
$this->last_render = $value;
|
||||
$this->original_value = $value;
|
||||
|
@ -1144,7 +1151,7 @@ abstract class FieldPluginBase extends HandlerBase implements FieldHandlerInterf
|
|||
foreach ($raw_items as $count => $item) {
|
||||
$value = $this->render_item($count, $item);
|
||||
if (is_array($value)) {
|
||||
$value = $this->getRenderer()->render($value);
|
||||
$value = (string) $this->getRenderer()->render($value);
|
||||
}
|
||||
$this->last_render = $value;
|
||||
$this->original_value = $this->last_render;
|
||||
|
@ -1162,7 +1169,7 @@ abstract class FieldPluginBase extends HandlerBase implements FieldHandlerInterf
|
|||
}
|
||||
|
||||
if (is_array($value)) {
|
||||
$value = $this->getRenderer()->render($value);
|
||||
$value = (string) $this->getRenderer()->render($value);
|
||||
}
|
||||
// This happens here so that renderAsLink can get the unaltered value of
|
||||
// this field as a token rather than the altered value.
|
||||
|
@ -1284,9 +1291,7 @@ abstract class FieldPluginBase extends HandlerBase implements FieldHandlerInterf
|
|||
* Render this field as user-defined altered text.
|
||||
*/
|
||||
protected function renderAltered($alter, $tokens) {
|
||||
// Filter this right away as our substitutions are already sanitized.
|
||||
$template = Xss::filterAdmin($alter['text']);
|
||||
return $this->viewsTokenReplace($template, $tokens);
|
||||
return SafeString::create($this->viewsTokenReplace($alter['text'], $tokens));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -102,6 +102,7 @@ class NumericField extends FieldPluginBase {
|
|||
for ($i = 0; $i < $plurals; $i++) {
|
||||
$form['format_plural_values'][$i] = array(
|
||||
'#type' => 'textfield',
|
||||
// @todo Should use better labels https://www.drupal.org/node/2499639
|
||||
'#title' => ($i == 0 ? $this->t('Singular form') : $this->formatPlural($i, 'First plural form', '@count. plural form')),
|
||||
'#default_value' => isset($plural_array[$i]) ? $plural_array[$i] : '',
|
||||
'#description' => $this->t('Text to use for this variant, @count will be replaced with the value.'),
|
||||
|
|
|
@ -96,6 +96,7 @@ class Full extends SqlBase {
|
|||
'#element' => $this->options['id'],
|
||||
'#parameters' => $input,
|
||||
'#quantity' => $this->options['quantity'],
|
||||
'#route_name' => !empty($this->view->live_preview) ? '<current>' : '<none>',
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -103,6 +103,7 @@ class Mini extends SqlBase {
|
|||
'#tags' => $tags,
|
||||
'#element' => $this->options['id'],
|
||||
'#parameters' => $input,
|
||||
'#route_name' => !empty($this->view->live_preview) ? '<current>' : '<none>',
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -382,14 +382,9 @@ abstract class SqlBase extends PagerPluginBase implements CacheablePluginInterfa
|
|||
* {@inheritdoc}
|
||||
*/
|
||||
public function getCacheContexts() {
|
||||
$contexts = ['url.query_args.pagers:' . $this->options['id']];
|
||||
if ($this->options['expose']['items_per_page']) {
|
||||
$contexts[] = 'url.query_args:items_per_page';
|
||||
}
|
||||
if ($this->options['expose']['offset']) {
|
||||
$contexts[] = 'url.query_args:offset';
|
||||
}
|
||||
return $contexts;
|
||||
// The rendered link needs to play well with any other query parameter used
|
||||
// on the page, like other pagers and exposed filter.
|
||||
return ['url.query_args'];
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -237,12 +237,15 @@ abstract class QueryPluginBase extends PluginBase implements CacheablePluginInte
|
|||
* An appropriate query expression pointing to the date field.
|
||||
* @param string $format
|
||||
* A format string for the result, like 'Y-m-d H:i:s'.
|
||||
* @param boolean $string_date
|
||||
* For certain databases, date format functions vary depending on string or
|
||||
* numeric storage.
|
||||
*
|
||||
* @return string
|
||||
* A string representing the field formatted as a date in the format
|
||||
* specified by $format.
|
||||
*/
|
||||
public function getDateFormat($field, $format) {
|
||||
public function getDateFormat($field, $format, $string_date = FALSE) {
|
||||
return $field;
|
||||
}
|
||||
|
||||
|
|
|
@ -1454,7 +1454,7 @@ class Sql extends QueryPluginBase {
|
|||
drupal_set_message($e->getMessage(), 'error');
|
||||
}
|
||||
else {
|
||||
throw new DatabaseExceptionWrapper(format_string('Exception in @label[@view_name]: @message', array('@label' => $view->storage->label(), '@view_name' => $view->storage->id(), '@message' => $e->getMessage())));
|
||||
throw new DatabaseExceptionWrapper("Exception in {$view->storage->label()}[$view->storage->id()]: {$e->getMessage()}");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1748,9 +1748,9 @@ class Sql extends QueryPluginBase {
|
|||
}
|
||||
|
||||
/**
|
||||
* Overrides \Drupal\views\Plugin\views\query\QueryPluginBase::getDateFormat().
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getDateFormat($field, $format) {
|
||||
public function getDateFormat($field, $format, $string_date = FALSE) {
|
||||
$db_type = Database::getConnection()->databaseType();
|
||||
switch ($db_type) {
|
||||
case 'mysql':
|
||||
|
@ -1797,7 +1797,12 @@ class Sql extends QueryPluginBase {
|
|||
'A' => 'AM',
|
||||
);
|
||||
$format = strtr($format, $replace);
|
||||
return "TO_CHAR($field, '$format')";
|
||||
if (!$string_date) {
|
||||
return "TO_CHAR($field, '$format')";
|
||||
}
|
||||
// In order to allow for partials (eg, only the year), transform to a
|
||||
// date, back to a string again.
|
||||
return "TO_CHAR(TO_TIMESTAMP($field, 'YYYY-MM-DD HH24:MI:SS'), '$format')";
|
||||
case 'sqlite':
|
||||
$replace = array(
|
||||
'Y' => '%Y',
|
||||
|
@ -1827,15 +1832,19 @@ class Sql extends QueryPluginBase {
|
|||
'A' => '',
|
||||
);
|
||||
$format = strtr($format, $replace);
|
||||
|
||||
// Don't use the 'unixepoch' flag for string date comparisons.
|
||||
$unixepoch = $string_date ? '' : ", 'unixepoch'";
|
||||
|
||||
// SQLite does not have a ISO week substitution string, so it needs
|
||||
// special handling.
|
||||
// @see http://en.wikipedia.org/wiki/ISO_week_date#Calculation
|
||||
// @see http://stackoverflow.com/a/15511864/1499564
|
||||
if ($format === '%W') {
|
||||
$expression = "((strftime('%j', date(strftime('%Y-%m-%d', $field, 'unixepoch'), '-3 days', 'weekday 4')) - 1) / 7 + 1)";
|
||||
$expression = "((strftime('%j', date(strftime('%Y-%m-%d', $field" . $unixepoch . "), '-3 days', 'weekday 4')) - 1) / 7 + 1)";
|
||||
}
|
||||
else {
|
||||
$expression = "strftime('$format', $field, 'unixepoch')";
|
||||
$expression = "strftime('$format', $field" . $unixepoch . ")";
|
||||
}
|
||||
// The expression yields a string, but the comparison value is an
|
||||
// integer in case the comparison value is a float, integer, or numeric.
|
||||
|
|
|
@ -217,7 +217,7 @@ class OpmlFields extends RowPluginBase {
|
|||
if (empty($this->view->style_plugin) || !is_object($this->view->style_plugin) || empty($field_id)) {
|
||||
return '';
|
||||
}
|
||||
return $this->view->style_plugin->getField($index, $field_id);
|
||||
return (string) $this->view->style_plugin->getField($index, $field_id);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -8,9 +8,10 @@
|
|||
namespace Drupal\views\Plugin\views\style;
|
||||
|
||||
use Drupal\Component\Utility\Html;
|
||||
use Drupal\Component\Utility\SafeMarkup;
|
||||
use Drupal\Component\Utility\Xss;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\Render\Element;
|
||||
use Drupal\Core\Render\SafeString;
|
||||
use Drupal\views\Plugin\views\display\DisplayPluginBase;
|
||||
use Drupal\views\Plugin\views\PluginBase;
|
||||
use Drupal\views\Plugin\views\wizard\WizardInterface;
|
||||
|
@ -239,6 +240,11 @@ abstract class StylePluginBase extends PluginBase {
|
|||
|
||||
$value = $this->viewsTokenReplace($value, $tokens);
|
||||
}
|
||||
else {
|
||||
// ::viewsTokenReplace() will run Xss::filterAdmin on the
|
||||
// resulting string. We do the same here for consistency.
|
||||
$value = Xss::filterAdmin($value);
|
||||
}
|
||||
return $value;
|
||||
}
|
||||
|
||||
|
@ -700,8 +706,9 @@ abstract class StylePluginBase extends PluginBase {
|
|||
$placeholders = array_keys($post_render_tokens);
|
||||
$values = array_values($post_render_tokens);
|
||||
foreach ($this->rendered_fields[$index] as &$rendered_field) {
|
||||
$rendered_field = str_replace($placeholders, $values, $rendered_field);
|
||||
SafeMarkup::set($rendered_field);
|
||||
// Placeholders and rendered fields have been processed by the
|
||||
// render system and are therefore safe.
|
||||
$rendered_field = SafeString::create(str_replace($placeholders, $values, $rendered_field));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -738,7 +745,7 @@ abstract class StylePluginBase extends PluginBase {
|
|||
* @param string $field
|
||||
* The ID of the field.
|
||||
*
|
||||
* @return string|null
|
||||
* @return \Drupal\Core\Render\SafeString|null
|
||||
* The output of the field, or NULL if it was empty.
|
||||
*/
|
||||
public function getField($index, $field) {
|
||||
|
|
|
@ -444,8 +444,9 @@ class Table extends StylePluginBase implements CacheablePluginInterface {
|
|||
|
||||
foreach ($this->options['info'] as $field_id => $info) {
|
||||
if (!empty($info['sortable'])) {
|
||||
$contexts[] = 'url.query_args:order';
|
||||
$contexts[] = 'url.query_args:sort';
|
||||
// The rendered link needs to play well with any other query parameter
|
||||
// used on the page, like pager and exposed filter.
|
||||
$contexts[] = 'url.query_args';
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,54 +7,13 @@
|
|||
|
||||
namespace Drupal\views\Routing;
|
||||
|
||||
use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
|
||||
use Drupal\Core\Entity\EntityStorageInterface;
|
||||
use Drupal\Core\Routing\RouteMatchInterface;
|
||||
use Drupal\views\Plugin\views\display\Page;
|
||||
use Drupal\views\ViewExecutableFactory;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Defines a page controller to execute and render a view.
|
||||
*/
|
||||
class ViewPageController implements ContainerInjectionInterface {
|
||||
|
||||
/**
|
||||
* The entity storage.
|
||||
*
|
||||
* @var \Drupal\Core\Entity\EntityStorageInterface
|
||||
*/
|
||||
protected $storage;
|
||||
|
||||
/**
|
||||
* The view executable factory.
|
||||
*
|
||||
* @var \Drupal\views\ViewExecutableFactory
|
||||
*/
|
||||
protected $executableFactory;
|
||||
|
||||
/**
|
||||
* Constructs a ViewPageController object.
|
||||
*
|
||||
* @param \Drupal\Core\Entity\EntityStorageInterface $storage
|
||||
* The entity storage.
|
||||
* @param \Drupal\views\ViewExecutableFactory $executable_factory
|
||||
* The view executable factory
|
||||
*/
|
||||
public function __construct(EntityStorageInterface $storage, ViewExecutableFactory $executable_factory) {
|
||||
$this->storage = $storage;
|
||||
$this->executableFactory = $executable_factory;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container) {
|
||||
return new static(
|
||||
$container->get('entity.manager')->getStorage('view'),
|
||||
$container->get('views.executable')
|
||||
);
|
||||
}
|
||||
class ViewPageController {
|
||||
|
||||
/**
|
||||
* Handler a response for a given view and display.
|
||||
|
|
|
@ -71,17 +71,29 @@ class GlossaryTest extends ViewTestBase {
|
|||
$url = Url::fromRoute('view.glossary.page_1');
|
||||
|
||||
// Verify cache tags.
|
||||
$this->assertPageCacheContextsAndTags($url, ['languages:' . LanguageInterface::TYPE_CONTENT, 'languages:' . LanguageInterface::TYPE_INTERFACE, 'theme', 'url', 'user.node_grants:view', 'user.permissions'], [
|
||||
'config:views.view.glossary',
|
||||
'node:' . $nodes_by_char['a'][0]->id(), 'node:' . $nodes_by_char['a'][1]->id(), 'node:' . $nodes_by_char['a'][2]->id(),
|
||||
'node_list',
|
||||
'user:0',
|
||||
'user_list',
|
||||
'rendered',
|
||||
// FinishResponseSubscriber adds this cache tag to responses that have the
|
||||
// 'user.permissions' cache context for anonymous users.
|
||||
'config:user.role.anonymous',
|
||||
]);
|
||||
$this->assertPageCacheContextsAndTags(
|
||||
$url,
|
||||
[
|
||||
'languages:' . LanguageInterface::TYPE_CONTENT,
|
||||
'languages:' . LanguageInterface::TYPE_INTERFACE,
|
||||
'theme',
|
||||
'url',
|
||||
'user.node_grants:view',
|
||||
'user.permissions',
|
||||
'route',
|
||||
],
|
||||
[
|
||||
'config:views.view.glossary',
|
||||
'node:' . $nodes_by_char['a'][0]->id(), 'node:' . $nodes_by_char['a'][1]->id(), 'node:' . $nodes_by_char['a'][2]->id(),
|
||||
'node_list',
|
||||
'user:0',
|
||||
'user_list',
|
||||
'rendered',
|
||||
// FinishResponseSubscriber adds this cache tag to responses that have the
|
||||
// 'user.permissions' cache context for anonymous users.
|
||||
'config:user.role.anonymous',
|
||||
]
|
||||
);
|
||||
|
||||
// Check the actual page response.
|
||||
$this->drupalGet($url);
|
||||
|
|
|
@ -51,11 +51,11 @@ class FieldCounterTest extends ViewUnitTestBase {
|
|||
$view->preview();
|
||||
|
||||
$counter = $view->style_plugin->getField(0, 'counter');
|
||||
$this->assertEqual($counter, 1, format_string('Make sure the expected number (@expected) patches with the rendered number (@counter)', array('@expected' => 1, '@counter' => $counter)));
|
||||
$this->assertEqual($counter, '1', format_string('Make sure the expected number (@expected) patches with the rendered number (@counter)', array('@expected' => 1, '@counter' => $counter)));
|
||||
$counter = $view->style_plugin->getField(1, 'counter');
|
||||
$this->assertEqual($counter, 2, format_string('Make sure the expected number (@expected) patches with the rendered number (@counter)', array('@expected' => 2, '@counter' => $counter)));
|
||||
$this->assertEqual($counter, '2', format_string('Make sure the expected number (@expected) patches with the rendered number (@counter)', array('@expected' => 2, '@counter' => $counter)));
|
||||
$counter = $view->style_plugin->getField(2, 'counter');
|
||||
$this->assertEqual($counter, 3, format_string('Make sure the expected number (@expected) patches with the rendered number (@counter)', array('@expected' => 3, '@counter' => $counter)));
|
||||
$this->assertEqual($counter, '3', format_string('Make sure the expected number (@expected) patches with the rendered number (@counter)', array('@expected' => 3, '@counter' => $counter)));
|
||||
$view->destroy();
|
||||
$view->storage->invalidateCaches();
|
||||
|
||||
|
@ -80,13 +80,13 @@ class FieldCounterTest extends ViewUnitTestBase {
|
|||
|
||||
$counter = $view->style_plugin->getField(0, 'counter');
|
||||
$expected_number = 0 + $rand_start;
|
||||
$this->assertEqual($counter, $expected_number, format_string('Make sure the expected number (@expected) patches with the rendered number (@counter)', array('@expected' => $expected_number, '@counter' => $counter)));
|
||||
$this->assertEqual($counter, (string) $expected_number, format_string('Make sure the expected number (@expected) patches with the rendered number (@counter)', array('@expected' => $expected_number, '@counter' => $counter)));
|
||||
$counter = $view->style_plugin->getField(1, 'counter');
|
||||
$expected_number = 1 + $rand_start;
|
||||
$this->assertEqual($counter, $expected_number, format_string('Make sure the expected number (@expected) patches with the rendered number (@counter)', array('@expected' => $expected_number, '@counter' => $counter)));
|
||||
$this->assertEqual($counter, (string) $expected_number, format_string('Make sure the expected number (@expected) patches with the rendered number (@counter)', array('@expected' => $expected_number, '@counter' => $counter)));
|
||||
$counter = $view->style_plugin->getField(2, 'counter');
|
||||
$expected_number = 2 + $rand_start;
|
||||
$this->assertEqual($counter, $expected_number, format_string('Make sure the expected number (@expected) patches with the rendered number (@counter)', array('@expected' => $expected_number, '@counter' => $counter)));
|
||||
$this->assertEqual($counter, (string) $expected_number, format_string('Make sure the expected number (@expected) patches with the rendered number (@counter)', array('@expected' => $expected_number, '@counter' => $counter)));
|
||||
}
|
||||
|
||||
// @TODO: Write tests for pager.
|
||||
|
|
|
@ -251,18 +251,18 @@ class FieldFieldTest extends ViewUnitTestBase {
|
|||
$executable = Views::getView('test_field_field_test');
|
||||
$executable->execute();
|
||||
|
||||
$this->assertEqual(1, $executable->getStyle()->getField(0, 'id'));
|
||||
$this->assertEqual(3, $executable->getStyle()->getField(0, 'field_test'));
|
||||
$this->assertEqual(2, $executable->getStyle()->getField(1, 'id'));
|
||||
$this->assertEqual('1', $executable->getStyle()->getField(0, 'id'));
|
||||
$this->assertEqual('3', $executable->getStyle()->getField(0, 'field_test'));
|
||||
$this->assertEqual('2', $executable->getStyle()->getField(1, 'id'));
|
||||
// @todo Switch this assertion to assertIdentical('', ...) when
|
||||
// https://www.drupal.org/node/2488006 gets fixed.
|
||||
$this->assertEqual(0, $executable->getStyle()->getField(1, 'field_test'));
|
||||
$this->assertEqual(3, $executable->getStyle()->getField(2, 'id'));
|
||||
$this->assertEqual(8, $executable->getStyle()->getField(2, 'field_test'));
|
||||
$this->assertEqual(4, $executable->getStyle()->getField(3, 'id'));
|
||||
$this->assertEqual(5, $executable->getStyle()->getField(3, 'field_test'));
|
||||
$this->assertEqual(5, $executable->getStyle()->getField(4, 'id'));
|
||||
$this->assertEqual(6, $executable->getStyle()->getField(4, 'field_test'));
|
||||
$this->assertEqual('0', $executable->getStyle()->getField(1, 'field_test'));
|
||||
$this->assertEqual('3', $executable->getStyle()->getField(2, 'id'));
|
||||
$this->assertEqual('8', $executable->getStyle()->getField(2, 'field_test'));
|
||||
$this->assertEqual('4', $executable->getStyle()->getField(3, 'id'));
|
||||
$this->assertEqual('5', $executable->getStyle()->getField(3, 'field_test'));
|
||||
$this->assertEqual('5', $executable->getStyle()->getField(4, 'id'));
|
||||
$this->assertEqual('6', $executable->getStyle()->getField(4, 'field_test'));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -326,10 +326,10 @@ class FieldFieldTest extends ViewUnitTestBase {
|
|||
$executable->execute();
|
||||
|
||||
for ($i = 0; $i < 5; $i++) {
|
||||
$this->assertEqual($i + 1, $executable->getStyle()->getField($i, 'id'));
|
||||
$this->assertEqual((string) ($i + 1), $executable->getStyle()->getField($i, 'id'));
|
||||
$this->assertEqual('test ' . $i, $executable->getStyle()->getField($i, 'name'));
|
||||
$entity = EntityTest::load($i + 1);
|
||||
$this->assertEqual('<a href="' . $entity->url() . '" hreflang="' . $entity->language()->getId() . '">test ' . $i . '</a>', $executable->getStyle()->getField($i, 'name_alias'));
|
||||
$this->assertEqual('<a href="' . $entity->url() . '" hreflang="' . $entity->language()->getId() . '">test ' . $i . '</a>', (string) $executable->getStyle()->getField($i, 'name_alias'));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -426,24 +426,24 @@ class FieldFieldTest extends ViewUnitTestBase {
|
|||
$executable = Views::getView('test_field_field_revision_test');
|
||||
$executable->execute();
|
||||
|
||||
$this->assertEqual(1, $executable->getStyle()->getField(0, 'id'));
|
||||
$this->assertEqual(1, $executable->getStyle()->getField(0, 'revision_id'));
|
||||
$this->assertEqual(1, $executable->getStyle()->getField(0, 'field_test'));
|
||||
$this->assertEqual('1', $executable->getStyle()->getField(0, 'id'));
|
||||
$this->assertEqual('1', $executable->getStyle()->getField(0, 'revision_id'));
|
||||
$this->assertEqual('1', $executable->getStyle()->getField(0, 'field_test'));
|
||||
$this->assertEqual('base value', $executable->getStyle()->getField(0, 'name'));
|
||||
|
||||
$this->assertEqual(1, $executable->getStyle()->getField(1, 'id'));
|
||||
$this->assertEqual(2, $executable->getStyle()->getField(1, 'revision_id'));
|
||||
$this->assertEqual(2, $executable->getStyle()->getField(1, 'field_test'));
|
||||
$this->assertEqual('1', $executable->getStyle()->getField(1, 'id'));
|
||||
$this->assertEqual('2', $executable->getStyle()->getField(1, 'revision_id'));
|
||||
$this->assertEqual('2', $executable->getStyle()->getField(1, 'field_test'));
|
||||
$this->assertEqual('revision value1', $executable->getStyle()->getField(1, 'name'));
|
||||
|
||||
$this->assertEqual(1, $executable->getStyle()->getField(2, 'id'));
|
||||
$this->assertEqual(3, $executable->getStyle()->getField(2, 'revision_id'));
|
||||
$this->assertEqual(3, $executable->getStyle()->getField(2, 'field_test'));
|
||||
$this->assertEqual('1', $executable->getStyle()->getField(2, 'id'));
|
||||
$this->assertEqual('3', $executable->getStyle()->getField(2, 'revision_id'));
|
||||
$this->assertEqual('3', $executable->getStyle()->getField(2, 'field_test'));
|
||||
$this->assertEqual('revision value2', $executable->getStyle()->getField(2, 'name'));
|
||||
|
||||
$this->assertEqual(2, $executable->getStyle()->getField(3, 'id'));
|
||||
$this->assertEqual(4, $executable->getStyle()->getField(3, 'revision_id'));
|
||||
$this->assertEqual(4, $executable->getStyle()->getField(3, 'field_test'));
|
||||
$this->assertEqual('2', $executable->getStyle()->getField(3, 'id'));
|
||||
$this->assertEqual('4', $executable->getStyle()->getField(3, 'revision_id'));
|
||||
$this->assertEqual('4', $executable->getStyle()->getField(3, 'field_test'));
|
||||
$this->assertEqual('next entity value', $executable->getStyle()->getField(3, 'name'));
|
||||
}
|
||||
|
||||
|
@ -484,29 +484,29 @@ class FieldFieldTest extends ViewUnitTestBase {
|
|||
$executable = Views::getView('test_field_field_revision_complex_test');
|
||||
$executable->execute();
|
||||
|
||||
$this->assertEqual(1, $executable->getStyle()->getField(0, 'id'));
|
||||
$this->assertEqual(1, $executable->getStyle()->getField(0, 'revision_id'));
|
||||
$this->assertEqual('1', $executable->getStyle()->getField(0, 'id'));
|
||||
$this->assertEqual('1', $executable->getStyle()->getField(0, 'revision_id'));
|
||||
$this->assertEqual($this->testUsers[0]->getTimeZone(), $executable->getStyle()->getField(0, 'timezone'));
|
||||
$this->assertEqual('1, 3, 7', $executable->getStyle()->getField(0, 'field_test_multiple'));
|
||||
$this->assertEqual('1', $executable->getStyle()->getField(0, 'field_test_multiple_1'));
|
||||
$this->assertEqual('3, 7', $executable->getStyle()->getField(0, 'field_test_multiple_2'));
|
||||
|
||||
$this->assertEqual(1, $executable->getStyle()->getField(1, 'id'));
|
||||
$this->assertEqual(2, $executable->getStyle()->getField(1, 'revision_id'));
|
||||
$this->assertEqual('1', $executable->getStyle()->getField(1, 'id'));
|
||||
$this->assertEqual('2', $executable->getStyle()->getField(1, 'revision_id'));
|
||||
$this->assertEqual($this->testUsers[1]->getTimeZone(), $executable->getStyle()->getField(1, 'timezone'));
|
||||
$this->assertEqual('0, 3, 5', $executable->getStyle()->getField(1, 'field_test_multiple'));
|
||||
$this->assertEqual('0', $executable->getStyle()->getField(1, 'field_test_multiple_1'));
|
||||
$this->assertEqual('3, 5', $executable->getStyle()->getField(1, 'field_test_multiple_2'));
|
||||
|
||||
$this->assertEqual(1, $executable->getStyle()->getField(2, 'id'));
|
||||
$this->assertEqual(3, $executable->getStyle()->getField(2, 'revision_id'));
|
||||
$this->assertEqual('1', $executable->getStyle()->getField(2, 'id'));
|
||||
$this->assertEqual('3', $executable->getStyle()->getField(2, 'revision_id'));
|
||||
$this->assertEqual($this->testUsers[2]->getTimeZone(), $executable->getStyle()->getField(2, 'timezone'));
|
||||
$this->assertEqual('9, 9, 9', $executable->getStyle()->getField(2, 'field_test_multiple'));
|
||||
$this->assertEqual('9', $executable->getStyle()->getField(2, 'field_test_multiple_1'));
|
||||
$this->assertEqual('9, 9', $executable->getStyle()->getField(2, 'field_test_multiple_2'));
|
||||
|
||||
$this->assertEqual(2, $executable->getStyle()->getField(3, 'id'));
|
||||
$this->assertEqual(4, $executable->getStyle()->getField(3, 'revision_id'));
|
||||
$this->assertEqual('2', $executable->getStyle()->getField(3, 'id'));
|
||||
$this->assertEqual('4', $executable->getStyle()->getField(3, 'revision_id'));
|
||||
$this->assertEqual($this->testUsers[3]->getTimeZone(), $executable->getStyle()->getField(3, 'timezone'));
|
||||
$this->assertEqual('2, 9, 9', $executable->getStyle()->getField(3, 'field_test_multiple'));
|
||||
$this->assertEqual('2', $executable->getStyle()->getField(3, 'field_test_multiple_1'));
|
||||
|
@ -531,9 +531,7 @@ class FieldFieldTest extends ViewUnitTestBase {
|
|||
$executable = Views::getView('test_field_field_test');
|
||||
$executable->execute();
|
||||
|
||||
// @todo Switch this assertion to assertIdentical('', ...) when
|
||||
// https://www.drupal.org/node/2488006 gets fixed.
|
||||
$this->assertEqual(0, $executable->getStyle()->getField(1, 'field_test'));
|
||||
$this->assertEqual('', $executable->getStyle()->getField(1, 'field_test'));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
namespace Drupal\views\Tests\Handler;
|
||||
|
||||
use Drupal\Core\Field\FieldStorageDefinitionInterface;
|
||||
use Drupal\Core\Render\RenderContext;
|
||||
use Drupal\views\Views;
|
||||
|
||||
/**
|
||||
|
@ -67,6 +68,9 @@ class FieldGroupRowsTest extends HandlerTestBase {
|
|||
* Testing the "Grouped rows" functionality.
|
||||
*/
|
||||
public function testGroupRows() {
|
||||
/** @var \Drupal\Core\Render\RendererInterface $renderer */
|
||||
$renderer = \Drupal::service('renderer');
|
||||
|
||||
$edit = array(
|
||||
'title' => $this->randomMachineName(),
|
||||
$this->fieldName => array('a', 'b', 'c'),
|
||||
|
@ -77,7 +81,10 @@ class FieldGroupRowsTest extends HandlerTestBase {
|
|||
|
||||
// Test grouped rows.
|
||||
$this->executeView($view);
|
||||
$this->assertEqual($view->field[$this->fieldName]->advancedRender($view->result[0]), 'a, b, c');
|
||||
$output = $renderer->executeInRenderContext(new RenderContext(), function () use ($view) {
|
||||
return $view->field[$this->fieldName]->advancedRender($view->result[0]);
|
||||
});
|
||||
$this->assertEqual($output, 'a, b, c');
|
||||
|
||||
// Change the group_rows checkbox to false.
|
||||
$view = Views::getView('test_group_rows');
|
||||
|
@ -88,11 +95,20 @@ class FieldGroupRowsTest extends HandlerTestBase {
|
|||
$view->render();
|
||||
|
||||
$view->row_index = 0;
|
||||
$this->assertEqual($view->field[$this->fieldName]->advancedRender($view->result[0]), 'a');
|
||||
$output = $renderer->executeInRenderContext(new RenderContext(), function () use ($view) {
|
||||
return $view->field[$this->fieldName]->advancedRender($view->result[0]);
|
||||
});
|
||||
$this->assertEqual($output, 'a');
|
||||
$view->row_index = 1;
|
||||
$this->assertEqual($view->field[$this->fieldName]->advancedRender($view->result[1]), 'b');
|
||||
$output = $renderer->executeInRenderContext(new RenderContext(), function () use ($view) {
|
||||
return $view->field[$this->fieldName]->advancedRender($view->result[1]);
|
||||
});
|
||||
$this->assertEqual($output, 'b');
|
||||
$view->row_index = 2;
|
||||
$this->assertEqual($view->field[$this->fieldName]->advancedRender($view->result[2]), 'c');
|
||||
$output = $renderer->executeInRenderContext(new RenderContext(), function () use ($view) {
|
||||
return $view->field[$this->fieldName]->advancedRender($view->result[2]);
|
||||
});
|
||||
$this->assertEqual($output, 'c');
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
namespace Drupal\views\Tests\Handler;
|
||||
|
||||
use Drupal\Core\Render\RenderContext;
|
||||
use Drupal\views\Tests\ViewUnitTestBase;
|
||||
use Drupal\views\Plugin\views\field\FieldPluginBase;
|
||||
use Drupal\views\Views;
|
||||
|
@ -52,12 +53,18 @@ class FieldUnitTest extends ViewUnitTestBase {
|
|||
* Tests that the render function is called.
|
||||
*/
|
||||
public function testRender() {
|
||||
/** @var \Drupal\Core\Render\RendererInterface $renderer */
|
||||
$renderer = \Drupal::service('renderer');
|
||||
|
||||
$view = Views::getView('test_field_tokens');
|
||||
$this->executeView($view);
|
||||
|
||||
$random_text = $this->randomMachineName();
|
||||
$view->field['job']->setTestValue($random_text);
|
||||
$this->assertEqual($view->field['job']->theme($view->result[0]), $random_text, 'Make sure the render method rendered the manual set value.');
|
||||
$output = $renderer->executeInRenderContext(new RenderContext(), function () use ($view) {
|
||||
return $view->field['job']->theme($view->result[0]);
|
||||
});
|
||||
$this->assertEqual($output, $random_text, 'Make sure the render method rendered the manual set value.');
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -141,6 +148,9 @@ class FieldUnitTest extends ViewUnitTestBase {
|
|||
* Tests general rewriting of the output.
|
||||
*/
|
||||
public function testRewrite() {
|
||||
/** @var \Drupal\Core\Render\RendererInterface $renderer */
|
||||
$renderer = \Drupal::service('renderer');
|
||||
|
||||
$view = Views::getView('test_view');
|
||||
$view->initHandlers();
|
||||
$this->executeView($view);
|
||||
|
@ -149,11 +159,15 @@ class FieldUnitTest extends ViewUnitTestBase {
|
|||
|
||||
// Don't check the rewrite checkbox, so the text shouldn't appear.
|
||||
$id_field->options['alter']['text'] = $random_text = $this->randomMachineName();
|
||||
$output = $id_field->theme($row);
|
||||
$output = $renderer->executeInRenderContext(new RenderContext(), function () use ($id_field, $row) {
|
||||
return $id_field->theme($row);
|
||||
});
|
||||
$this->assertNotSubString($output, $random_text);
|
||||
|
||||
$id_field->options['alter']['alter_text'] = TRUE;
|
||||
$output = $id_field->theme($row);
|
||||
$output = $renderer->executeInRenderContext(new RenderContext(), function () use ($id_field, $row) {
|
||||
return $id_field->theme($row);
|
||||
});
|
||||
$this->assertSubString($output, $random_text);
|
||||
}
|
||||
|
||||
|
@ -161,6 +175,9 @@ class FieldUnitTest extends ViewUnitTestBase {
|
|||
* Tests the field tokens, row level and field level.
|
||||
*/
|
||||
public function testFieldTokens() {
|
||||
/** @var \Drupal\Core\Render\RendererInterface $renderer */
|
||||
$renderer = \Drupal::service('renderer');
|
||||
|
||||
$view = Views::getView('test_field_tokens');
|
||||
$this->executeView($view);
|
||||
$name_field_0 = $view->field['name'];
|
||||
|
@ -175,26 +192,32 @@ class FieldUnitTest extends ViewUnitTestBase {
|
|||
$name_field_1->options['alter']['text'] = '{{ name_1 }} {{ name }}';
|
||||
|
||||
$name_field_2->options['alter']['alter_text'] = TRUE;
|
||||
$name_field_2->options['alter']['text'] = '{{ name_2 }} {{ name_1 }}';
|
||||
$name_field_2->options['alter']['text'] = '{% if name_2|length > 3 %}{{ name_2 }} {{ name_1 }}{% endif %}';
|
||||
|
||||
foreach ($view->result as $row) {
|
||||
$expected_output_0 = $row->views_test_data_name;
|
||||
$expected_output_1 = "$row->views_test_data_name $row->views_test_data_name";
|
||||
$expected_output_2 = "$row->views_test_data_name $row->views_test_data_name $row->views_test_data_name";
|
||||
|
||||
$output = $name_field_0->advancedRender($row);
|
||||
$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,
|
||||
]));
|
||||
|
||||
$output = $name_field_1->advancedRender($row);
|
||||
$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,
|
||||
]));
|
||||
|
||||
$output = $name_field_2->advancedRender($row);
|
||||
$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,
|
||||
|
@ -207,7 +230,9 @@ class FieldUnitTest extends ViewUnitTestBase {
|
|||
|
||||
$random_text = $this->randomMachineName();
|
||||
$job_field->setTestValue($random_text);
|
||||
$output = $job_field->advancedRender($row);
|
||||
$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,
|
||||
|
@ -219,12 +244,46 @@ class FieldUnitTest extends ViewUnitTestBase {
|
|||
$job_field->options['alter']['text'] = $old_token;
|
||||
$random_text = $this->randomMachineName();
|
||||
$job_field->setTestValue($random_text);
|
||||
$output = $job_field->advancedRender($row);
|
||||
$this->assertSubString($output, $old_token, format_string('Make sure the old token style (!token => !value) is not changed in the output (!output)', [
|
||||
$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'],
|
||||
]));
|
||||
|
||||
// Verify HTML tags are allowed in rewrite templates while token
|
||||
// replacements are escaped.
|
||||
$job_field->options['alter']['text'] = '<h1>{{ job }}</h1>';
|
||||
$random_text = $this->randomMachineName();
|
||||
$job_field->setTestValue('<span>' . $random_text . '</span>');
|
||||
$output = $renderer->executeInRenderContext(new RenderContext(), function () use ($job_field, $row) {
|
||||
return $job_field->advancedRender($row);
|
||||
});
|
||||
$this->assertEqual($output, '<h1><span>' . $random_text . '</span></h1>', 'Valid tags are allowed in rewrite templates and token replacements.');
|
||||
|
||||
// Verify <script> tags are correctly removed from rewritten text.
|
||||
$rewrite_template = '<script>alert("malicious");</script>';
|
||||
$job_field->options['alter']['text'] = $rewrite_template;
|
||||
$random_text = $this->randomMachineName();
|
||||
$job_field->setTestValue($random_text);
|
||||
$output = $renderer->executeInRenderContext(new RenderContext(), function () use ($job_field, $row) {
|
||||
return $job_field->advancedRender($row);
|
||||
});
|
||||
$this->assertNotSubString($output, '<script>', 'Ensure a script tag in the rewrite template is removed.');
|
||||
|
||||
$rewrite_template = '<script>{{ job }}</script>';
|
||||
$job_field->options['alter']['text'] = $rewrite_template;
|
||||
$random_text = $this->randomMachineName();
|
||||
$job_field->setTestValue($random_text);
|
||||
$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,
|
||||
]));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -268,6 +327,9 @@ class FieldUnitTest extends ViewUnitTestBase {
|
|||
* This tests alters the result to get easier and less coupled results.
|
||||
*/
|
||||
function _testHideIfEmpty() {
|
||||
/** @var \Drupal\Core\Render\RendererInterface $renderer */
|
||||
$renderer = \Drupal::service('renderer');
|
||||
|
||||
$view = Views::getView('test_view');
|
||||
$view->initDisplay();
|
||||
$this->executeView($view);
|
||||
|
@ -284,22 +346,30 @@ class FieldUnitTest extends ViewUnitTestBase {
|
|||
|
||||
// Test a valid string.
|
||||
$view->result[0]->{$column_map_reversed['name']} = $random_name;
|
||||
$render = $view->field['name']->advancedRender($view->result[0]);
|
||||
$render = $renderer->executeInRenderContext(new RenderContext(), function () use ($view) {
|
||||
return $view->field['name']->advancedRender($view->result[0]);
|
||||
});
|
||||
$this->assertIdentical($render, $random_name, 'By default, a string should not be treated as empty.');
|
||||
|
||||
// Test an empty string.
|
||||
$view->result[0]->{$column_map_reversed['name']} = "";
|
||||
$render = $view->field['name']->advancedRender($view->result[0]);
|
||||
$render = $renderer->executeInRenderContext(new RenderContext(), function () use ($view) {
|
||||
return $view->field['name']->advancedRender($view->result[0]);
|
||||
});
|
||||
$this->assertIdentical($render, "", 'By default, "" should not be treated as empty.');
|
||||
|
||||
// Test zero as an integer.
|
||||
$view->result[0]->{$column_map_reversed['name']} = 0;
|
||||
$render = $view->field['name']->advancedRender($view->result[0]);
|
||||
$render = $renderer->executeInRenderContext(new RenderContext(), function () use ($view) {
|
||||
return $view->field['name']->advancedRender($view->result[0]);
|
||||
});
|
||||
$this->assertIdentical($render, '0', 'By default, 0 should not be treated as empty.');
|
||||
|
||||
// Test zero as a string.
|
||||
$view->result[0]->{$column_map_reversed['name']} = "0";
|
||||
$render = $view->field['name']->advancedRender($view->result[0]);
|
||||
$render = $renderer->executeInRenderContext(new RenderContext(), function () use ($view) {
|
||||
return $view->field['name']->advancedRender($view->result[0]);
|
||||
});
|
||||
$this->assertIdentical($render, "0", 'By default, "0" should not be treated as empty.');
|
||||
|
||||
// Test when results are not rewritten and non-zero empty values are hidden.
|
||||
|
@ -309,22 +379,30 @@ class FieldUnitTest extends ViewUnitTestBase {
|
|||
|
||||
// Test a valid string.
|
||||
$view->result[0]->{$column_map_reversed['name']} = $random_name;
|
||||
$render = $view->field['name']->advancedRender($view->result[0]);
|
||||
$render = $renderer->executeInRenderContext(new RenderContext(), function () use ($view) {
|
||||
return $view->field['name']->advancedRender($view->result[0]);
|
||||
});
|
||||
$this->assertIdentical($render, $random_name, 'If hide_empty is checked, a string should not be treated as empty.');
|
||||
|
||||
// Test an empty string.
|
||||
$view->result[0]->{$column_map_reversed['name']} = "";
|
||||
$render = $view->field['name']->advancedRender($view->result[0]);
|
||||
$render = $renderer->executeInRenderContext(new RenderContext(), function () use ($view) {
|
||||
return $view->field['name']->advancedRender($view->result[0]);
|
||||
});
|
||||
$this->assertIdentical($render, "", 'If hide_empty is checked, "" should be treated as empty.');
|
||||
|
||||
// Test zero as an integer.
|
||||
$view->result[0]->{$column_map_reversed['name']} = 0;
|
||||
$render = $view->field['name']->advancedRender($view->result[0]);
|
||||
$render = $renderer->executeInRenderContext(new RenderContext(), function () use ($view) {
|
||||
return $view->field['name']->advancedRender($view->result[0]);
|
||||
});
|
||||
$this->assertIdentical($render, '0', 'If hide_empty is checked, but not empty_zero, 0 should not be treated as empty.');
|
||||
|
||||
// Test zero as a string.
|
||||
$view->result[0]->{$column_map_reversed['name']} = "0";
|
||||
$render = $view->field['name']->advancedRender($view->result[0]);
|
||||
$render = $renderer->executeInRenderContext(new RenderContext(), function () use ($view) {
|
||||
return $view->field['name']->advancedRender($view->result[0]);
|
||||
});
|
||||
$this->assertIdentical($render, "0", 'If hide_empty is checked, but not empty_zero, "0" should not be treated as empty.');
|
||||
|
||||
// Test when results are not rewritten and all empty values are hidden.
|
||||
|
@ -334,12 +412,16 @@ class FieldUnitTest extends ViewUnitTestBase {
|
|||
|
||||
// Test zero as an integer.
|
||||
$view->result[0]->{$column_map_reversed['name']} = 0;
|
||||
$render = $view->field['name']->advancedRender($view->result[0]);
|
||||
$render = $renderer->executeInRenderContext(new RenderContext(), function () use ($view) {
|
||||
return $view->field['name']->advancedRender($view->result[0]);
|
||||
});
|
||||
$this->assertIdentical($render, "", 'If hide_empty and empty_zero are checked, 0 should be treated as empty.');
|
||||
|
||||
// Test zero as a string.
|
||||
$view->result[0]->{$column_map_reversed['name']} = "0";
|
||||
$render = $view->field['name']->advancedRender($view->result[0]);
|
||||
$render = $renderer->executeInRenderContext(new RenderContext(), function () use ($view) {
|
||||
return $view->field['name']->advancedRender($view->result[0]);
|
||||
});
|
||||
$this->assertIdentical($render, "", 'If hide_empty and empty_zero are checked, "0" should be treated as empty.');
|
||||
|
||||
// Test when results are rewritten to a valid string and non-zero empty
|
||||
|
@ -352,22 +434,30 @@ class FieldUnitTest extends ViewUnitTestBase {
|
|||
|
||||
// Test a valid string.
|
||||
$view->result[0]->{$column_map_reversed['name']} = $random_value;
|
||||
$render = $view->field['name']->advancedRender($view->result[0]);
|
||||
$render = $renderer->executeInRenderContext(new RenderContext(), function () use ($view) {
|
||||
return $view->field['name']->advancedRender($view->result[0]);
|
||||
});
|
||||
$this->assertIdentical($render, $random_name, 'If the rewritten string is not empty, it should not be treated as empty.');
|
||||
|
||||
// Test an empty string.
|
||||
$view->result[0]->{$column_map_reversed['name']} = "";
|
||||
$render = $view->field['name']->advancedRender($view->result[0]);
|
||||
$render = $renderer->executeInRenderContext(new RenderContext(), function () use ($view) {
|
||||
return $view->field['name']->advancedRender($view->result[0]);
|
||||
});
|
||||
$this->assertIdentical($render, $random_name, 'If the rewritten string is not empty, "" should not be treated as empty.');
|
||||
|
||||
// Test zero as an integer.
|
||||
$view->result[0]->{$column_map_reversed['name']} = 0;
|
||||
$render = $view->field['name']->advancedRender($view->result[0]);
|
||||
$render = $renderer->executeInRenderContext(new RenderContext(), function () use ($view) {
|
||||
return $view->field['name']->advancedRender($view->result[0]);
|
||||
});
|
||||
$this->assertIdentical($render, $random_name, 'If the rewritten string is not empty, 0 should not be treated as empty.');
|
||||
|
||||
// Test zero as a string.
|
||||
$view->result[0]->{$column_map_reversed['name']} = "0";
|
||||
$render = $view->field['name']->advancedRender($view->result[0]);
|
||||
$render = $renderer->executeInRenderContext(new RenderContext(), function () use ($view) {
|
||||
return $view->field['name']->advancedRender($view->result[0]);
|
||||
});
|
||||
$this->assertIdentical($render, $random_name, 'If the rewritten string is not empty, "0" should not be treated as empty.');
|
||||
|
||||
// Test when results are rewritten to an empty string and non-zero empty results are hidden.
|
||||
|
@ -379,22 +469,30 @@ class FieldUnitTest extends ViewUnitTestBase {
|
|||
|
||||
// Test a valid string.
|
||||
$view->result[0]->{$column_map_reversed['name']} = $random_name;
|
||||
$render = $view->field['name']->advancedRender($view->result[0]);
|
||||
$render = $renderer->executeInRenderContext(new RenderContext(), function () use ($view) {
|
||||
return $view->field['name']->advancedRender($view->result[0]);
|
||||
});
|
||||
$this->assertIdentical($render, $random_name, 'If the rewritten string is empty, it should not be treated as empty.');
|
||||
|
||||
// Test an empty string.
|
||||
$view->result[0]->{$column_map_reversed['name']} = "";
|
||||
$render = $view->field['name']->advancedRender($view->result[0]);
|
||||
$render = $renderer->executeInRenderContext(new RenderContext(), function () use ($view) {
|
||||
return $view->field['name']->advancedRender($view->result[0]);
|
||||
});
|
||||
$this->assertIdentical($render, "", 'If the rewritten string is empty, "" should be treated as empty.');
|
||||
|
||||
// Test zero as an integer.
|
||||
$view->result[0]->{$column_map_reversed['name']} = 0;
|
||||
$render = $view->field['name']->advancedRender($view->result[0]);
|
||||
$render = $renderer->executeInRenderContext(new RenderContext(), function () use ($view) {
|
||||
return $view->field['name']->advancedRender($view->result[0]);
|
||||
});
|
||||
$this->assertIdentical($render, '0', 'If the rewritten string is empty, 0 should not be treated as empty.');
|
||||
|
||||
// Test zero as a string.
|
||||
$view->result[0]->{$column_map_reversed['name']} = "0";
|
||||
$render = $view->field['name']->advancedRender($view->result[0]);
|
||||
$render = $renderer->executeInRenderContext(new RenderContext(), function () use ($view) {
|
||||
return $view->field['name']->advancedRender($view->result[0]);
|
||||
});
|
||||
$this->assertIdentical($render, "0", 'If the rewritten string is empty, "0" should not be treated as empty.');
|
||||
|
||||
// Test when results are rewritten to zero as a string and non-zero empty
|
||||
|
@ -407,22 +505,30 @@ class FieldUnitTest extends ViewUnitTestBase {
|
|||
|
||||
// Test a valid string.
|
||||
$view->result[0]->{$column_map_reversed['name']} = $random_name;
|
||||
$render = $view->field['name']->advancedRender($view->result[0]);
|
||||
$render = $renderer->executeInRenderContext(new RenderContext(), function () use ($view) {
|
||||
return $view->field['name']->advancedRender($view->result[0]);
|
||||
});
|
||||
$this->assertIdentical($render, "0", 'If the rewritten string is zero and empty_zero is not checked, the string rewritten as 0 should not be treated as empty.');
|
||||
|
||||
// Test an empty string.
|
||||
$view->result[0]->{$column_map_reversed['name']} = "";
|
||||
$render = $view->field['name']->advancedRender($view->result[0]);
|
||||
$render = $renderer->executeInRenderContext(new RenderContext(), function () use ($view) {
|
||||
return $view->field['name']->advancedRender($view->result[0]);
|
||||
});
|
||||
$this->assertIdentical($render, "0", 'If the rewritten string is zero and empty_zero is not checked, "" rewritten as 0 should not be treated as empty.');
|
||||
|
||||
// Test zero as an integer.
|
||||
$view->result[0]->{$column_map_reversed['name']} = 0;
|
||||
$render = $view->field['name']->advancedRender($view->result[0]);
|
||||
$render = $renderer->executeInRenderContext(new RenderContext(), function () use ($view) {
|
||||
return $view->field['name']->advancedRender($view->result[0]);
|
||||
});
|
||||
$this->assertIdentical($render, "0", 'If the rewritten string is zero and empty_zero is not checked, 0 should not be treated as empty.');
|
||||
|
||||
// Test zero as a string.
|
||||
$view->result[0]->{$column_map_reversed['name']} = "0";
|
||||
$render = $view->field['name']->advancedRender($view->result[0]);
|
||||
$render = $renderer->executeInRenderContext(new RenderContext(), function () use ($view) {
|
||||
return $view->field['name']->advancedRender($view->result[0]);
|
||||
});
|
||||
$this->assertIdentical($render, "0", 'If the rewritten string is zero and empty_zero is not checked, "0" should not be treated as empty.');
|
||||
|
||||
// Test when results are rewritten to a valid string and non-zero empty
|
||||
|
@ -435,22 +541,30 @@ class FieldUnitTest extends ViewUnitTestBase {
|
|||
|
||||
// Test a valid string.
|
||||
$view->result[0]->{$column_map_reversed['name']} = $random_name;
|
||||
$render = $view->field['name']->advancedRender($view->result[0]);
|
||||
$render = $renderer->executeInRenderContext(new RenderContext(), function () use ($view) {
|
||||
return $view->field['name']->advancedRender($view->result[0]);
|
||||
});
|
||||
$this->assertIdentical($render, $random_value, 'If the original and rewritten strings are valid, it should not be treated as empty.');
|
||||
|
||||
// Test an empty string.
|
||||
$view->result[0]->{$column_map_reversed['name']} = "";
|
||||
$render = $view->field['name']->advancedRender($view->result[0]);
|
||||
$render = $renderer->executeInRenderContext(new RenderContext(), function () use ($view) {
|
||||
return $view->field['name']->advancedRender($view->result[0]);
|
||||
});
|
||||
$this->assertIdentical($render, "", 'If either the original or rewritten string is invalid, "" should be treated as empty.');
|
||||
|
||||
// Test zero as an integer.
|
||||
$view->result[0]->{$column_map_reversed['name']} = 0;
|
||||
$render = $view->field['name']->advancedRender($view->result[0]);
|
||||
$render = $renderer->executeInRenderContext(new RenderContext(), function () use ($view) {
|
||||
return $view->field['name']->advancedRender($view->result[0]);
|
||||
});
|
||||
$this->assertIdentical($render, $random_value, 'If the original and rewritten strings are valid, 0 should not be treated as empty.');
|
||||
|
||||
// Test zero as a string.
|
||||
$view->result[0]->{$column_map_reversed['name']} = "0";
|
||||
$render = $view->field['name']->advancedRender($view->result[0]);
|
||||
$render = $renderer->executeInRenderContext(new RenderContext(), function () use ($view) {
|
||||
return $view->field['name']->advancedRender($view->result[0]);
|
||||
});
|
||||
$this->assertIdentical($render, $random_value, 'If the original and rewritten strings are valid, "0" should not be treated as empty.');
|
||||
|
||||
// Test when results are rewritten to zero as a string and all empty
|
||||
|
@ -463,22 +577,30 @@ class FieldUnitTest extends ViewUnitTestBase {
|
|||
|
||||
// Test a valid string.
|
||||
$view->result[0]->{$column_map_reversed['name']} = $random_name;
|
||||
$render = $view->field['name']->advancedRender($view->result[0]);
|
||||
$render = $renderer->executeInRenderContext(new RenderContext(), function () use ($view) {
|
||||
return $view->field['name']->advancedRender($view->result[0]);
|
||||
});
|
||||
$this->assertIdentical($render, "", 'If the rewritten string is zero, it should be treated as empty.');
|
||||
|
||||
// Test an empty string.
|
||||
$view->result[0]->{$column_map_reversed['name']} = "";
|
||||
$render = $view->field['name']->advancedRender($view->result[0]);
|
||||
$render = $renderer->executeInRenderContext(new RenderContext(), function () use ($view) {
|
||||
return $view->field['name']->advancedRender($view->result[0]);
|
||||
});
|
||||
$this->assertIdentical($render, "", 'If the rewritten string is zero, "" should be treated as empty.');
|
||||
|
||||
// Test zero as an integer.
|
||||
$view->result[0]->{$column_map_reversed['name']} = 0;
|
||||
$render = $view->field['name']->advancedRender($view->result[0]);
|
||||
$render = $renderer->executeInRenderContext(new RenderContext(), function () use ($view) {
|
||||
return $view->field['name']->advancedRender($view->result[0]);
|
||||
});
|
||||
$this->assertIdentical($render, "", 'If the rewritten string is zero, 0 should not be treated as empty.');
|
||||
|
||||
// Test zero as a string.
|
||||
$view->result[0]->{$column_map_reversed['name']} = "0";
|
||||
$render = $view->field['name']->advancedRender($view->result[0]);
|
||||
$render = $renderer->executeInRenderContext(new RenderContext(), function () use ($view) {
|
||||
return $view->field['name']->advancedRender($view->result[0]);
|
||||
});
|
||||
$this->assertIdentical($render, "", 'If the rewritten string is zero, "0" should not be treated as empty.');
|
||||
}
|
||||
|
||||
|
@ -486,6 +608,9 @@ class FieldUnitTest extends ViewUnitTestBase {
|
|||
* Tests the usage of the empty text.
|
||||
*/
|
||||
function _testEmptyText() {
|
||||
/** @var \Drupal\Core\Render\RendererInterface $renderer */
|
||||
$renderer = \Drupal::service('renderer');
|
||||
|
||||
$view = Views::getView('test_view');
|
||||
$view->initDisplay();
|
||||
$this->executeView($view);
|
||||
|
@ -495,27 +620,37 @@ class FieldUnitTest extends ViewUnitTestBase {
|
|||
|
||||
$empty_text = $view->field['name']->options['empty'] = $this->randomMachineName();
|
||||
$view->result[0]->{$column_map_reversed['name']} = "";
|
||||
$render = $view->field['name']->advancedRender($view->result[0]);
|
||||
$render = $renderer->executeInRenderContext(new RenderContext(), function () use ($view) {
|
||||
return $view->field['name']->advancedRender($view->result[0]);
|
||||
});
|
||||
$this->assertIdentical($render, $empty_text, 'If a field is empty, the empty text should be used for the output.');
|
||||
|
||||
$view->result[0]->{$column_map_reversed['name']} = "0";
|
||||
$render = $view->field['name']->advancedRender($view->result[0]);
|
||||
$render = $renderer->executeInRenderContext(new RenderContext(), function () use ($view) {
|
||||
return $view->field['name']->advancedRender($view->result[0]);
|
||||
});
|
||||
$this->assertIdentical($render, "0", 'If a field is 0 and empty_zero is not checked, the empty text should not be used for the output.');
|
||||
|
||||
$view->result[0]->{$column_map_reversed['name']} = "0";
|
||||
$view->field['name']->options['empty_zero'] = TRUE;
|
||||
$render = $view->field['name']->advancedRender($view->result[0]);
|
||||
$render = $renderer->executeInRenderContext(new RenderContext(), function () use ($view) {
|
||||
return $view->field['name']->advancedRender($view->result[0]);
|
||||
});
|
||||
$this->assertIdentical($render, $empty_text, 'If a field is 0 and empty_zero is checked, the empty text should be used for the output.');
|
||||
|
||||
$view->result[0]->{$column_map_reversed['name']} = "";
|
||||
$view->field['name']->options['alter']['alter_text'] = TRUE;
|
||||
$alter_text = $view->field['name']->options['alter']['text'] = $this->randomMachineName();
|
||||
$view->field['name']->options['hide_alter_empty'] = FALSE;
|
||||
$render = $view->field['name']->advancedRender($view->result[0]);
|
||||
$render = $renderer->executeInRenderContext(new RenderContext(), function () use ($view) {
|
||||
return $view->field['name']->advancedRender($view->result[0]);
|
||||
});
|
||||
$this->assertIdentical($render, $alter_text, 'If a field is empty, some rewrite text exists, but hide_alter_empty is not checked, render the rewrite text.');
|
||||
|
||||
$view->field['name']->options['hide_alter_empty'] = TRUE;
|
||||
$render = $view->field['name']->advancedRender($view->result[0]);
|
||||
$render = $renderer->executeInRenderContext(new RenderContext(), function () use ($view) {
|
||||
return $view->field['name']->advancedRender($view->result[0]);
|
||||
});
|
||||
$this->assertIdentical($render, $empty_text, 'If a field is empty, some rewrite text exists, and hide_alter_empty is checked, use the empty text.');
|
||||
}
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@ namespace Drupal\views\Tests\Handler;
|
|||
use Drupal\Component\Utility\Html;
|
||||
use Drupal\Component\Utility\Unicode;
|
||||
use Drupal\Component\Utility\UrlHelper;
|
||||
use Drupal\Core\Render\RenderContext;
|
||||
use Drupal\system\Tests\Cache\AssertPageCacheContextsAndTagsTrait;
|
||||
use Drupal\views\Views;
|
||||
|
||||
|
@ -67,23 +68,21 @@ class FieldWebTest extends HandlerTestBase {
|
|||
$this->assertResponse(200);
|
||||
|
||||
// Only the id and name should be click sortable, but not the name.
|
||||
$this->assertLinkByHref(\Drupal::url('view.test_click_sort.page_1', [], ['query' => ['order' => 'id', 'sort' => 'asc']]));
|
||||
$this->assertLinkByHref(\Drupal::url('view.test_click_sort.page_1', [], ['query' => ['order' => 'name', 'sort' => 'desc']]));
|
||||
$this->assertNoLinkByHref(\Drupal::url('view.test_click_sort.page_1', [], ['query' => ['order' => 'created']]));
|
||||
$this->assertLinkByHref(\Drupal::url('<none>', [], ['query' => ['order' => 'id', 'sort' => 'asc']]));
|
||||
$this->assertLinkByHref(\Drupal::url('<none>', [], ['query' => ['order' => 'name', 'sort' => 'desc']]));
|
||||
$this->assertNoLinkByHref(\Drupal::url('<none>', [], ['query' => ['order' => 'created']]));
|
||||
|
||||
// Check that the view returns the click sorting cache contexts.
|
||||
$expected_contexts = [
|
||||
'languages:language_interface',
|
||||
'theme',
|
||||
'url.query_args.pagers:0',
|
||||
'url.query_args:order',
|
||||
'url.query_args:sort',
|
||||
'url.query_args',
|
||||
];
|
||||
$this->assertCacheContexts($expected_contexts);
|
||||
|
||||
// Clicking a click sort should change the order.
|
||||
$this->clickLink(t('ID'));
|
||||
$this->assertLinkByHref(\Drupal::url('view.test_click_sort.page_1', [], ['query' => ['order' => 'id', 'sort' => 'desc']]));
|
||||
$this->assertLinkByHref(\Drupal::url('<none>', [], ['query' => ['order' => 'id', 'sort' => 'desc']]));
|
||||
// Check that the output has the expected order (asc).
|
||||
$ids = $this->clickSortLoadIdsFromOutput();
|
||||
$this->assertEqual($ids, range(1, 5));
|
||||
|
@ -197,6 +196,9 @@ class FieldWebTest extends HandlerTestBase {
|
|||
* Tests rewriting the output to a link.
|
||||
*/
|
||||
public function testAlterUrl() {
|
||||
/** @var \Drupal\Core\Render\RendererInterface $renderer */
|
||||
$renderer = \Drupal::service('renderer');
|
||||
|
||||
$view = Views::getView('test_view');
|
||||
$view->setDisplay();
|
||||
$view->initHandlers();
|
||||
|
@ -211,13 +213,17 @@ class FieldWebTest extends HandlerTestBase {
|
|||
// Tests that the suffix/prefix appears on the output.
|
||||
$id_field->options['alter']['prefix'] = $prefix = $this->randomMachineName();
|
||||
$id_field->options['alter']['suffix'] = $suffix = $this->randomMachineName();
|
||||
$output = $id_field->theme($row);
|
||||
$output = $renderer->executeInRenderContext(new RenderContext(), function () use ($id_field, $row) {
|
||||
return $id_field->theme($row);
|
||||
});
|
||||
$this->assertSubString($output, $prefix);
|
||||
$this->assertSubString($output, $suffix);
|
||||
unset($id_field->options['alter']['prefix']);
|
||||
unset($id_field->options['alter']['suffix']);
|
||||
|
||||
$output = $id_field->theme($row);
|
||||
$output = $renderer->executeInRenderContext(new RenderContext(), function () use ($id_field, $row) {
|
||||
return $id_field->theme($row);
|
||||
});
|
||||
$this->assertSubString($output, $path, 'Make sure that the path is part of the output');
|
||||
|
||||
// Some generic test code adapted from the UrlTest class, which tests
|
||||
|
@ -228,44 +234,60 @@ class FieldWebTest extends HandlerTestBase {
|
|||
|
||||
$expected_result = \Drupal::url('entity.node.canonical', ['node' => '123'], ['absolute' => $absolute]);
|
||||
$alter['absolute'] = $absolute;
|
||||
$result = $id_field->theme($row);
|
||||
$result = $renderer->executeInRenderContext(new RenderContext(), function () use ($id_field, $row) {
|
||||
return $id_field->theme($row);
|
||||
});
|
||||
$this->assertSubString($result, $expected_result);
|
||||
|
||||
$expected_result = \Drupal::url('entity.node.canonical', ['node' => '123'], ['fragment' => 'foo', 'absolute' => $absolute]);
|
||||
$alter['path'] = 'node/123#foo';
|
||||
$result = $id_field->theme($row);
|
||||
$result = $renderer->executeInRenderContext(new RenderContext(), function () use ($id_field, $row) {
|
||||
return $id_field->theme($row);
|
||||
});
|
||||
$this->assertSubString($result, $expected_result);
|
||||
|
||||
$expected_result = \Drupal::url('entity.node.canonical', ['node' => '123'], ['query' => ['foo' => NULL], 'absolute' => $absolute]);
|
||||
$alter['path'] = 'node/123?foo';
|
||||
$result = $id_field->theme($row);
|
||||
$result = $renderer->executeInRenderContext(new RenderContext(), function () use ($id_field, $row) {
|
||||
return $id_field->theme($row);
|
||||
});
|
||||
$this->assertSubString($result, $expected_result);
|
||||
|
||||
$expected_result = \Drupal::url('entity.node.canonical', ['node' => '123'], ['query' => ['foo' => 'bar', 'bar' => 'baz'], 'absolute' => $absolute]);
|
||||
$alter['path'] = 'node/123?foo=bar&bar=baz';
|
||||
$result = $id_field->theme($row);
|
||||
$result = $renderer->executeInRenderContext(new RenderContext(), function () use ($id_field, $row) {
|
||||
return $id_field->theme($row);
|
||||
});
|
||||
$this->assertSubString(Html::decodeEntities($result), Html::decodeEntities($expected_result));
|
||||
|
||||
// @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));
|
||||
$alter['path'] = 'node/123?foo#bar';
|
||||
$result = $id_field->theme($row);
|
||||
$result = $renderer->executeInRenderContext(new RenderContext(), function () use ($id_field, $row) {
|
||||
return $id_field->theme($row);
|
||||
});
|
||||
$this->assertSubString(Html::decodeEntities($result), Html::decodeEntities($expected_result));
|
||||
|
||||
$expected_result = \Drupal::url('<front>', [], ['absolute' => $absolute]);
|
||||
$alter['path'] = '<front>';
|
||||
$result = $id_field->theme($row);
|
||||
$result = $renderer->executeInRenderContext(new RenderContext(), function () use ($id_field, $row) {
|
||||
return $id_field->theme($row);
|
||||
});
|
||||
$this->assertSubString($result, $expected_result);
|
||||
}
|
||||
|
||||
// Tests the replace spaces with dashes feature.
|
||||
$id_field->options['alter']['replace_spaces'] = TRUE;
|
||||
$id_field->options['alter']['path'] = $path = $this->randomMachineName() . ' ' . $this->randomMachineName();
|
||||
$output = $id_field->theme($row);
|
||||
$output = $renderer->executeInRenderContext(new RenderContext(), function () use ($id_field, $row) {
|
||||
return $id_field->theme($row);
|
||||
});
|
||||
$this->assertSubString($output, str_replace(' ', '-', $path));
|
||||
$id_field->options['alter']['replace_spaces'] = FALSE;
|
||||
$output = $id_field->theme($row);
|
||||
$output = $renderer->executeInRenderContext(new RenderContext(), function () use ($id_field, $row) {
|
||||
return $id_field->theme($row);
|
||||
});
|
||||
// The url has a space in it, so to check we have to decode the url output.
|
||||
$this->assertSubString(urldecode($output), $path);
|
||||
|
||||
|
@ -273,44 +295,60 @@ class FieldWebTest extends HandlerTestBase {
|
|||
// Switch on the external flag should output an external url as well.
|
||||
$id_field->options['alter']['external'] = TRUE;
|
||||
$id_field->options['alter']['path'] = $path = 'www.drupal.org';
|
||||
$output = $id_field->theme($row);
|
||||
$output = $renderer->executeInRenderContext(new RenderContext(), function () use ($id_field, $row) {
|
||||
return $id_field->theme($row);
|
||||
});
|
||||
$this->assertSubString($output, 'http://www.drupal.org');
|
||||
|
||||
// Setup a not external url, which shouldn't lead to an external url.
|
||||
$id_field->options['alter']['external'] = FALSE;
|
||||
$id_field->options['alter']['path'] = $path = 'www.drupal.org';
|
||||
$output = $id_field->theme($row);
|
||||
$output = $renderer->executeInRenderContext(new RenderContext(), function () use ($id_field, $row) {
|
||||
return $id_field->theme($row);
|
||||
});
|
||||
$this->assertNotSubString($output, 'http://www.drupal.org');
|
||||
|
||||
// Tests the transforming of the case setting.
|
||||
$id_field->options['alter']['path'] = $path = $this->randomMachineName();
|
||||
$id_field->options['alter']['path_case'] = 'none';
|
||||
$output = $id_field->theme($row);
|
||||
$output = $renderer->executeInRenderContext(new RenderContext(), function () use ($id_field, $row) {
|
||||
return $id_field->theme($row);
|
||||
});
|
||||
$this->assertSubString($output, $path);
|
||||
|
||||
// Switch to uppercase and lowercase.
|
||||
$id_field->options['alter']['path_case'] = 'upper';
|
||||
$output = $id_field->theme($row);
|
||||
$output = $renderer->executeInRenderContext(new RenderContext(), function () use ($id_field, $row) {
|
||||
return $id_field->theme($row);
|
||||
});
|
||||
$this->assertSubString($output, strtoupper($path));
|
||||
$id_field->options['alter']['path_case'] = 'lower';
|
||||
$output = $id_field->theme($row);
|
||||
$output = $renderer->executeInRenderContext(new RenderContext(), function () use ($id_field, $row) {
|
||||
return $id_field->theme($row);
|
||||
});
|
||||
$this->assertSubString($output, strtolower($path));
|
||||
|
||||
// Switch to ucfirst and ucwords.
|
||||
$id_field->options['alter']['path_case'] = 'ucfirst';
|
||||
$id_field->options['alter']['path'] = 'drupal has a great community';
|
||||
$output = $id_field->theme($row);
|
||||
$output = $renderer->executeInRenderContext(new RenderContext(), function () use ($id_field, $row) {
|
||||
return $id_field->theme($row);
|
||||
});
|
||||
$this->assertSubString($output, UrlHelper::encodePath('Drupal has a great community'));
|
||||
|
||||
$id_field->options['alter']['path_case'] = 'ucwords';
|
||||
$output = $id_field->theme($row);
|
||||
$output = $renderer->executeInRenderContext(new RenderContext(), function () use ($id_field, $row) {
|
||||
return $id_field->theme($row);
|
||||
});
|
||||
$this->assertSubString($output, UrlHelper::encodePath('Drupal Has A Great Community'));
|
||||
unset($id_field->options['alter']['path_case']);
|
||||
|
||||
// Tests the linkclass setting and see whether it actually exists in the
|
||||
// output.
|
||||
$id_field->options['alter']['link_class'] = $class = $this->randomMachineName();
|
||||
$output = $id_field->theme($row);
|
||||
$output = $renderer->executeInRenderContext(new RenderContext(), function () use ($id_field, $row) {
|
||||
return $id_field->theme($row);
|
||||
});
|
||||
$elements = $this->xpathContent($output, '//a[contains(@class, :class)]', array(':class' => $class));
|
||||
$this->assertTrue($elements);
|
||||
// @fixme link_class, alt, rel cannot be unset, which should be fixed.
|
||||
|
@ -318,21 +356,27 @@ class FieldWebTest extends HandlerTestBase {
|
|||
|
||||
// Tests the alt setting.
|
||||
$id_field->options['alter']['alt'] = $rel = $this->randomMachineName();
|
||||
$output = $id_field->theme($row);
|
||||
$output = $renderer->executeInRenderContext(new RenderContext(), function () use ($id_field, $row) {
|
||||
return $id_field->theme($row);
|
||||
});
|
||||
$elements = $this->xpathContent($output, '//a[contains(@title, :alt)]', array(':alt' => $rel));
|
||||
$this->assertTrue($elements);
|
||||
$id_field->options['alter']['alt'] = '';
|
||||
|
||||
// Tests the rel setting.
|
||||
$id_field->options['alter']['rel'] = $rel = $this->randomMachineName();
|
||||
$output = $id_field->theme($row);
|
||||
$output = $renderer->executeInRenderContext(new RenderContext(), function () use ($id_field, $row) {
|
||||
return $id_field->theme($row);
|
||||
});
|
||||
$elements = $this->xpathContent($output, '//a[contains(@rel, :rel)]', array(':rel' => $rel));
|
||||
$this->assertTrue($elements);
|
||||
$id_field->options['alter']['rel'] = '';
|
||||
|
||||
// Tests the target setting.
|
||||
$id_field->options['alter']['target'] = $target = $this->randomMachineName();
|
||||
$output = $id_field->theme($row);
|
||||
$output = $renderer->executeInRenderContext(new RenderContext(), function () use ($id_field, $row) {
|
||||
return $id_field->theme($row);
|
||||
});
|
||||
$elements = $this->xpathContent($output, '//a[contains(@target, :target)]', array(':target' => $target));
|
||||
$this->assertTrue($elements);
|
||||
unset($id_field->options['alter']['target']);
|
||||
|
@ -453,6 +497,9 @@ class FieldWebTest extends HandlerTestBase {
|
|||
* Tests trimming/read-more/ellipses.
|
||||
*/
|
||||
public function testTextRendering() {
|
||||
/** @var \Drupal\Core\Render\RendererInterface $renderer */
|
||||
$renderer = \Drupal::service('renderer');
|
||||
|
||||
$view = Views::getView('test_field_output');
|
||||
$view->initHandlers();
|
||||
$name_field = $view->field['name'];
|
||||
|
@ -465,18 +512,24 @@ class FieldWebTest extends HandlerTestBase {
|
|||
$row = $view->result[0];
|
||||
|
||||
$name_field->options['alter']['strip_tags'] = TRUE;
|
||||
$output = $name_field->advancedRender($row);
|
||||
$output = $renderer->executeInRenderContext(new RenderContext(), function () use ($name_field, $row) {
|
||||
return $name_field->advancedRender($row);
|
||||
});
|
||||
$this->assertSubString($output, $random_text, 'Find text without html if stripping of views field output is enabled.');
|
||||
$this->assertNotSubString($output, $html_text, 'Find no text with the html if stripping of views field output is enabled.');
|
||||
|
||||
// Tests preserving of html tags.
|
||||
$name_field->options['alter']['preserve_tags'] = '<div>';
|
||||
$output = $name_field->advancedRender($row);
|
||||
$output = $renderer->executeInRenderContext(new RenderContext(), function () use ($name_field, $row) {
|
||||
return $name_field->advancedRender($row);
|
||||
});
|
||||
$this->assertSubString($output, $random_text, 'Find text without html if stripping of views field output is enabled but a div is allowed.');
|
||||
$this->assertSubString($output, $html_text, 'Find text with the html if stripping of views field output is enabled but a div is allowed.');
|
||||
|
||||
$name_field->options['alter']['strip_tags'] = FALSE;
|
||||
$output = $name_field->advancedRender($row);
|
||||
$output = $renderer->executeInRenderContext(new RenderContext(), function () use ($name_field, $row) {
|
||||
return $name_field->advancedRender($row);
|
||||
});
|
||||
$this->assertSubString($output, $random_text, 'Find text without html if stripping of views field output is disabled.');
|
||||
$this->assertSubString($output, $html_text, 'Find text with the html if stripping of views field output is disabled.');
|
||||
|
||||
|
@ -485,13 +538,17 @@ class FieldWebTest extends HandlerTestBase {
|
|||
$views_test_data_name = $row->views_test_data_name;
|
||||
$row->views_test_data_name = ' ' . $views_test_data_name . ' ';
|
||||
$name_field->options['alter']['trim_whitespace'] = TRUE;
|
||||
$output = $name_field->advancedRender($row);
|
||||
$output = $renderer->executeInRenderContext(new RenderContext(), function () use ($name_field, $row) {
|
||||
return $name_field->advancedRender($row);
|
||||
});
|
||||
|
||||
$this->assertSubString($output, $views_test_data_name, 'Make sure the trimmed text can be found if trimming is enabled.');
|
||||
$this->assertNotSubString($output, $row->views_test_data_name, 'Make sure the untrimmed text can be found if trimming is enabled.');
|
||||
|
||||
$name_field->options['alter']['trim_whitespace'] = FALSE;
|
||||
$output = $name_field->advancedRender($row);
|
||||
$output = $renderer->executeInRenderContext(new RenderContext(), function () use ($name_field, $row) {
|
||||
return $name_field->advancedRender($row);
|
||||
});
|
||||
$this->assertSubString($output, $views_test_data_name, 'Make sure the trimmed text can be found if trimming is disabled.');
|
||||
$this->assertSubString($output, $row->views_test_data_name, 'Make sure the untrimmed text can be found if trimming is disabled.');
|
||||
|
||||
|
@ -504,12 +561,16 @@ class FieldWebTest extends HandlerTestBase {
|
|||
$name_field->options['alter']['max_length'] = 5;
|
||||
$trimmed_name = Unicode::substr($row->views_test_data_name, 0, 5);
|
||||
|
||||
$output = $name_field->advancedRender($row);
|
||||
$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)));
|
||||
|
||||
$name_field->options['alter']['max_length'] = 9;
|
||||
$output = $name_field->advancedRender($row);
|
||||
$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)));
|
||||
|
||||
// Take word_boundary into account for the tests.
|
||||
|
@ -549,7 +610,9 @@ class FieldWebTest extends HandlerTestBase {
|
|||
|
||||
foreach ($tuples as $tuple) {
|
||||
$row->views_test_data_name = $tuple['value'];
|
||||
$output = $name_field->advancedRender($row);
|
||||
$output = $renderer->executeInRenderContext(new RenderContext(), function () use ($name_field, $row) {
|
||||
return $name_field->advancedRender($row);
|
||||
});
|
||||
|
||||
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)));
|
||||
|
@ -566,22 +629,30 @@ class FieldWebTest extends HandlerTestBase {
|
|||
$name_field->options['alter']['more_link_text'] = $more_text = $this->randomMachineName();
|
||||
$name_field->options['alter']['more_link_path'] = $more_path = $this->randomMachineName();
|
||||
|
||||
$output = $name_field->advancedRender($row);
|
||||
$output = $renderer->executeInRenderContext(new RenderContext(), function () use ($name_field, $row) {
|
||||
return $name_field->advancedRender($row);
|
||||
});
|
||||
$this->assertSubString($output, $more_text, 'Make sure a read more text is displayed if the output got trimmed');
|
||||
$this->assertTrue($this->xpathContent($output, '//a[contains(@href, :path)]', array(':path' => $more_path)), 'Make sure the read more link points to the right destination.');
|
||||
|
||||
$name_field->options['alter']['more_link'] = FALSE;
|
||||
$output = $name_field->advancedRender($row);
|
||||
$output = $renderer->executeInRenderContext(new RenderContext(), function () use ($name_field, $row) {
|
||||
return $name_field->advancedRender($row);
|
||||
});
|
||||
$this->assertNotSubString($output, $more_text, 'Make sure no read more text appears.');
|
||||
$this->assertFalse($this->xpathContent($output, '//a[contains(@href, :path)]', array(':path' => $more_path)), 'Make sure no read more link appears.');
|
||||
|
||||
// Check for the ellipses.
|
||||
$row->views_test_data_name = $this->randomMachineName(8);
|
||||
$name_field->options['alter']['max_length'] = 5;
|
||||
$output = $name_field->advancedRender($row);
|
||||
$output = $renderer->executeInRenderContext(new RenderContext(), function () use ($name_field, $row) {
|
||||
return $name_field->advancedRender($row);
|
||||
});
|
||||
$this->assertSubString($output, '…', 'An ellipsis should appear if the output is trimmed');
|
||||
$name_field->options['alter']['max_length'] = 10;
|
||||
$output = $name_field->advancedRender($row);
|
||||
$output = $renderer->executeInRenderContext(new RenderContext(), function () use ($name_field, $row) {
|
||||
return $name_field->advancedRender($row);
|
||||
});
|
||||
$this->assertNotSubString($output, '…', 'No ellipsis should appear if the output is not trimmed');
|
||||
}
|
||||
|
||||
|
|
|
@ -7,8 +7,8 @@
|
|||
|
||||
namespace Drupal\views\Tests\Handler;
|
||||
|
||||
use Drupal\simpletest\UserCreationTrait;
|
||||
use Drupal\views\Views;
|
||||
use Drupal\views\Tests\ViewUnitTestBase;
|
||||
use Drupal\views\Tests\Plugin\RelationshipJoinTestBase;
|
||||
|
||||
/**
|
||||
|
@ -18,6 +18,7 @@ use Drupal\views\Tests\Plugin\RelationshipJoinTestBase;
|
|||
* @see \Drupal\views\Plugin\views\relationship\RelationshipPluginBase
|
||||
*/
|
||||
class RelationshipTest extends RelationshipJoinTestBase {
|
||||
use UserCreationTrait;
|
||||
|
||||
/**
|
||||
* Views used by this test.
|
||||
|
@ -133,4 +134,51 @@ class RelationshipTest extends RelationshipJoinTestBase {
|
|||
$this->assertIdenticalResultset($view, $expected_result, $this->columnMap);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests rendering of a view with a relationship.
|
||||
*/
|
||||
public function testRelationshipRender() {
|
||||
$author1 = $this->createUser();
|
||||
db_query("UPDATE {views_test_data} SET uid = :uid WHERE id = 1", [':uid' => $author1->id()]);
|
||||
$author2 = $this->createUser();
|
||||
db_query("UPDATE {views_test_data} SET uid = :uid WHERE id = 2", [':uid' => $author2->id()]);
|
||||
// Set uid to non-existing author uid for row 3.
|
||||
db_query("UPDATE {views_test_data} SET uid = :uid WHERE id = 3", [':uid' => $author2->id() + 123]);
|
||||
|
||||
$view = Views::getView('test_view');
|
||||
// Add a relationship for authors.
|
||||
$view->getDisplay()->overrideOption('relationships', [
|
||||
'uid' => [
|
||||
'id' => 'uid',
|
||||
'table' => 'views_test_data',
|
||||
'field' => 'uid',
|
||||
],
|
||||
]);
|
||||
// Add fields for {views_test_data}.id and author name.
|
||||
$view->getDisplay()->overrideOption('fields', [
|
||||
'id' => [
|
||||
'id' => 'id',
|
||||
'table' => 'views_test_data',
|
||||
'field' => 'id',
|
||||
],
|
||||
'author' => [
|
||||
'id' => 'author',
|
||||
'table' => 'users_field_data',
|
||||
'field' => 'name',
|
||||
'relationship' => 'uid',
|
||||
],
|
||||
]);
|
||||
|
||||
// Render the view.
|
||||
$output = $view->preview();
|
||||
$html = $this->container->get('renderer')->renderRoot($output);
|
||||
$this->setRawContent($html);
|
||||
|
||||
// Check that the output contains correct values.
|
||||
$xpath = '//div[@class="views-row" and div[@class="views-field views-field-id"]=:id and div[@class="views-field views-field-author"]=:author]';
|
||||
$this->assertEqual(1, count($this->xpath($xpath, [':id' => 1, ':author' => $author1->getUsername()])));
|
||||
$this->assertEqual(1, count($this->xpath($xpath, [':id' => 2, ':author' => $author2->getUsername()])));
|
||||
$this->assertEqual(1, count($this->xpath($xpath, [':id' => 3, ':author' => ''])));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -197,7 +197,7 @@ class CacheTagTest extends PluginTestBase {
|
|||
$view->destroy();
|
||||
// Invalidate the views cache tags in order to invalidate the render
|
||||
// caching.
|
||||
\Drupal::service('cache_tags.invalidator')->invalidateTags($view->storage->getCacheTags());
|
||||
\Drupal::service('cache_tags.invalidator')->invalidateTags($view->storage->getCacheTagsToInvalidate());
|
||||
$build = $view->buildRenderable();
|
||||
$renderer->renderPlain($build);
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
namespace Drupal\views\Tests\Plugin;
|
||||
|
||||
use Drupal\Core\Render\RenderContext;
|
||||
use Drupal\node\Entity\Node;
|
||||
use Drupal\views\Tests\ViewUnitTestBase;
|
||||
use Drupal\views\Views;
|
||||
|
@ -282,14 +283,18 @@ class CacheTest extends ViewUnitTestBase {
|
|||
$output = $view->buildRenderable();
|
||||
/** @var \Drupal\Core\Render\RendererInterface $renderer */
|
||||
$renderer = \Drupal::service('renderer');
|
||||
$renderer->render($output);
|
||||
$renderer->executeInRenderContext(new RenderContext(), function () use (&$output, $renderer) {
|
||||
return $renderer->render($output);
|
||||
});
|
||||
|
||||
unset($view->pre_render_called);
|
||||
$view->destroy();
|
||||
|
||||
$view->setDisplay();
|
||||
$output = $view->buildRenderable();
|
||||
$renderer->render($output);
|
||||
$renderer->executeInRenderContext(new RenderContext(), function () use (&$output, $renderer) {
|
||||
return $renderer->render($output);
|
||||
});
|
||||
|
||||
$this->assertTrue(in_array('views_test_data/test', $output['#attached']['library']), 'Make sure libraries are added for cached views.');
|
||||
$this->assertEqual(['foo' => 'bar'], $output['#attached']['drupalSettings'], 'Make sure drupalSettings are added for cached views.');
|
||||
|
|
|
@ -206,11 +206,7 @@ class ExposedFormTest extends ViewTestBase {
|
|||
'languages:language_interface',
|
||||
'entity_test_view_grants',
|
||||
'theme',
|
||||
'url.query_args.pagers:0',
|
||||
'url.query_args:items_per_page',
|
||||
'url.query_args:offset',
|
||||
'url.query_args:sort_order',
|
||||
'url.query_args:sort_by',
|
||||
'url.query_args',
|
||||
'languages:language_content'
|
||||
];
|
||||
|
||||
|
|
|
@ -261,7 +261,7 @@ class PagerTest extends PluginTestBase {
|
|||
|
||||
// Test pager cache contexts.
|
||||
$this->drupalGet('test_pager_full');
|
||||
$this->assertCacheContexts(['languages:language_interface', 'theme', 'timezone', 'url.query_args.pagers:0', 'user.node_grants:view']);
|
||||
$this->assertCacheContexts(['languages:language_interface', 'theme', 'timezone', 'url.query_args', 'user.node_grants:view']);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -253,9 +253,9 @@ class QueryGroupByTest extends ViewUnitTestBase {
|
|||
$this->executeView($view);
|
||||
$this->assertEqual(2, count($view->result));
|
||||
|
||||
$this->assertEqual(3, $view->getStyle()->getField(0, 'id'));
|
||||
$this->assertEqual('3', $view->getStyle()->getField(0, 'id'));
|
||||
$this->assertEqual('1', $view->getStyle()->getField(0, 'field_test'));
|
||||
$this->assertEqual(6, $view->getStyle()->getField(1, 'id'));
|
||||
$this->assertEqual('6', $view->getStyle()->getField(1, 'id'));
|
||||
$this->assertEqual('2', $view->getStyle()->getField(1, 'field_test'));
|
||||
|
||||
$entities[2]->field_test[0]->value = 3;
|
||||
|
@ -267,15 +267,15 @@ class QueryGroupByTest extends ViewUnitTestBase {
|
|||
$this->executeView($view);
|
||||
$this->assertEqual(5, count($view->result));
|
||||
|
||||
$this->assertEqual(3, $view->getStyle()->getField(0, 'id'));
|
||||
$this->assertEqual('3', $view->getStyle()->getField(0, 'id'));
|
||||
$this->assertEqual('1', $view->getStyle()->getField(0, 'field_test'));
|
||||
$this->assertEqual(3, $view->getStyle()->getField(1, 'id'));
|
||||
$this->assertEqual('3', $view->getStyle()->getField(1, 'id'));
|
||||
$this->assertEqual('2', $view->getStyle()->getField(1, 'field_test'));
|
||||
$this->assertEqual(1, $view->getStyle()->getField(2, 'id'));
|
||||
$this->assertEqual('1', $view->getStyle()->getField(2, 'id'));
|
||||
$this->assertEqual('3', $view->getStyle()->getField(2, 'field_test'));
|
||||
$this->assertEqual(1, $view->getStyle()->getField(3, 'id'));
|
||||
$this->assertEqual('1', $view->getStyle()->getField(3, 'id'));
|
||||
$this->assertEqual('4', $view->getStyle()->getField(3, 'field_test'));
|
||||
$this->assertEqual(1, $view->getStyle()->getField(4, 'id'));
|
||||
$this->assertEqual('1', $view->getStyle()->getField(4, 'id'));
|
||||
$this->assertEqual('5', $view->getStyle()->getField(4, 'field_test'));
|
||||
|
||||
// Check that translated values are correctly retrieved and are not grouped
|
||||
|
@ -288,7 +288,7 @@ class QueryGroupByTest extends ViewUnitTestBase {
|
|||
$this->executeView($view);
|
||||
|
||||
$this->assertEqual(6, count($view->result));
|
||||
$this->assertEqual(3, $view->getStyle()->getField(5, 'id'));
|
||||
$this->assertEqual('3', $view->getStyle()->getField(5, 'id'));
|
||||
$this->assertEqual('6', $view->getStyle()->getField(5, 'field_test'));
|
||||
}
|
||||
|
||||
|
|
|
@ -124,7 +124,11 @@ class RenderCacheIntegrationTest extends ViewUnitTestBase {
|
|||
$this->pass('Test pager');
|
||||
$this->pass('Page 1');
|
||||
\Drupal::request()->query->set('page', 0);
|
||||
$tags_page_1 = Cache::mergeTags($base_tags, $entities[1]->getCacheTags(), $entities[2]->getCacheTags(), $entities[3]->getCacheTags(), $entities[4]->getCacheTags(), $entities[5]->getCacheTags());
|
||||
$tags_page_1 = Cache::mergeTags($base_tags, $entities[1]->getCacheTags());
|
||||
$tags_page_1 = Cache::mergeTags($tags_page_1, $entities[2]->getCacheTags());
|
||||
$tags_page_1 = Cache::mergeTags($tags_page_1, $entities[3]->getCacheTags());
|
||||
$tags_page_1 = Cache::mergeTags($tags_page_1, $entities[4]->getCacheTags());
|
||||
$tags_page_1 = Cache::mergeTags($tags_page_1, $entities[5]->getCacheTags());
|
||||
$this->assertViewsCacheTags($view, $tags_page_1, $do_assert_views_caches, $tags_page_1);
|
||||
$this->assertViewsCacheTagsFromStaticRenderArray($view, $tags_page_1, $do_assert_views_caches);
|
||||
$view->destroy();
|
||||
|
@ -254,7 +258,8 @@ class RenderCacheIntegrationTest extends ViewUnitTestBase {
|
|||
$entity->save();
|
||||
|
||||
$result_tags_with_entity = Cache::mergeTags($base_tags, $entities[0]->getCacheTags());
|
||||
$render_tags_with_entity = Cache::mergeTags($base_render_tags, $entities[0]->getCacheTags(), ['entity_test_view']);
|
||||
$render_tags_with_entity = Cache::mergeTags($base_render_tags, $entities[0]->getCacheTags());
|
||||
$render_tags_with_entity = Cache::mergeTags($render_tags_with_entity, ['entity_test_view']);
|
||||
$this->assertViewsCacheTags($view, $result_tags_with_entity, $do_assert_views_caches, $render_tags_with_entity);
|
||||
$this->assertViewsCacheTagsFromStaticRenderArray($view, $render_tags_with_entity, $do_assert_views_caches);
|
||||
|
||||
|
@ -265,9 +270,13 @@ class RenderCacheIntegrationTest extends ViewUnitTestBase {
|
|||
$entity->save();
|
||||
}
|
||||
|
||||
$new_entities_cache_tags = Cache::mergeTags($entities[1]->getCacheTags(), $entities[2]->getCacheTags(), $entities[3]->getCacheTags(), $entities[4]->getCacheTags(), $entities[5]->getCacheTags());
|
||||
$new_entities_cache_tags = Cache::mergeTags($entities[1]->getCacheTags(), $entities[2]->getCacheTags());
|
||||
$new_entities_cache_tags = Cache::mergeTags($new_entities_cache_tags, $entities[3]->getCacheTags());
|
||||
$new_entities_cache_tags = Cache::mergeTags($new_entities_cache_tags, $entities[4]->getCacheTags());
|
||||
$new_entities_cache_tags = Cache::mergeTags($new_entities_cache_tags, $entities[5]->getCacheTags());
|
||||
$result_tags_page_1 = Cache::mergeTags($base_tags, $new_entities_cache_tags);
|
||||
$render_tags_page_1 = Cache::mergeTags($base_render_tags, $new_entities_cache_tags, ['entity_test_view']);
|
||||
$render_tags_page_1 = Cache::mergeTags($base_render_tags, $new_entities_cache_tags);
|
||||
$render_tags_page_1 = Cache::mergeTags($render_tags_page_1, ['entity_test_view']);
|
||||
$this->assertViewsCacheTags($view, $result_tags_page_1, $do_assert_views_caches, $render_tags_page_1);
|
||||
$this->assertViewsCacheTagsFromStaticRenderArray($view, $render_tags_page_1, $do_assert_views_caches);
|
||||
}
|
||||
|
@ -292,7 +301,7 @@ class RenderCacheIntegrationTest extends ViewUnitTestBase {
|
|||
$view = View::load('test_display');
|
||||
$view->save();
|
||||
|
||||
$this->assertEqual(['languages:' . LanguageInterface::TYPE_CONTENT, 'languages:' . LanguageInterface::TYPE_INTERFACE, 'url.query_args.pagers:0', 'user.node_grants:view', 'user.permissions'], $view->getDisplay('default')['cache_metadata']['contexts']);
|
||||
$this->assertEqual(['languages:' . LanguageInterface::TYPE_CONTENT, 'languages:' . LanguageInterface::TYPE_INTERFACE, 'url.query_args', 'user.node_grants:view', 'user.permissions'], $view->getDisplay('default')['cache_metadata']['contexts']);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
namespace Drupal\views\Tests;
|
||||
|
||||
use Drupal\Core\Render\BubbleableMetadata;
|
||||
use Drupal\views\Views;
|
||||
|
||||
/**
|
||||
|
@ -54,9 +55,25 @@ class TokenReplaceTest extends ViewUnitTestBase {
|
|||
'[view:page-count]' => '1',
|
||||
);
|
||||
|
||||
$base_bubbleable_metadata = BubbleableMetadata::createFromObject($view->storage);
|
||||
$metadata_tests = [];
|
||||
$metadata_tests['[view:label]'] = $base_bubbleable_metadata;
|
||||
$metadata_tests['[view:description]'] = $base_bubbleable_metadata;
|
||||
$metadata_tests['[view:id]'] = $base_bubbleable_metadata;
|
||||
$metadata_tests['[view:title]'] = $base_bubbleable_metadata;
|
||||
$metadata_tests['[view:url]'] = $base_bubbleable_metadata;
|
||||
$metadata_tests['[view:total-rows]'] = $base_bubbleable_metadata;
|
||||
$metadata_tests['[view:base-table]'] = $base_bubbleable_metadata;
|
||||
$metadata_tests['[view:base-field]'] = $base_bubbleable_metadata;
|
||||
$metadata_tests['[view:items-per-page]'] = $base_bubbleable_metadata;
|
||||
$metadata_tests['[view:current-page]'] = $base_bubbleable_metadata;
|
||||
$metadata_tests['[view:page-count]'] = $base_bubbleable_metadata;
|
||||
|
||||
foreach ($expected as $token => $expected_output) {
|
||||
$output = $token_handler->replace($token, array('view' => $view));
|
||||
$bubbleable_metadata = new BubbleableMetadata();
|
||||
$output = $token_handler->replace($token, array('view' => $view), [], $bubbleable_metadata);
|
||||
$this->assertIdentical($output, $expected_output, format_string('Token %token replaced correctly.', array('%token' => $token)));
|
||||
$this->assertEqual($bubbleable_metadata, $metadata_tests[$token]);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
namespace Drupal\views\Tests;
|
||||
|
||||
use Drupal\comment\Tests\CommentTestTrait;
|
||||
use Drupal\Component\Utility\Xss;
|
||||
use Drupal\views\Entity\View;
|
||||
use Drupal\views\Views;
|
||||
use Drupal\views\ViewExecutable;
|
||||
|
@ -326,7 +327,7 @@ class ViewExecutableTest extends ViewUnitTestBase {
|
|||
// Test the title methods.
|
||||
$title = $this->randomString();
|
||||
$view->setTitle($title);
|
||||
$this->assertEqual($view->getTitle(), $title);
|
||||
$this->assertEqual($view->getTitle(), Xss::filterAdmin($title));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -31,7 +31,7 @@ abstract class ViewUnitTestBase extends KernelTestBase {
|
|||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = array('system', 'views', 'views_test_config', 'views_test_data');
|
||||
public static $modules = array('system', 'views', 'views_test_config', 'views_test_data', 'user');
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
|
|
|
@ -133,6 +133,7 @@ class BasicTest extends WizardTestBase {
|
|||
|
||||
// Confirm that the block is available in the block administration UI.
|
||||
$this->drupalGet('admin/structure/block/list/' . $this->config('system.theme')->get('default'));
|
||||
$this->clickLinkPartialName('Place block');
|
||||
$this->assertText($view3['label']);
|
||||
|
||||
// Place the block.
|
||||
|
|
|
@ -71,6 +71,7 @@ class ItemsPerPageTest extends WizardTestBase {
|
|||
|
||||
// Confirm that the block is listed in the block administration UI.
|
||||
$this->drupalGet('admin/structure/block/list/' . $this->config('system.theme')->get('default'));
|
||||
$this->clickLinkPartialName('Place block');
|
||||
$this->assertText($view['label']);
|
||||
|
||||
// Place the block, visit a page that displays the block, and check that the
|
||||
|
|
|
@ -9,7 +9,6 @@ namespace Drupal\views;
|
|||
|
||||
use Drupal\Component\Utility\Html;
|
||||
use Drupal\Core\Cache\Cache;
|
||||
use Drupal\Component\Utility\SafeMarkup;
|
||||
use Drupal\Core\DependencyInjection\DependencySerializationTrait;
|
||||
use Drupal\Core\Form\FormState;
|
||||
use Drupal\Core\Routing\RouteProviderInterface;
|
||||
|
@ -1615,29 +1614,6 @@ class ViewExecutable implements \Serializable {
|
|||
$this->is_attachment = FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns menu links from the view and the named display handler.
|
||||
*
|
||||
* @param string $display_id
|
||||
* A display ID.
|
||||
*
|
||||
* @return array|bool
|
||||
* The generated menu links for this view and display, FALSE if the call
|
||||
* to ::setDisplay failed.
|
||||
*/
|
||||
public function getMenuLinks($display_id = NULL) {
|
||||
// Prepare the view with the information we have. This was probably already
|
||||
// called, but it's good to be safe.
|
||||
if (!$this->setDisplay($display_id)) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Execute the hook.
|
||||
if (isset($this->display_handler)) {
|
||||
return $this->display_handler->getMenuLinks();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the given user has access to the view. Note that
|
||||
* this sets the display handler if it hasn't been.
|
||||
|
@ -1897,7 +1873,7 @@ class ViewExecutable implements \Serializable {
|
|||
public function getUrlInfo($display_id = '') {
|
||||
$this->initDisplay();
|
||||
if (!$this->display_handler instanceof DisplayRouterInterface) {
|
||||
throw new \InvalidArgumentException(SafeMarkup::format('You cannot generate a URL for the display @display_id', ['@display_id' => $display_id]));
|
||||
throw new \InvalidArgumentException("You cannot generate a URL for the display '$display_id'");
|
||||
}
|
||||
return $this->display_handler->getUrlInfo();
|
||||
}
|
||||
|
|
|
@ -7,10 +7,13 @@
|
|||
|
||||
namespace Drupal\views_test_data\Cache;
|
||||
|
||||
use Drupal\Core\Cache\CacheableMetadata;
|
||||
use Drupal\Core\Cache\Context\CacheContextInterface;
|
||||
|
||||
/**
|
||||
* Test cache context which uses a dynamic context coming from state.
|
||||
*
|
||||
* Cache context ID: 'views_test_cache_context'.
|
||||
*/
|
||||
class ViewsTestCacheContext implements CacheContextInterface {
|
||||
|
||||
|
@ -28,4 +31,11 @@ class ViewsTestCacheContext implements CacheContextInterface {
|
|||
return \Drupal::state()->get('views_test_cache_context', 'George');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getCacheableMetadata() {
|
||||
return new CacheableMetadata();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -7,11 +7,13 @@
|
|||
|
||||
namespace Drupal\Tests\views\Unit\Controller {
|
||||
|
||||
use Drupal\Core\Render\RenderContext;
|
||||
use Drupal\Tests\UnitTestCase;
|
||||
use Drupal\views\Ajax\ViewAjaxResponse;
|
||||
use Drupal\views\Controller\ViewAjaxController;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\HttpFoundation\RequestStack;
|
||||
|
||||
/**
|
||||
* @coversDefaultClass \Drupal\views\Controller\ViewAjaxController
|
||||
|
@ -76,6 +78,11 @@ class ViewAjaxControllerTest extends UnitTestCase {
|
|||
$elements['#attached'] = [];
|
||||
return isset($elements['#markup']) ? $elements['#markup'] : '';
|
||||
}));
|
||||
$this->renderer->expects($this->any())
|
||||
->method('executeInRenderContext')
|
||||
->willReturnCallback(function (RenderContext $context, callable $callable) {
|
||||
return $callable();
|
||||
});
|
||||
$this->currentPath = $this->getMockBuilder('Drupal\Core\Path\CurrentPathStack')
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
|
@ -83,8 +90,23 @@ class ViewAjaxControllerTest extends UnitTestCase {
|
|||
|
||||
$this->viewAjaxController = new ViewAjaxController($this->viewStorage, $this->executableFactory, $this->renderer, $this->currentPath, $this->redirectDestination);
|
||||
|
||||
$request_stack = new RequestStack();
|
||||
$request_stack->push(new Request());
|
||||
$args = [
|
||||
$this->getMock('\Drupal\Core\Controller\ControllerResolverInterface'),
|
||||
$this->getMock('\Drupal\Core\Theme\ThemeManagerInterface'),
|
||||
$this->getMock('\Drupal\Core\Render\ElementInfoManagerInterface'),
|
||||
$this->getMock('\Drupal\Core\Render\RenderCacheInterface'),
|
||||
$request_stack,
|
||||
[
|
||||
'required_cache_contexts' => [
|
||||
'languages:language_interface',
|
||||
'theme',
|
||||
],
|
||||
],
|
||||
];
|
||||
$this->renderer = $this->getMockBuilder('Drupal\Core\Render\Renderer')
|
||||
->disableOriginalConstructor()
|
||||
->setConstructorArgs($args)
|
||||
->setMethods(NULL)
|
||||
->getMock();
|
||||
$container = new ContainerBuilder();
|
||||
|
|
|
@ -168,20 +168,12 @@ class FieldPluginBaseTest extends UnitTestCase {
|
|||
* Sets up the unrouted url assembler and the link generator.
|
||||
*/
|
||||
protected function setUpUrlIntegrationServices() {
|
||||
$config = $this->getMockBuilder('Drupal\Core\Config\ImmutableConfig')
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
$config_factory = $this->getMock('\Drupal\Core\Config\ConfigFactoryInterface');
|
||||
$config_factory->expects($this->any())
|
||||
->method('get')
|
||||
->willReturn($config);
|
||||
|
||||
$this->pathProcessor = $this->getMock('Drupal\Core\PathProcessor\OutboundPathProcessorInterface');
|
||||
$this->unroutedUrlAssembler = new UnroutedUrlAssembler($this->requestStack, $config_factory, $this->pathProcessor);
|
||||
$this->unroutedUrlAssembler = new UnroutedUrlAssembler($this->requestStack, $this->pathProcessor);
|
||||
|
||||
\Drupal::getContainer()->set('unrouted_url_assembler', $this->unroutedUrlAssembler);
|
||||
|
||||
$this->linkGenerator = new LinkGenerator($this->urlGenerator, $this->getMock('Drupal\Core\Extension\ModuleHandlerInterface'));
|
||||
$this->linkGenerator = new LinkGenerator($this->urlGenerator, $this->getMock('Drupal\Core\Extension\ModuleHandlerInterface'), $this->renderer);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -453,6 +445,7 @@ class FieldPluginBaseTest extends UnitTestCase {
|
|||
'#type' => 'inline_template',
|
||||
'#template' => 'base:test-path/' . explode('/', $path)[1],
|
||||
'#context' => ['foo' => 123],
|
||||
'#post_render' => [function() {}],
|
||||
];
|
||||
|
||||
$this->renderer->expects($this->once())
|
||||
|
|
|
@ -13,7 +13,6 @@ use Drupal\views\Routing\ViewPageController;
|
|||
use Symfony\Cmf\Component\Routing\RouteObjectInterface;
|
||||
use Symfony\Component\HttpFoundation\ParameterBag;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Session\Attribute\AttributeBag;
|
||||
use Symfony\Component\Routing\Route;
|
||||
|
||||
/**
|
||||
|
@ -29,20 +28,6 @@ class ViewPageControllerTest extends UnitTestCase {
|
|||
*/
|
||||
public $pageController;
|
||||
|
||||
/**
|
||||
* The mocked view storage.
|
||||
*
|
||||
* @var \Drupal\views\ViewStorage|\PHPUnit_Framework_MockObject_MockObject
|
||||
*/
|
||||
protected $storage;
|
||||
|
||||
/**
|
||||
* The mocked view executable factory.
|
||||
*
|
||||
* @var \Drupal\views\ViewExecutableFactory|\PHPUnit_Framework_MockObject_MockObject
|
||||
*/
|
||||
protected $executableFactory;
|
||||
|
||||
/**
|
||||
* A render array expected for every page controller render array result.
|
||||
*
|
||||
|
@ -56,23 +41,13 @@ class ViewPageControllerTest extends UnitTestCase {
|
|||
];
|
||||
|
||||
protected function setUp() {
|
||||
$this->storage = $this->getMockBuilder('Drupal\Core\Config\Entity\ConfigEntityStorage')
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
$this->executableFactory = $this->getMockBuilder('Drupal\views\ViewExecutableFactory')
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
|
||||
$this->pageController = new ViewPageController($this->storage, $this->executableFactory);
|
||||
$this->pageController = new ViewPageController();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the page controller.
|
||||
*/
|
||||
public function testPageController() {
|
||||
$this->storage->expects($this->never())
|
||||
->method('load');
|
||||
|
||||
$build = [
|
||||
'#type' => 'view',
|
||||
'#name' => 'test_page_view',
|
||||
|
@ -102,9 +77,6 @@ class ViewPageControllerTest extends UnitTestCase {
|
|||
* Tests the page controller with arguments on a non overridden page view.
|
||||
*/
|
||||
public function testHandleWithArgumentsWithoutOverridden() {
|
||||
$this->storage->expects($this->never())
|
||||
->method('load');
|
||||
|
||||
$request = new Request();
|
||||
$request->attributes->set('view_id', 'test_page_view');
|
||||
$request->attributes->set('display_id', 'page_1');
|
||||
|
@ -139,9 +111,6 @@ class ViewPageControllerTest extends UnitTestCase {
|
|||
* Note: This test does not care about upcasting for now.
|
||||
*/
|
||||
public function testHandleWithArgumentsOnOverriddenRoute() {
|
||||
$this->storage->expects($this->never())
|
||||
->method('load');
|
||||
|
||||
$request = new Request();
|
||||
$request->attributes->set('view_id', 'test_page_view');
|
||||
$request->attributes->set('display_id', 'page_1');
|
||||
|
@ -179,9 +148,6 @@ class ViewPageControllerTest extends UnitTestCase {
|
|||
* are pulled in.
|
||||
*/
|
||||
public function testHandleWithArgumentsOnOverriddenRouteWithUpcasting() {
|
||||
$this->storage->expects($this->never())
|
||||
->method('load');
|
||||
|
||||
$request = new Request();
|
||||
$request->attributes->set('view_id', 'test_page_view');
|
||||
$request->attributes->set('display_id', 'page_1');
|
||||
|
|
|
@ -494,7 +494,9 @@ function template_preprocess_views_view_table(&$variables) {
|
|||
'attributes' => array('title' => $title),
|
||||
'query' => $query,
|
||||
);
|
||||
$variables['header'][$field]['content'] = \Drupal::l($label, new Url('<current>', [], $link_options));
|
||||
// It is ok to specify no URL path here as we will always reload the
|
||||
// current page.
|
||||
$variables['header'][$field]['content'] = \Drupal::l($label, new Url('<none>', [], $link_options));
|
||||
}
|
||||
|
||||
$variables['header'][$field]['default_classes'] = $fields[$field]->options['element_default_classes'];
|
||||
|
@ -1050,6 +1052,10 @@ function template_preprocess_views_mini_pager(&$variables) {
|
|||
}
|
||||
$variables['items']['next']['attributes'] = new Attribute();
|
||||
}
|
||||
|
||||
// This is is based on the entire current query string. We need to ensure
|
||||
// cacheability is affected accordingly.
|
||||
$variables['#cache']['contexts'][] = 'url.query_args';
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
*/
|
||||
|
||||
use Drupal\Component\Utility\SafeMarkup;
|
||||
use Drupal\Core\Render\BubbleableMetadata;
|
||||
|
||||
/**
|
||||
* Implements hook_token_info().
|
||||
|
@ -68,9 +69,7 @@ function views_token_info() {
|
|||
/**
|
||||
* Implements hook_tokens().
|
||||
*/
|
||||
function views_tokens($type, $tokens, array $data = array(), array $options = array()) {
|
||||
$token_service = \Drupal::token();
|
||||
|
||||
function views_tokens($type, $tokens, array $data, array $options, BubbleableMetadata $bubbleable_metadata) {
|
||||
$url_options = array('absolute' => TRUE);
|
||||
if (isset($options['language'])) {
|
||||
$url_options['language'] = $options['language'];
|
||||
|
@ -83,6 +82,8 @@ function views_tokens($type, $tokens, array $data = array(), array $options = ar
|
|||
/** @var \Drupal\views\ViewExecutable $view */
|
||||
$view = $data['view'];
|
||||
|
||||
$bubbleable_metadata->addCacheableDependency($view->storage);
|
||||
|
||||
foreach ($tokens as $name => $original) {
|
||||
switch ($name) {
|
||||
case 'label':
|
||||
|
@ -104,7 +105,8 @@ function views_tokens($type, $tokens, array $data = array(), array $options = ar
|
|||
|
||||
case 'url':
|
||||
if ($url = $view->getUrl()) {
|
||||
$replacements[$original] = $url->setOptions($url_options)->toString();
|
||||
$replacements[$original] = $url->setOptions($url_options)
|
||||
->toString();
|
||||
}
|
||||
break;
|
||||
case 'base-table':
|
||||
|
@ -129,13 +131,6 @@ function views_tokens($type, $tokens, array $data = array(), array $options = ar
|
|||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// [view:url:*] nested tokens. This only works if Token module is installed.
|
||||
if ($url_tokens = $token_service->findWithPrefix($tokens, 'url')) {
|
||||
if ($path = $view->getUrl()) {
|
||||
$replacements += $token_service->generate('url', $url_tokens, array('path' => $url->getInternalPath()), $options);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $replacements;
|
||||
|
|
Reference in a new issue