diff --cc core/modules/views/src/Plugin/views/PluginBase.php index ef4c141,49b7f1d..0000000 --- a/core/modules/views/src/Plugin/views/PluginBase.php +++ b/core/modules/views/src/Plugin/views/PluginBase.php @@@ -353,31 -357,30 +353,38 @@@ abstract class PluginBase extends Compo return Xss::filterAdmin($text); } - // Separate Twig tokens from other tokens (e.g.: contextual filter tokens in - // the form of %1). $twig_tokens = array(); - $other_tokens = array(); foreach ($tokens as $token => $replacement) { + // Twig wants a token replacement array stripped of curly-brackets. + // Some Views tokens come with curly-braces, others do not. + //@todo: https://www.drupal.org/node/2544392 if (strpos($token, '{{') !== FALSE) { - $token = trim(str_replace(array('{{', '}}'), '', $token)); - // Twig wants a token replacement array stripped of curly-brackets. - $token = trim(str_replace(array('{', '}'), '', $token)); ++ $token = trim(str_replace(['{{', '}}'], '', $token)); + } - // Check for arrays in Twig tokens. Internally these are passed a + ++ // Check for arrays in Twig tokens. Internally these are passed as + // dot-delimited strings, but need to be turned into associative arrays + // for parsing. - if (strpos($token, '.') !== FALSE) { ++ if (strpos($token, '.') === FALSE) { + // We need to validate tokens are valid Twig variables. Twig uses the + // same variable naming rules as PHP. + // @see http://php.net/manual/en/language.variables.basics.php + assert('preg_match(\'/^[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*$/\', $token) === 1', 'Tokens need to be valid Twig variables.'); - + $twig_tokens[$token] = $replacement; + } + else { - $other_tokens[$token] = $replacement; + $parts = explode('.', $token); + $top = array_shift($parts); ++ assert('preg_match(\'/^[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*$/\', $top) === 1', 'Tokens need to be valid Twig variables.'); + $token_array = array(array_pop($parts) => $replacement); + foreach(array_reverse($parts) as $key) { ++ assert('preg_match(\'/^[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*$/\', $key) === 1', 'Tokens need to be valid Twig variables.'); + $token_array = array($key => $token_array); + } + $twig_tokens[$top] = $token_array; } - else { - $twig_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) { // Use the unfiltered text for the Twig template, then filter the output. // Otherwise, Xss::filterAdmin could remove valid Twig syntax before the diff --cc core/modules/views/tests/modules/views_test_data/src/Plugin/views/field/FieldTest.php index 3a4f1ea,0f8feef..0000000 --- a/core/modules/views/tests/modules/views_test_data/src/Plugin/views/field/FieldTest.php +++ b/core/modules/views/tests/modules/views_test_data/src/Plugin/views/field/FieldTest.php