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 4459ac2..fab7664 100644 --- a/core/modules/views/src/Plugin/views/field/FieldPluginBase.php +++ b/core/modules/views/src/Plugin/views/field/FieldPluginBase.php @@ -337,7 +337,7 @@ public function elementClasses($row_index = NULL) { * tokens so they will all be available. */ public function tokenizeValue($value, $row_index = NULL) { - if (strpos($value, '[') !== FALSE || strpos($value, '!') !== FALSE || strpos($value, '%') !== FALSE) { + if ($this->view->getStyle()->hasRowToken($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 aa2d8e8..542aaf3 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->hasRowToken($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'])) { @@ -244,6 +230,80 @@ public function tokenizeValue($value, $row_index) { } /** + * Indicates whether the value has a Views argument token. + * + * @param string $value + * The string to check + * + * @return bool + * TRUE if the string has a Views 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 Views row-level token. + * + * @param string $value + * The string to check + * + * @return bool + * TRUE if the string has a global token. + */ + public function hasRowToken($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 ] that does not contain [ or ]. + return preg_match('/\[[^\[\]]+\]/', $value); + } + + /** + * Indicates whether the value has a global token. + * + * @param string $value + * The string to check + * + * @return bool + * TRUE if the string has a global token. + * + * @see \Drupal\Core\Utility\Token + */ + public function hasGlobalToken($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. + $tokens = \Drupal::token()->scan($value); + return (!empty($tokens)); + } + + /** + * Indicates whether the value has a special Views token or a global token. + * + * @param string $value + * The string to check + * + * @return bool + * TRUE if the string has any token. + */ + public function hasToken($value) { + return ($this->hasArgToken($value) || $this->hasRowToken($value) || $this->hasGlobalToken($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..c16025a --- /dev/null +++ b/core/modules/views/tests/src/Unit/Plugin/style/StylePluginBaseTest.php @@ -0,0 +1,132 @@ +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('[other_token]', FALSE), + ); + } + + /** + * @covers ::hasRowToken + * @dataProvider providerHasRowToken + */ + public function testHasRowToken($value, $return) { + $this->assertEquals($this->stylePlugin->hasRowToken($value), $return); + } + + /** + * Data provider for testHasRowToken(). + * + * @return array + */ + public function providerHasRowToken() { + return array( + array('%1', FALSE), + array('!1', FALSE), + array('[', FALSE), + array(']', FALSE), + array('[]', FALSE), + array('[[]', FALSE), + array('[elephant]', TRUE), + array(' [elephant_row_token_1] ', TRUE), + ); + } + + /** + * @covers ::hasGlobalToken + * @dataProvider providerHasGlobalToken + * + * @see \Drupal\system\Tests\System\TokenScanTest + */ + public function testHasGlobalToken($value, $return) { + // @todo This needs to have Token available, and atm the whole bleeping + // Drupal class and service container as well. + //$this->assertEquals($this->stylePlugin->hasGlobalToken($value), $return); + } + + /** + * Data provider for testHasGlobalToken(). + * + * @return array + * + * @see \Drupal\system\Tests\System\TokenScanTest + */ + public function providerHasGlobalToken() { + return array( + array('%1', FALSE), + array('!1', FALSE), + array('[', FALSE), + array(']', FALSE), + array('[]', FALSE), + array('[[]', FALSE), + array('[elephant]', FALSE), + // We don't need to test too many valid patterns because the token tests + // cover that already. + array(' [some:token] ', TRUE) + ); + } + + /** + * @covers ::hasToken + */ + public function testHasToken() { + } + +} + +class TestStylePlugin extends StylePluginBase {}