diff --git a/composer.lock b/composer.lock index 9ed6128219..4c5ad97215 100644 --- a/composer.lock +++ b/composer.lock @@ -2479,31 +2479,32 @@ }, { "name": "twig/twig", - "version": "v1.35.4", + "version": "v2.6.2", "source": { "type": "git", "url": "https://github.com/twigphp/Twig.git", - "reference": "7e081e98378a1e78c29cc9eba4aefa5d78a05d2a" + "reference": "7d7342c8a4059fefb9b8d07db0cc14007021f9b7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/twigphp/Twig/zipball/7e081e98378a1e78c29cc9eba4aefa5d78a05d2a", - "reference": "7e081e98378a1e78c29cc9eba4aefa5d78a05d2a", + "url": "https://api.github.com/repos/twigphp/Twig/zipball/7d7342c8a4059fefb9b8d07db0cc14007021f9b7", + "reference": "7d7342c8a4059fefb9b8d07db0cc14007021f9b7", "shasum": "" }, "require": { - "php": ">=5.3.3", - "symfony/polyfill-ctype": "^1.8" + "php": "^7.0", + "symfony/polyfill-ctype": "^1.8", + "symfony/polyfill-mbstring": "^1.3" }, "require-dev": { "psr/container": "^1.0", "symfony/debug": "^2.7", - "symfony/phpunit-bridge": "^3.3" + "symfony/phpunit-bridge": "^3.4.19|^4.1.8" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.35-dev" + "dev-master": "2.6-dev" } }, "autoload": { @@ -2541,7 +2542,7 @@ "keywords": [ "templating" ], - "time": "2018-07-13T07:12:17+00:00" + "time": "2019-01-14T15:00:48+00:00" }, { "name": "typo3/phar-stream-wrapper", diff --git a/core/composer.json b/core/composer.json index 7964dee573..0daa4f5539 100644 --- a/core/composer.json +++ b/core/composer.json @@ -32,7 +32,7 @@ "symfony/polyfill-iconv": "^1.0", "symfony/yaml": "~3.4.5", "typo3/phar-stream-wrapper": "^2.0.1", - "twig/twig": "^1.35.0", + "twig/twig": "^1.35.0|^2.4.0", "doctrine/common": "^2.5", "doctrine/annotations": "^1.2", "guzzlehttp/guzzle": "^6.2.1", diff --git a/core/lib/Drupal/Core/Template/TwigEnvironment.php b/core/lib/Drupal/Core/Template/TwigEnvironment.php index 59f2005490..426234459b 100644 --- a/core/lib/Drupal/Core/Template/TwigEnvironment.php +++ b/core/lib/Drupal/Core/Template/TwigEnvironment.php @@ -36,6 +36,11 @@ class TwigEnvironment extends \Twig_Environment { */ protected $templateClasses; + /** + * The template cache filename prefix. + * + * @var string + */ protected $twigCachePrefix = ''; /** @@ -55,7 +60,7 @@ class TwigEnvironment extends \Twig_Environment { * @param array $options * The options for the Twig environment. */ - public function __construct($root, CacheBackendInterface $cache, $twig_extension_hash, StateInterface $state, \Twig_LoaderInterface $loader = NULL, $options = []) { + public function __construct($root, CacheBackendInterface $cache, $twig_extension_hash, StateInterface $state, \Twig_LoaderInterface $loader = NULL, array $options = []) { $this->state = $state; // Ensure that twig.engine is loaded, given that it is needed to render a @@ -73,11 +78,6 @@ public function __construct($root, CacheBackendInterface $cache, $twig_extension ]; // Ensure autoescaping is always on. $options['autoescape'] = 'html'; - - $policy = new TwigSandboxPolicy(); - $sandbox = new \Twig_Extension_Sandbox($policy, TRUE); - $this->addExtension($sandbox); - if ($options['cache'] === TRUE) { $current = $state->get(static::CACHE_PREFIX_METADATA_KEY, ['twig_extension_hash' => '']); if ($current['twig_extension_hash'] !== $twig_extension_hash || empty($current['twig_cache_prefix'])) { @@ -94,8 +94,11 @@ public function __construct($root, CacheBackendInterface $cache, $twig_extension $options['cache'] = new TwigPhpStorageCache($cache, $this->twigCachePrefix); } - $this->loader = $loader; - parent::__construct($this->loader, $options); + $this->setLoader($loader); + parent::__construct($this->getLoader(), $options); + $policy = new TwigSandboxPolicy(); + $sandbox = new \Twig_Extension_Sandbox($policy, TRUE); + $this->addExtension($sandbox); } /** @@ -106,7 +109,6 @@ public function __construct($root, CacheBackendInterface $cache, $twig_extension public function invalidate() { PhpStorageFactory::get('twig')->deleteAll(); $this->templateClasses = []; - $this->loadedTemplates = []; $this->state->delete(static::CACHE_PREFIX_METADATA_KEY); } @@ -138,7 +140,7 @@ public function getTemplateClass($name, $index = NULL) { // node.html.twig for the output of each node and the same compiled class. $cache_index = $name . (NULL === $index ? '' : '_' . $index); if (!isset($this->templateClasses[$cache_index])) { - $this->templateClasses[$cache_index] = $this->templateClassPrefix . hash('sha256', $this->loader->getCacheKey($name)) . (NULL === $index ? '' : '_' . $index); + $this->templateClasses[$cache_index] = parent::getTemplateClass($name, $index); } return $this->templateClasses[$cache_index]; } @@ -168,7 +170,7 @@ public function getTemplateClass($name, $index = NULL) { public function renderInline($template_string, array $context = []) { // Prefix all inline templates with a special comment. $template_string = '{# inline_template_start #}' . $template_string; - return Markup::create($this->loadTemplate($template_string, NULL)->render($context)); + return Markup::create($this->createTemplate($template_string)->render($context)); } } diff --git a/core/lib/Drupal/Core/Template/TwigTransTokenParser.php b/core/lib/Drupal/Core/Template/TwigTransTokenParser.php index 96f55607f3..a7c0c785d2 100644 --- a/core/lib/Drupal/Core/Template/TwigTransTokenParser.php +++ b/core/lib/Drupal/Core/Template/TwigTransTokenParser.php @@ -54,15 +54,21 @@ public function parse(\Twig_Token $token) { /** * Detect a 'plural' switch or the end of a 'trans' tag. + * + * @param \Twig_Token $token + * The token to check to detect the start of subparsing. */ - public function decideForFork($token) { + public function decideForFork(\Twig_Token $token) { return $token->test(['plural', 'endtrans']); } /** * Detect the end of a 'trans' tag. + * + * @param \Twig_Token $token + * The token to check to detect the end of a 'trans' tag. */ - public function decideForEnd($token) { + public function decideForEnd(\Twig_Token $token) { return $token->test('endtrans'); } diff --git a/core/modules/system/tests/modules/twig_loader_test/src/Loader/TestLoader.php b/core/modules/system/tests/modules/twig_loader_test/src/Loader/TestLoader.php index 7937daa14d..bd23809e26 100644 --- a/core/modules/system/tests/modules/twig_loader_test/src/Loader/TestLoader.php +++ b/core/modules/system/tests/modules/twig_loader_test/src/Loader/TestLoader.php @@ -2,10 +2,21 @@ namespace Drupal\twig_loader_test\Loader; +use Twig\Source; + /** * A test Twig loader. */ -class TestLoader implements \Twig_LoaderInterface, \Twig_ExistsLoaderInterface { +class TestLoader implements \Twig_LoaderInterface, \Twig_ExistsLoaderInterface, \Twig_SourceContextLoaderInterface { + + /** + * {@inheritdoc} + */ + public function getSourceContext($name) { + $name = (string) $name; + $value = $this->getSource($name); + return new Source($value, $name); + } /** * {@inheritdoc} diff --git a/core/tests/Drupal/KernelTests/Core/Theme/TwigEnvironmentTest.php b/core/tests/Drupal/KernelTests/Core/Theme/TwigEnvironmentTest.php index 1aaf40c4e0..0b0273fe02 100644 --- a/core/tests/Drupal/KernelTests/Core/Theme/TwigEnvironmentTest.php +++ b/core/tests/Drupal/KernelTests/Core/Theme/TwigEnvironmentTest.php @@ -216,7 +216,7 @@ public function testTemplateInvalidation() { // Manually change $templateClassPrefix to force a different template // classname, as the other class is still loaded. This wouldn't be a problem // on a real site where you reload the page. - $reflection = new \ReflectionClass($environment); + $reflection = new \ReflectionClass('\Twig_Environment'); $property_reflection = $reflection->getProperty('templateClassPrefix'); $property_reflection->setAccessible(TRUE); $property_reflection->setValue($environment, 'otherPrefix'); diff --git a/core/tests/Drupal/Tests/Core/Template/TwigExtensionTest.php b/core/tests/Drupal/Tests/Core/Template/TwigExtensionTest.php index 6cfb562d25..f255e4c907 100644 --- a/core/tests/Drupal/Tests/Core/Template/TwigExtensionTest.php +++ b/core/tests/Drupal/Tests/Core/Template/TwigExtensionTest.php @@ -331,7 +331,8 @@ public function testRenderVarWithGeneratedLink() { * @covers ::createAttribute */ public function testCreateAttribute() { - $loader = new StringLoader(); + $name = '__string_template_test_1__'; + $loader = new \Twig_Loader_Array([$name => "{% for iteration in iterations %}{% endfor %}"]); $twig = new \Twig_Environment($loader); $twig->addExtension($this->systemUnderTest); @@ -340,12 +341,15 @@ public function testCreateAttribute() { ['id' => 'puppies', 'data-value' => 'foo', 'data-lang' => 'en'], [], ]; - $result = $twig->render("{% for iteration in iterations %}{% endfor %}", ['iterations' => $iterations]); + $result = $twig->render($name, ['iterations' => $iterations]); $expected = '
'; $this->assertEquals($expected, $result); // Test default creation of empty attribute object and using its method. - $result = $twig->render(""); + $name = '__string_template_test_2__'; + $loader = new \Twig_Loader_Array([$name => ""]); + $twig->setLoader($loader); + $result = $twig->render($name); $expected = '
'; $this->assertEquals($expected, $result); }