diff --git a/core/modules/views/src/Form/ViewsForm.php b/core/modules/views/src/Form/ViewsForm.php index cdf39eb..4951777 100644 --- a/core/modules/views/src/Form/ViewsForm.php +++ b/core/modules/views/src/Form/ViewsForm.php @@ -14,6 +14,7 @@ use Drupal\Core\Form\FormInterface; use Drupal\Core\Form\FormStateInterface; use Drupal\Core\Routing\UrlGeneratorInterface; +use Drupal\Core\Url; use Drupal\views\ViewExecutable; use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\HttpFoundation\RequestStack; diff --git a/core/modules/views/src/Plugin/views/PluginBase.php b/core/modules/views/src/Plugin/views/PluginBase.php index 4d252e2..e3467c4 100644 --- a/core/modules/views/src/Plugin/views/PluginBase.php +++ b/core/modules/views/src/Plugin/views/PluginBase.php @@ -326,117 +326,14 @@ public function usesOptions() { } /** - * {@inheritdoc} - */ - public function globalTokenReplace($string = '', array $options = array()) { - return \Drupal::token()->replace($string, array('view' => $this->view), $options); - } - - /** - * 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. * - * 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 }}) + * @see \Drupal\views\TokenParser::viewsTokenReplace() * - * @param $text - * String with possible tokens. - * @param $tokens - * Array of token => replacement_value items. - * - * @return String + * @todo Remove this wrapper. */ protected function viewsTokenReplace($text, $tokens) { - if (empty($tokens)) { - return $text; - } - - // Separate Twig tokens from other tokens (e.g.: contextual filter tokens in - // the form of %1). - $twig_tokens = array(); - $other_tokens = array(); - foreach ($tokens as $token => $replacement) { - if (strpos($token, '{{') !== FALSE) { - // Twig wants a token replacement array stripped of curly-brackets. - $token = trim(str_replace(array('{', '}'), '', $token)); - $twig_tokens[$token] = $replacement; - } - else { - $other_tokens[$token] = $replacement; - } - } - - // 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)) { - $build = array( - '#type' => 'inline_template', - '#template' => $text, - '#context' => $twig_tokens, - ); - - return $this->getRenderer()->render($build); - } - else { - return $text; - } - } - - /** - * {@inheritdoc} - */ - public function getAvailableGlobalTokens($prepared = FALSE, array $types = array()) { - $info = \Drupal::token()->getInfo(); - // Site and view tokens should always be available. - $types += array('site', 'view'); - $available = array_intersect_key($info['tokens'], array_flip($types)); - - // Construct the token string for each token. - if ($prepared) { - $prepared = array(); - foreach ($available as $type => $tokens) { - foreach (array_keys($tokens) as $token) { - $prepared[$type][] = "[$type:$token]"; - } - } - - return $prepared; - } - - return $available; - } - - /** - * {@inheritdoc} - */ - public function globalTokenForm(&$form, FormStateInterface $form_state) { - $token_items = array(); - - foreach ($this->getAvailableGlobalTokens() as $type => $tokens) { - $item = array( - '#markup' => $type, - 'children' => array(), - ); - foreach ($tokens as $name => $info) { - $item['children'][$name] = "[$type:$name]" . ' - ' . $info['name'] . ': ' . $info['description']; - } - - $token_items[$type] = $item; - } - - $form['global_tokens'] = array( - '#type' => 'details', - '#title' => $this->t('Available global token replacements'), - ); - $form['global_tokens']['list'] = array( - '#theme' => 'item_list', - '#items' => $token_items, - '#attributes' => array( - 'class' => array('global-tokens'), - ), - ); + return $this->view->getTokenParser()->viewsTokenReplace($text, $tokens); } /** diff --git a/core/modules/views/src/Plugin/views/ViewsPluginInterface.php b/core/modules/views/src/Plugin/views/ViewsPluginInterface.php index d36b4b2..007241d 100644 --- a/core/modules/views/src/Plugin/views/ViewsPluginInterface.php +++ b/core/modules/views/src/Plugin/views/ViewsPluginInterface.php @@ -96,31 +96,6 @@ public function init(ViewExecutable $view, DisplayPluginBase $display, array &$o public function submitOptionsForm(&$form, FormStateInterface $form_state); /** - * Adds elements for available core tokens to a form. - * - * @param array $form - * The form array to alter, passed by reference. - * @param \Drupal\Core\Form\FormStateInterface $form_state - * The current state of the form. - */ - public function globalTokenForm(&$form, FormStateInterface $form_state); - - /** - * Returns an array of available token replacements. - * - * @param bool $prepared - * Whether to return the raw token info for each token or an array of - * prepared tokens for each type. E.g. "[view:name]". - * @param array $types - * An array of additional token types to return, defaults to 'site' and - * 'view'. - * - * @return array - * An array of available token replacement info or tokens, grouped by type. - */ - public function getAvailableGlobalTokens($prepared = FALSE, array $types = array()); - - /** * Flattens the structure of form elements. * * If a form element has #flatten = TRUE, then all of it's children get moved @@ -136,19 +111,6 @@ public function getAvailableGlobalTokens($prepared = FALSE, array $types = array public static function preRenderFlattenData($form); /** - * Returns a string with any core tokens replaced. - * - * @param string $string - * The string to preform the token replacement on. - * @param array $options - * An array of options, as passed to \Drupal\Core\Utility\Token::replace(). - * - * @return string - * The tokenized string. - */ - public function globalTokenReplace($string = '', array $options = array()); - - /** * Clears a plugin. */ public function destroy(); diff --git a/core/modules/views/src/Plugin/views/area/Title.php b/core/modules/views/src/Plugin/views/area/Title.php index 8843324..93ea0a4 100644 --- a/core/modules/views/src/Plugin/views/area/Title.php +++ b/core/modules/views/src/Plugin/views/area/Title.php @@ -41,7 +41,7 @@ public function buildOptionsForm(&$form, FormStateInterface $form_state) { ); // Don't use the AreaPluginBase tokenForm method, we don't want row tokens. - $this->globalTokenForm($form, $form_state); + $this->view->getTokenParser()->globalTokenForm($form, $form_state); } /** @@ -52,7 +52,7 @@ public function preRender(array $results) { // If a title is provided, process it. if (!empty($this->options['title'])) { - $value = $this->globalTokenReplace($this->options['title']); + $value = $this->view->getTokenParser()->globalTokenReplace($this->options['title']); $this->view->setTitle($this->sanitizeValue($value, 'xss_admin')); } } diff --git a/core/modules/views/src/Plugin/views/area/TokenizeAreaPluginBase.php b/core/modules/views/src/Plugin/views/area/TokenizeAreaPluginBase.php index 82bb51d..6317f89 100644 --- a/core/modules/views/src/Plugin/views/area/TokenizeAreaPluginBase.php +++ b/core/modules/views/src/Plugin/views/area/TokenizeAreaPluginBase.php @@ -42,6 +42,8 @@ public function buildOptionsForm(&$form, FormStateInterface $form_state) { /** * Adds tokenization form elements. + * + * @todo This needs an update for https://www.drupal.org/node/2342287. */ public function tokenForm(&$form, FormStateInterface $form_state) { $form['tokenize'] = array( @@ -91,7 +93,7 @@ public function tokenForm(&$form, FormStateInterface $form_state) { } } - $this->globalTokenForm($form, $form_state); + $this->view->getTokenParser()->globalTokenForm($form, $form_state); } /** @@ -109,7 +111,7 @@ public function tokenizeValue($value) { $value = $this->view->getStyle()->tokenizeValue($value, 0); } // As we add the globalTokenForm() we also should replace the token here. - return $this->globalTokenReplace($value); + return $this->view->getTokenParser()->globalTokenReplace($value); } } diff --git a/core/modules/views/src/Plugin/views/display/DisplayPluginBase.php b/core/modules/views/src/Plugin/views/display/DisplayPluginBase.php index 5a4bda2..6d785f0 100644 --- a/core/modules/views/src/Plugin/views/display/DisplayPluginBase.php +++ b/core/modules/views/src/Plugin/views/display/DisplayPluginBase.php @@ -1047,7 +1047,7 @@ public function optionLink($text, $section, $class = '', $title = '') { /** * {@inheritdoc} */ - public function getArgumentsTokens() { + public function getArgumentTokens() { $tokens = array(); if (!empty($this->view->build_info['substitutions'])) { $tokens = $this->view->build_info['substitutions']; @@ -1059,9 +1059,9 @@ public function getArgumentsTokens() { if (!isset($tokens["%$count"])) { $tokens["%$count"] = ''; } - // Use strip tags as there should never be HTML in the path. - // However, we need to preserve special characters like " that - // were removed by String::checkPlain(). + // Use strip tags as there should never be HTML in the path. + // However, we need to preserve special characters like " that + // were removed by String::checkPlain(). $tokens["!$count"] = isset($this->view->args[$count - 1]) ? strip_tags(String::decodeEntities($this->view->args[$count - 1])) : ''; } @@ -2081,7 +2081,7 @@ public function renderMoreLink() { // If the user has supplied a custom "More" link path, replace any // argument tokens and use that for the URL. if ($this->getOption('link_display') == 'custom_url' && $override_path = $this->getOption('link_url')) { - $tokens = $this->getArgumentsTokens(); + $tokens = $this->getArgumentTokens(); $path = $this->viewsTokenReplace($override_path, $tokens); // @todo Views should expect and store a leading /. See: // https://www.drupal.org/node/2423913 diff --git a/core/modules/views/src/Plugin/views/display/DisplayPluginInterface.php b/core/modules/views/src/Plugin/views/display/DisplayPluginInterface.php index 2c9da2b..41fa008 100644 --- a/core/modules/views/src/Plugin/views/display/DisplayPluginInterface.php +++ b/core/modules/views/src/Plugin/views/display/DisplayPluginInterface.php @@ -316,7 +316,7 @@ public function optionLink($text, $section, $class = '', $title = ''); * This function is similar to views_handler_field::getRenderTokens() * but without fields tokens. */ - public function getArgumentsTokens(); + public function getArgumentTokens(); /** * Provides the default summary for options in the views UI. diff --git a/core/modules/views/src/Plugin/views/field/FieldPluginBase.php b/core/modules/views/src/Plugin/views/field/FieldPluginBase.php index 3089c39..0ab5ae6 100644 --- a/core/modules/views/src/Plugin/views/field/FieldPluginBase.php +++ b/core/modules/views/src/Plugin/views/field/FieldPluginBase.php @@ -332,7 +332,7 @@ public function elementClasses($row_index = NULL) { * {@inheritdoc} */ public function tokenizeValue($value, $row_index = NULL) { - if (strpos($value, '{{') !== FALSE || strpos($value, '!') !== FALSE || strpos($value, '%') !== FALSE) { + if ($this->view->getTokenParser()->hasRenderToken($value) || $this->view->getTokenParser()->hasArgumentToken($value)) { $fake_item = array( 'alter_text' => TRUE, 'text' => $value, @@ -1495,22 +1495,7 @@ protected function renderAsLink($alter, $text, $tokens) { * {@inheritdoc} */ public function getRenderTokens($item) { - $tokens = array(); - if (!empty($this->view->build_info['substitutions'])) { - $tokens = $this->view->build_info['substitutions']; - } - $count = 0; - foreach ($this->displayHandler->getHandlers('argument') as $arg => $handler) { - $token = '%' . ++$count; - if (!isset($tokens[$token])) { - $tokens[$token] = ''; - } - - // Use strip tags as there should never be HTML in the path. - // However, we need to preserve special characters like " that - // were removed by String::checkPlain(). - $tokens['!' . $count] = isset($this->view->args[$count - 1]) ? strip_tags(String::decodeEntities($this->view->args[$count - 1])) : ''; - } + $tokens = $this->view->display_handler->getArgumentTokens(); // Get flattened set of tokens for any array depth in query parameters. if ($request = $this->view->getRequest()) { diff --git a/core/modules/views/src/Plugin/views/style/StylePluginBase.php b/core/modules/views/src/Plugin/views/style/StylePluginBase.php index 360b717..4933749 100644 --- a/core/modules/views/src/Plugin/views/style/StylePluginBase.php +++ b/core/modules/views/src/Plugin/views/style/StylePluginBase.php @@ -184,20 +184,6 @@ function usesFields() { } /** - * Return TRUE if this style uses tokens. - * - * Used to ensure we don't fetch tokens when not needed for performance. - */ - public function usesTokens() { - if ($this->usesRowClass()) { - $class = $this->options['row_class']; - if (strpos($class, '{{') !== FALSE || strpos($class, '!') !== FALSE || strpos($class, '%') !== FALSE) { - return TRUE; - } - } - } - - /** * Return TRUE if this style enables field labels by default. * * @return bool @@ -228,14 +214,14 @@ public function getRowClass($row_index) { * Take a value and apply token replacement logic to it. */ public function tokenizeValue($value, $row_index) { - if (strpos($value, '{{') !== FALSE || strpos($value, '!') !== FALSE || strpos($value, '%') !== FALSE) { + if ($this->view->getTokenParser()->hasArgumentToken($value) || $this->view->getTokenParser()->hasRenderToken($value)) { // Row tokens might be empty, for example for node row style. $tokens = isset($this->rowTokens[$row_index]) ? $this->rowTokens[$row_index] : array(); if (!empty($this->view->build_info['substitutions'])) { $tokens += $this->view->build_info['substitutions']; } - $value = $this->viewsTokenReplace($value, $tokens); + $value = $this->view->getTokenParser()->viewsTokenReplace($value, $tokens); } return $value; } diff --git a/core/modules/views/src/Tests/Handler/AreaTest.php b/core/modules/views/src/Tests/Handler/AreaTest.php index 03b8b57..6fa059c 100644 --- a/core/modules/views/src/Tests/Handler/AreaTest.php +++ b/core/modules/views/src/Tests/Handler/AreaTest.php @@ -170,7 +170,7 @@ public function testRenderAreaToken() { $empty_handler = &$view->empty['test_example']; // Test the list of available tokens. - $available = $empty_handler->getAvailableGlobalTokens(); + $available = $empty_handler->view->getTokenParser()->getAvailableGlobalTokens(); foreach (array('site', 'view') as $type) { $this->assertTrue(!empty($available[$type]) && is_array($available[$type])); // Test that each item exists in the list. diff --git a/core/modules/views/src/TokenParser.php b/core/modules/views/src/TokenParser.php new file mode 100644 index 0000000..661d271 --- /dev/null +++ b/core/modules/views/src/TokenParser.php @@ -0,0 +1,249 @@ +view = $view; + $this->tokenUtility = $token_utility; + } + + /** + * Returns a string with any core tokens replaced. + * + * @param string $string + * The string to preform the token replacement on. + * @param array $options + * An array of options, as passed to \Drupal\Core\Utility\Token::replace(). + * + * @return string + * The tokenized string. + */ + public function globalTokenReplace($string = '', array $options = array()) { + return $this->tokenUtility->replace($string, array('view' => $this->view), $options); + } + + /** + * Indicates whether the value has a potential Views argument token. + * + * @param string $value + * The string to check + * + * @return bool + * TRUE if the string has a potential Views argument token. + * + * @see \Drupal\views\Plugin\views\display\DisplayPluginBase::getArgumentTokens() + */ + public function hasArgumentToken($value) { + // If the string definitely does not contain a token, return FALSE + // immediately for performance. + if ((strpos($value, '!') === FALSE) && (strpos($value, '%') === FALSE)) { + return FALSE; + } + // Otherwise, scan for valid token patterns. + return preg_match('/[!%]\d+/', $value); + } + + /** + * Indicates whether the value has a potential Views row-level token. + * + * @param string $value + * The string to check + * + * @return bool + * TRUE if the string has a potential row token. + * + * @see \Drupal\views\Plugin\views\field\FieldPluginBase::getRenderTokens() + */ + public function hasRenderToken($value) { + // If the string definitely does not contain a token, return FALSE + // immediately for performance. + if (strpos($value, '{{') === FALSE) { + return FALSE; + } + // Otherwise, scan for valid token patterns. + // Match any non-empty string between {{ and }} except another {{. + return preg_match('/\{\{[^(\{\{)]+\}\}/', $value); + } + + /** + * Indicates whether the value has a potential Views token. + * + * @param string $value + * The string to check + * + * @return bool + * TRUE if the string has any token pattern. + */ + public function hasToken($value) { + return ($this->hasArgumentToken($value) || $this->hasRenderToken($value)); + } + + /** + * Replaces Views' tokens in a given string. + * + * It is the responsibility of the calling function to ensure $text and + * $token replacements are sanitized. + * + * @param $text + * String with possible tokens. + * @param $tokens + * Array of token => replacement_value items. + * + * @return String + * The text with the tokens replaced. + * + * @see \Drupal\views\TokenParser::hasToken() + * @see \Drupal\views\Plugin\views\display\DisplayPluginBase::getArgumentTokens() + * @see \Drupal\views\Plugin\views\field\FieldPluginBase::getRenderTokens() + */ + public function viewsTokenReplace($text, $tokens) { + if (empty($tokens)) { + return $text; + } + + // Separate Twig tokens from other tokens (e.g.: contextual filter tokens in + // the form of %1). + $twig_tokens = array(); + $other_tokens = array(); + foreach ($tokens as $token => $replacement) { + if ($this->hasRenderToken($token)) { + // Twig wants a token replacement array stripped of curly-brackets. + // @todo Do this with the regex instead. + $token = trim(str_replace(array('{', '}'), '', $token)); + $twig_tokens[$token] = $replacement; + } + else { + $other_tokens[$token] = $replacement; + } + } + + // 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) { + $build = array( + '#type' => 'inline_template', + '#template' => $text, + '#context' => $twig_tokens, + ); + return drupal_render($build); + } + else { + return $text; + } + } + + /** + * {@inheritdoc} + */ + public function getAvailableGlobalTokens($prepared = FALSE, array $types = array()) { + $info = $this->tokenUtility->getInfo(); + // Site and view tokens should always be available. + $types += array('site', 'view'); + $available = array_intersect_key($info['tokens'], array_flip($types)); + + // Construct the token string for each token. + if ($prepared) { + $prepared = array(); + foreach ($available as $type => $tokens) { + foreach (array_keys($tokens) as $token) { + $prepared[$type][] = "[$type:$token]"; + } + } + + return $prepared; + } + + return $available; + } + + /** + * Adds elements for available core tokens to a form. + * + * @param array $form + * The form array to alter, passed by reference. + * @param \Drupal\Core\Form\FormStateInterface $form_state + * The current state of the form. + */ + public function globalTokenForm(&$form, FormStateInterface $form_state) { + $token_items = array(); + + foreach ($this->getAvailableGlobalTokens() as $type => $tokens) { + $item = array( + '#markup' => $type, + 'children' => array(), + ); + foreach ($tokens as $name => $info) { + $item['children'][$name] = "[$type:$name]" . ' - ' . $info['name'] . ': ' . $info['description']; + } + + $token_items[$type] = $item; + } + + $form['global_tokens'] = array( + '#type' => 'details', + '#title' => $this->t('Available global token replacements'), + ); + $form['global_tokens']['list'] = array( + '#theme' => 'item_list', + '#items' => $token_items, + '#attributes' => array( + 'class' => array('global-tokens'), + ), + ); + } + +} diff --git a/core/modules/views/src/ViewExecutable.php b/core/modules/views/src/ViewExecutable.php index 11dce89..3c01adc 100644 --- a/core/modules/views/src/ViewExecutable.php +++ b/core/modules/views/src/ViewExecutable.php @@ -13,10 +13,10 @@ use Drupal\Core\Form\FormState; use Drupal\Core\Routing\RouteProviderInterface; use Drupal\Core\Session\AccountInterface; -use Drupal\Core\Url; -use Drupal\views\Plugin\views\display\DisplayRouterInterface; +use Drupal\Core\Utility\Token; use Drupal\views\Plugin\views\query\QueryPluginBase; use Drupal\views\ViewEntityInterface; +use Drupal\views\Plugin\views\display\DisplayRouterInterface; use Drupal\Component\Utility\Tags; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; @@ -429,11 +429,18 @@ class ViewExecutable implements \Serializable { protected $viewsData; /** - * The route provider. + * The global token utility. + * + * @var \Drupal\Core\Utility\TokenUtility + */ + protected $tokenUtility; + + /** + * The token parser for the view. * - * @var \Drupal\Core\Routing\RouteProviderInterface + * @var \Drupal\views\TokenParser */ - protected $routeProvider; + protected $tokenParser; /** * Constructs a new ViewExecutable object. @@ -446,17 +453,21 @@ class ViewExecutable implements \Serializable { * The views data. * @param \Drupal\Core\Routing\RouteProviderInterface $route_provider * The route provider. + * @param \Drupal\Core\Utility\Token $token_utility + * The global token utility. */ - public function __construct(ViewEntityInterface $storage, AccountInterface $user, ViewsData $views_data, RouteProviderInterface $route_provider) { + public function __construct(ViewEntityInterface $storage, AccountInterface $user, ViewsData $views_data, RouteProviderInterface $route_provider, Token $token_utility) { // Reference the storage and the executable to each other. $this->storage = $storage; $this->storage->set('executable', $this); $this->user = $user; $this->viewsData = $views_data; $this->routeProvider = $route_provider; + $this->tokenUtility = $token_utility; // Add the default css for a view. $this->element['#attached']['library'][] = 'views/views.module'; + $this->tokenParser = new TokenParser($this, $this->tokenUtility); } /** @@ -486,6 +497,16 @@ public function setArguments($args) { } /** + * Returns the view's token parser. + * + * @return \Drupal\views\TokenParser + * The token parser for the view. + */ + public function getTokenParser() { + return $this->tokenParser; + } + + /** * Change/Set the current page for the pager. */ public function setCurrentPage($page) { @@ -1923,7 +1944,7 @@ public function destroy() { $defaults = $reflection->getDefaultProperties(); // The external dependencies should not be reset. This is not generated by // the execution of a view. - unset($defaults['storage'], $defaults['user'], $defaults['request'], $defaults['routeProvider']); + unset($defaults['storage'], $defaults['user'], $defaults['request'], $defaults['routeProvider'], $defaults['tokenUtility'], $defaults['tokenParser']); foreach ($defaults as $property => $default) { $this->{$property} = $default; diff --git a/core/modules/views/src/ViewExecutableFactory.php b/core/modules/views/src/ViewExecutableFactory.php index 0975a48..8f9a479 100644 --- a/core/modules/views/src/ViewExecutableFactory.php +++ b/core/modules/views/src/ViewExecutableFactory.php @@ -9,6 +9,7 @@ use Drupal\Core\Routing\RouteProviderInterface; use Drupal\Core\Session\AccountInterface; +use Drupal\Core\Utility\Token; use Drupal\views\ViewEntityInterface; use Symfony\Component\HttpFoundation\RequestStack; @@ -46,6 +47,13 @@ class ViewExecutableFactory { protected $routeProvider; /** + * The global token utility. + * + * @var \Drupal\Core\Utility\Token + */ + protected $tokenUtility; + + /** * Constructs a new ViewExecutableFactory * * @param \Drupal\Core\Session\AccountInterface $user @@ -56,12 +64,15 @@ class ViewExecutableFactory { * The views data. * @param \Drupal\Core\Routing\RouteProviderInterface $route_provider * The route provider. + * @param \Drupal\Core\Utility\Token $token_utility + * The token utility. */ - public function __construct(AccountInterface $user, RequestStack $request_stack, ViewsData $views_data, RouteProviderInterface $route_provider) { + public function __construct(AccountInterface $user, RequestStack $request_stack, ViewsData $views_data, RouteProviderInterface $route_provider, Token $token_utility) { $this->user = $user; $this->requestStack = $request_stack; $this->viewsData = $views_data; $this->routeProvider = $route_provider; + $this->tokenUtility = $token_utility; } /** @@ -74,7 +85,7 @@ public function __construct(AccountInterface $user, RequestStack $request_stack, * A ViewExecutable instance. */ public function get(ViewEntityInterface $view) { - $view = new ViewExecutable($view, $this->user, $this->viewsData, $this->routeProvider); + $view = new ViewExecutable($view, $this->user, $this->viewsData, $this->routeProvider, $this->tokenUtility); $view->setRequest($this->requestStack->getCurrentRequest()); return $view; } diff --git a/core/modules/views/tests/modules/views_test_data/src/Plugin/views/area/TestExample.php b/core/modules/views/tests/modules/views_test_data/src/Plugin/views/area/TestExample.php index 1bcf2f4..f048480 100644 --- a/core/modules/views/tests/modules/views_test_data/src/Plugin/views/area/TestExample.php +++ b/core/modules/views/tests/modules/views_test_data/src/Plugin/views/area/TestExample.php @@ -43,7 +43,7 @@ public function defineOptions() { */ public function buildOptionsForm(&$form, FormStateInterface $form_state) { parent::buildOptionsForm($form, $form_state); - $this->globalTokenForm($form, $form_state); + $this->view->getTokenParser()->globalTokenForm($form, $form_state); } /** @@ -52,7 +52,7 @@ public function buildOptionsForm(&$form, FormStateInterface $form_state) { public function render($empty = FALSE) { if (!$empty || !empty($this->options['empty'])) { return array( - '#markup' => $this->globalTokenReplace($this->options['string']), + '#markup' => $this->view->getTokenParser()->globalTokenReplace($this->options['string']), ); } return array(); diff --git a/core/modules/views/tests/src/Unit/Plugin/area/ResultTest.php b/core/modules/views/tests/src/Unit/Plugin/area/ResultTest.php index 87c79a3d..4a89a3f 100644 --- a/core/modules/views/tests/src/Unit/Plugin/area/ResultTest.php +++ b/core/modules/views/tests/src/Unit/Plugin/area/ResultTest.php @@ -47,7 +47,10 @@ protected function setUp() { ->disableOriginalConstructor() ->getMock(); $route_provider = $this->getMock('Drupal\Core\Routing\RouteProviderInterface'); - $this->view = new ViewExecutable($storage, $user, $views_data, $route_provider); + $token_utility = $this->getMockBuilder('Drupal\Core\Utility\Token') + ->disableOriginalConstructor() + ->getMock(); + $this->view = new ViewExecutable($storage, $user, $views_data, $route_provider, $token_utility); $this->resultHandler = new Result(array(), 'result', array()); $this->resultHandler->view = $this->view; diff --git a/core/modules/views/tests/src/Unit/Plugin/field/CounterTest.php b/core/modules/views/tests/src/Unit/Plugin/field/CounterTest.php index 7b0c14d..b3b0ddd 100644 --- a/core/modules/views/tests/src/Unit/Plugin/field/CounterTest.php +++ b/core/modules/views/tests/src/Unit/Plugin/field/CounterTest.php @@ -76,7 +76,10 @@ protected function setUp() { ->disableOriginalConstructor() ->getMock(); $route_provider = $this->getMock('Drupal\Core\Routing\RouteProviderInterface'); - $this->view = $this->getMock('Drupal\views\ViewExecutable', NULL, array($storage, $user, $views_data, $route_provider)); + $token_utility = $this->getMockBuilder('Drupal\Core\Utility\Token') + ->disableOriginalConstructor() + ->getMock(); + $this->view = $this->getMock('Drupal\views\ViewExecutable', NULL, array($storage, $user, $views_data, $route_provider, $token_utility)); $this->display = $this->getMockBuilder('Drupal\views\Plugin\views\display\DisplayPluginBase') ->disableOriginalConstructor() diff --git a/core/modules/views/tests/src/Unit/PluginBaseTest.php b/core/modules/views/tests/src/Unit/PluginBaseTest.php index 4da75f4..daa1669 100644 --- a/core/modules/views/tests/src/Unit/PluginBaseTest.php +++ b/core/modules/views/tests/src/Unit/PluginBaseTest.php @@ -316,5 +316,4 @@ public function providerTestFilterByDefinedOptions() { return $data; } - } diff --git a/core/modules/views/tests/src/Unit/ViewExecutableFactoryTest.php b/core/modules/views/tests/src/Unit/ViewExecutableFactoryTest.php index 17b61c8..4b73fe2 100644 --- a/core/modules/views/tests/src/Unit/ViewExecutableFactoryTest.php +++ b/core/modules/views/tests/src/Unit/ViewExecutableFactoryTest.php @@ -61,6 +61,13 @@ class ViewExecutableFactoryTest extends UnitTestCase { protected $routeProvider; /** + * The global token utility. + * + * @var \Drupal\Core\Utility\Token + */ + protected $tokenUtility; + + /** * {@inheritdoc} */ protected function setUp() { @@ -72,8 +79,11 @@ protected function setUp() { $this->viewsData = $this->getMockBuilder('Drupal\views\ViewsData') ->disableOriginalConstructor() ->getMock(); + $this->tokenUtility = $this->getMockBuilder('Drupal\Core\Utility\Token') + ->disableOriginalConstructor() + ->getMock(); $this->routeProvider = $this->getMock('Drupal\Core\Routing\RouteProviderInterface'); - $this->viewExecutableFactory = new ViewExecutableFactory($this->user, $this->requestStack, $this->viewsData, $this->routeProvider); + $this->viewExecutableFactory = new ViewExecutableFactory($this->user, $this->requestStack, $this->viewsData, $this->routeProvider, $this->tokenUtility); } /** diff --git a/core/modules/views/tests/src/Unit/ViewExecutableTest.php b/core/modules/views/tests/src/Unit/ViewExecutableTest.php index 59fa23a..edb9725 100644 --- a/core/modules/views/tests/src/Unit/ViewExecutableTest.php +++ b/core/modules/views/tests/src/Unit/ViewExecutableTest.php @@ -77,6 +77,13 @@ class ViewExecutableTest extends UnitTestCase { protected $routeProvider; /** + * The global token utility. + * + * @var \Drupal\Core\Utility\Token + */ + protected $tokenUtility; + + /** * {@inheritdoc} */ protected function setUp() { @@ -94,8 +101,11 @@ protected function setUp() { $this->displayHandlers = $this->getMockBuilder('Drupal\views\DisplayPluginCollection') ->disableOriginalConstructor() ->getMock(); + $this->tokenUtility = $this->getMockBuilder('Drupal\Core\Utility\Token') + ->disableOriginalConstructor() + ->getMock(); - $this->executable = new ViewExecutable($this->view, $this->user, $this->viewsData, $this->routeProvider); + $this->executable = new ViewExecutable($this->view, $this->user, $this->viewsData, $this->routeProvider, $this->tokenUtility); $this->executable->display_handler = $this->displayHandler; $this->executable->displayHandlers = $this->displayHandlers; @@ -448,7 +458,7 @@ protected function setupBaseViewAndDisplay() { ); $storage = new View($config, 'view'); - $view = new ViewExecutable($storage, $this->user, $this->viewsData, $this->routeProvider); + $view = new ViewExecutable($storage, $this->user, $this->viewsData, $this->routeProvider, $this->tokenUtility); $display = $this->getMockBuilder('Drupal\views\Plugin\views\display\DisplayPluginBase') ->disableOriginalConstructor() ->getMock(); diff --git a/core/modules/views/tests/src/Unit/ViewsTest.php b/core/modules/views/tests/src/Unit/ViewsTest.php index aa7a8c9..f520418 100644 --- a/core/modules/views/tests/src/Unit/ViewsTest.php +++ b/core/modules/views/tests/src/Unit/ViewsTest.php @@ -35,7 +35,10 @@ protected function setUp() { ->disableOriginalConstructor() ->getMock(); $route_provider = $this->getMock('Drupal\Core\Routing\RouteProviderInterface'); - $container->set('views.executable', new ViewExecutableFactory($user, $request_stack, $views_data, $route_provider)); + $token_utility = $this->getMockBuilder('Drupal\Core\Utility\Token') + ->disableOriginalConstructor() + ->getMock(); + $container->set('views.executable', new ViewExecutableFactory($user, $request_stack, $views_data, $route_provider, $token_utility)); $this->view = new View(array('id' => 'test_view'), 'view'); diff --git a/core/modules/views/views.services.yml b/core/modules/views/views.services.yml index 1a01543..29f776a 100644 --- a/core/modules/views/views.services.yml +++ b/core/modules/views/views.services.yml @@ -64,7 +64,7 @@ services: arguments: ['@views.views_data'] views.executable: class: Drupal\views\ViewExecutableFactory - arguments: ['@current_user', '@request_stack', '@views.views_data', '@router.route_provider'] + arguments: ['@current_user', '@request_stack', '@views.views_data', '@router.route_provider', '@token'] views.analyzer: class: Drupal\views\Analyzer arguments: ['@module_handler'] diff --git a/core/modules/views/views.theme.inc b/core/modules/views/views.theme.inc index a9b6295..3c0aaa3 100644 --- a/core/modules/views/views.theme.inc +++ b/core/modules/views/views.theme.inc @@ -326,7 +326,7 @@ function template_preprocess_views_view_summary(&$variables) { if (!empty($argument->options['summary_options']['base_path'])) { $base_path = $argument->options['summary_options']['base_path']; - $tokens = $this->getArgumentsTokens(); + $tokens = $this->getArgumentTokens(); $base_path = $this->viewsTokenReplace($base_path, $tokens); // @todo Views should expect and store a leading /. See: // https://www.drupal.org/node/2423913 @@ -395,7 +395,7 @@ function template_preprocess_views_view_summary_unformatted(&$variables) { if (!empty($argument->options['summary_options']['base_path'])) { $base_path = $argument->options['summary_options']['base_path']; - $tokens = $this->getArgumentsTokens(); + $tokens = $this->getArgumentTokens(); $base_path = $this->viewsTokenReplace($base_path, $tokens); // @todo Views should expect and store a leading /. See: // https://www.drupal.org/node/2423913 diff --git a/core/modules/views_ui/tests/src/Unit/ViewListBuilderTest.php b/core/modules/views_ui/tests/src/Unit/ViewListBuilderTest.php index a42a879..68f78dc 100644 --- a/core/modules/views_ui/tests/src/Unit/ViewListBuilderTest.php +++ b/core/modules/views_ui/tests/src/Unit/ViewListBuilderTest.php @@ -126,7 +126,10 @@ public function testBuildRowEntityList() { ->disableOriginalConstructor() ->getMock(); $route_provider = $this->getMock('Drupal\Core\Routing\RouteProviderInterface'); - $executable_factory = new ViewExecutableFactory($user, $request_stack, $views_data, $route_provider); + $token = $this->getMockBuilder('Drupal\Core\Utility\Token') + ->disableOriginalConstructor() + ->getMock(); + $executable_factory = new ViewExecutableFactory($user, $request_stack, $views_data, $route_provider, $token); $container->set('views.executable', $executable_factory); $container->set('plugin.manager.views.display', $display_manager); \Drupal::setContainer($container);