diff --git a/core/modules/views/src/Plugin/views/area/TokenizeAreaPluginBase.php b/core/modules/views/src/Plugin/views/area/TokenizeAreaPluginBase.php index bf6fbf6..4da1200 100644 --- a/core/modules/views/src/Plugin/views/area/TokenizeAreaPluginBase.php +++ b/core/modules/views/src/Plugin/views/area/TokenizeAreaPluginBase.php @@ -106,7 +106,7 @@ public function tokenForm(&$form, FormStateInterface $form_state) { */ public function tokenizeValue($value) { if ($this->options['tokenize']) { - $value = $this->view->style_plugin->tokenizeValue($value, 0); + $value = $this->view->getStyle()->tokenizeValue($value, 0); } // As we add the globalTokenForm() we also should replace the token here. return $this->globalTokenReplace($value); diff --git a/core/modules/views/src/Plugin/views/field/FieldPluginBase.php b/core/modules/views/src/Plugin/views/field/FieldPluginBase.php index 74c8620..c68680e 100644 --- a/core/modules/views/src/Plugin/views/field/FieldPluginBase.php +++ b/core/modules/views/src/Plugin/views/field/FieldPluginBase.php @@ -331,7 +331,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->getStyle()->hasTwigToken($value) || $this->view->getStyle()->hasArgToken($value)) { $fake_item = array( 'alter_text' => TRUE, 'text' => $value, diff --git a/core/modules/views/src/Plugin/views/style/StylePluginBase.php b/core/modules/views/src/Plugin/views/style/StylePluginBase.php index 9c229da..c125782 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,7 +214,7 @@ 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->hasArgToken($value) || $this->hasTwigToken($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'])) { @@ -241,6 +227,58 @@ public function tokenizeValue($value, $row_index) { } /** + * 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. + */ + public function hasArgToken($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. + */ + public function hasTwigToken($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->hasArgToken($value) || $this->hasTwigToken($value)); + } + + /** * Should the output of the style plugin be rendered even if it's a empty view. */ public function evenEmpty() { diff --git a/core/modules/views/tests/src/Unit/Plugin/style/StylePluginBaseTest.php b/core/modules/views/tests/src/Unit/Plugin/style/StylePluginBaseTest.php new file mode 100644 index 0000000..445552c --- /dev/null +++ b/core/modules/views/tests/src/Unit/Plugin/style/StylePluginBaseTest.php @@ -0,0 +1,136 @@ +stylePlugin = new TestStylePlugin(array(), 'default', array()); + } + + /** + * @covers ::hasArgToken + * @dataProvider providerHasArgToken + */ + public function testHasArgToken($value, $return) { + $this->assertEquals($this->stylePlugin->hasArgToken($value), $return); + } + + /** + * Data provider for testHasArgToken(). + * + * @return array + */ + public function providerHasArgToken() { + return array( + array('%', FALSE), + array('!', FALSE), + array('!', FALSE), + array('% 1', FALSE), + array('! 1', FALSE), + array('!1', TRUE), + array('%1', TRUE), + array(' !12345 ', TRUE), + array(' %54321 ', TRUE), + array('%elephant', FALSE), + array('!elephant', FALSE), + array('[old_token]', FALSE), + array('[other:token]', FALSE), + array('{{twig_token}}', FALSE), + ); + } + + /** + * @covers ::hasTwigToken + * @dataProvider providerHasTwigToken + */ + public function testHasTwigToken($value, $return) { + $this->assertEquals($this->stylePlugin->hasTwigToken($value), $return); + } + + /** + * Data provider for testHasTwigToken(). + * + * @return array + */ + public function providerHasTwigToken() { + return array( + array('%1', FALSE), + array('!1', FALSE), + array('{', FALSE), + array('{{', FALSE), + array('}', FALSE), + array('}}', FALSE), + array('{{}}', FALSE), + array('{{{{}}', FALSE), + array('{{ elephant }}', TRUE), + array(' {{elephant_twig_token_1}} ', TRUE), + ); + } + + /** + * @covers ::hasToken + * @dataProvider providerHasToken + */ + public function testHasToken($value, $return) { + $this->assertEquals($this->stylePlugin->hasToken($value), $return); + } + + /** + * Data provider for testHasToken(). + * + * @return array + * + * @see \Drupal\system\Tests\System\TokenScanTest + */ + public function providerHasToken() { + return array( + array('%', FALSE), + array('!', FALSE), + array('!', FALSE), + array('% 1', FALSE), + array('! 1', FALSE), + array('!1', TRUE), + array('%1', TRUE), + array(' !12345 ', TRUE), + array(' %54321 ', TRUE), + array('%elephant', FALSE), + array('!elephant', FALSE), + array('{', FALSE), + array('{{', FALSE), + array('}', FALSE), + array('}}', FALSE), + array('{{}}', FALSE), + array('{{{{}}', FALSE), + array('{{ elephant }}', TRUE), + array(' {{elephant_twig_token_1}} ', TRUE), + array('[old_token]', FALSE), + array('[other:token]', FALSE), + ); + } + +} + +class TestStylePlugin extends StylePluginBase {}