From 837b829a53efd5f18aff9fc7e6dfc73513aa70c6 Mon Sep 17 00:00:00 2001
From: catch <catch@35733.no-reply.drupal.org>
Date: Wed, 5 Jan 2022 11:17:42 +0000
Subject: [PATCH] =?UTF-8?q?Issue=20#3094493=20by=20longwave,=20G=C3=A1bor?=
 =?UTF-8?q?=20Hojtsy,=20alexpott,=20naveen433,=20Chi,=20catch,=20andypost,?=
 =?UTF-8?q?=20Krzysztof=20Doma=C5=84ski,=20shaal,=20xjm,=20fgm,=20Luke.Leb?=
 =?UTF-8?q?er,=20daffie,=20Berdir,=20Fabianx,=20effulgentsia:=20Upgrade=20?=
 =?UTF-8?q?to=20Twig=203?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 composer.lock                                 | 24 ++++------
 .../Metapackage/CoreRecommended/composer.json |  2 +-
 core/composer.json                            |  2 +-
 .../Core/Template/Loader/FilesystemLoader.php |  2 +-
 .../Core/Template/Loader/StringLoader.php     |  6 +--
 .../Template/Loader/ThemeRegistryLoader.php   | 10 ++--
 .../Drupal/Core/Template/TwigEnvironment.php  |  4 +-
 .../Core/Template/TwigPhpStorageCache.php     |  8 ++--
 .../Core/Template/TwigSandboxPolicy.php       | 12 ++---
 .../help_topics/src/HelpTopicTwigLoader.php   |  2 +-
 .../tests/src/Unit/HelpTopicTwigTest.php      | 46 ++++---------------
 .../src/Loader/TestLoader.php                 |  8 ++--
 .../src/Functional/Theme/TwigLoaderTest.php   |  4 +-
 .../Core/Theme/FrontMatterTest.php            |  3 +-
 .../Core/Theme/TwigEnvironmentTest.php        |  2 +-
 .../Core/Theme/TwigWhiteListTest.php          |  2 +-
 core/themes/engines/twig/twig.engine          |  2 +-
 17 files changed, 53 insertions(+), 86 deletions(-)

diff --git a/composer.lock b/composer.lock
index 5b6777f9a78d..ca0806a233f2 100644
--- a/composer.lock
+++ b/composer.lock
@@ -452,7 +452,7 @@
             "dist": {
                 "type": "path",
                 "url": "core",
-                "reference": "25a2835ba98c19a6fa4d60089d813a81de36e5e5"
+                "reference": "7963aa1162a3808d6d854bbba38a125121839b66"
             },
             "require": {
                 "asm89/stack-cors": "^1.1",
@@ -494,7 +494,7 @@
                 "symfony/translation": "^4.4",
                 "symfony/validator": "^4.4",
                 "symfony/yaml": "^4.4.19",
-                "twig/twig": "^2.12.0",
+                "twig/twig": "^3.0",
                 "typo3/phar-stream-wrapper": "^3.1.3"
             },
             "conflict": {
@@ -651,8 +651,7 @@
             "autoload": {
                 "psr-4": {
                     "Drupal\\Core\\": "lib/Drupal/Core",
-                    "Drupal\\Component\\": "lib/Drupal/Component",
-                    "Drupal\\Driver\\": "../drivers/lib/Drupal/Driver"
+                    "Drupal\\Component\\": "lib/Drupal/Component"
                 },
                 "classmap": [
                     "lib/Drupal.php",
@@ -4284,16 +4283,16 @@
         },
         {
             "name": "twig/twig",
-            "version": "v2.14.7",
+            "version": "v3.3.7",
             "source": {
                 "type": "git",
                 "url": "https://github.com/twigphp/Twig.git",
-                "reference": "8e202327ee1ed863629de9b18a5ec70ac614d88f"
+                "reference": "8f168c6ffa3ce76d1786b3cd52275424a3fc675b"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/twigphp/Twig/zipball/8e202327ee1ed863629de9b18a5ec70ac614d88f",
-                "reference": "8e202327ee1ed863629de9b18a5ec70ac614d88f",
+                "url": "https://api.github.com/repos/twigphp/Twig/zipball/8f168c6ffa3ce76d1786b3cd52275424a3fc675b",
+                "reference": "8f168c6ffa3ce76d1786b3cd52275424a3fc675b",
                 "shasum": ""
             },
             "require": {
@@ -4308,13 +4307,10 @@
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "2.14-dev"
+                    "dev-master": "3.3-dev"
                 }
             },
             "autoload": {
-                "psr-0": {
-                    "Twig_": "lib/"
-                },
                 "psr-4": {
                     "Twig\\": "src/"
                 }
@@ -4347,7 +4343,7 @@
             ],
             "support": {
                 "issues": "https://github.com/twigphp/Twig/issues",
-                "source": "https://github.com/twigphp/Twig/tree/v2.14.7"
+                "source": "https://github.com/twigphp/Twig/tree/v3.3.7"
             },
             "funding": [
                 {
@@ -4359,7 +4355,7 @@
                     "type": "tidelift"
                 }
             ],
-            "time": "2021-09-17T08:39:54+00:00"
+            "time": "2022-01-03T21:15:37+00:00"
         },
         {
             "name": "typo3/phar-stream-wrapper",
diff --git a/composer/Metapackage/CoreRecommended/composer.json b/composer/Metapackage/CoreRecommended/composer.json
index 264055c04d96..96e100bfb060 100644
--- a/composer/Metapackage/CoreRecommended/composer.json
+++ b/composer/Metapackage/CoreRecommended/composer.json
@@ -59,7 +59,7 @@
         "symfony/validator": "v4.4.35",
         "symfony/var-dumper": "v5.4.0",
         "symfony/yaml": "v4.4.34",
-        "twig/twig": "v2.14.7",
+        "twig/twig": "v3.3.7",
         "typo3/phar-stream-wrapper": "v3.1.7"
     }
 }
diff --git a/core/composer.json b/core/composer.json
index 64078e9d8aa6..4c320a030ce9 100644
--- a/core/composer.json
+++ b/core/composer.json
@@ -33,7 +33,7 @@
         "symfony/polyfill-php80": "^1.16",
         "symfony/yaml": "^4.4.19",
         "typo3/phar-stream-wrapper": "^3.1.3",
-        "twig/twig": "^2.12.0",
+        "twig/twig": "^3.0",
         "doctrine/annotations": "^1.12",
         "guzzlehttp/guzzle": "^7.3.0",
         "laminas/laminas-feed": "^2.12",
diff --git a/core/lib/Drupal/Core/Template/Loader/FilesystemLoader.php b/core/lib/Drupal/Core/Template/Loader/FilesystemLoader.php
index 1864b3e128c4..6f4ddc11a753 100644
--- a/core/lib/Drupal/Core/Template/Loader/FilesystemLoader.php
+++ b/core/lib/Drupal/Core/Template/Loader/FilesystemLoader.php
@@ -50,7 +50,7 @@ public function __construct($paths, ModuleHandlerInterface $module_handler, Them
    * @param string $namespace
    *   (optional) A path name.
    */
-  public function addPath($path, $namespace = self::MAIN_NAMESPACE) {
+  public function addPath(string $path, string $namespace = self::MAIN_NAMESPACE): void {
     // Invalidate the cache.
     $this->cache = [];
     $this->paths[$namespace][] = rtrim($path, '/\\');
diff --git a/core/lib/Drupal/Core/Template/Loader/StringLoader.php b/core/lib/Drupal/Core/Template/Loader/StringLoader.php
index 888569e54696..5049c6a48637 100644
--- a/core/lib/Drupal/Core/Template/Loader/StringLoader.php
+++ b/core/lib/Drupal/Core/Template/Loader/StringLoader.php
@@ -40,21 +40,21 @@ public function exists($name) {
   /**
    * {@inheritdoc}
    */
-  public function getCacheKey($name) {
+  public function getCacheKey(string $name): string {
     return $name;
   }
 
   /**
    * {@inheritdoc}
    */
-  public function isFresh($name, $time) {
+  public function isFresh(string $name, int $time): bool {
     return TRUE;
   }
 
   /**
    * {@inheritdoc}
    */
-  public function getSourceContext($name) {
+  public function getSourceContext(string $name): Source {
     $name = (string) $name;
     return new Source($name, $name);
   }
diff --git a/core/lib/Drupal/Core/Template/Loader/ThemeRegistryLoader.php b/core/lib/Drupal/Core/Template/Loader/ThemeRegistryLoader.php
index 1271ef1627ec..5ac41be79b4f 100644
--- a/core/lib/Drupal/Core/Template/Loader/ThemeRegistryLoader.php
+++ b/core/lib/Drupal/Core/Template/Loader/ThemeRegistryLoader.php
@@ -38,13 +38,13 @@ public function __construct(Registry $theme_registry) {
    * @param bool $throw
    *   Whether to throw an exception when an error occurs.
    *
-   * @return string|false
-   *   The path to the template, or false if the template is not found.
+   * @return string|null
+   *   The path to the template, or NULL if the template is not found.
    *
    * @throws \Twig\Error\LoaderError
    *   Thrown if a template matching $name cannot be found.
    */
-  protected function findTemplate($name, $throw = TRUE) {
+  protected function findTemplate(string $name, bool $throw = TRUE) {
     // Allow for loading based on the Drupal theme registry.
     $hook = str_replace('.html.twig', '', strtr($name, '-', '_'));
     $theme_registry = $this->themeRegistry->getRuntime();
@@ -66,13 +66,13 @@ protected function findTemplate($name, $throw = TRUE) {
       throw new LoaderError(sprintf('Unable to find template "%s" in the Drupal theme registry.', $name));
     }
 
-    return FALSE;
+    return NULL;
   }
 
   /**
    * {@inheritdoc}
    */
-  public function getCacheKey($name) {
+  public function getCacheKey(string $name): string {
     // The parent implementation does unnecessary work that triggers
     // deprecations in PHP 8.1.
     return $this->findTemplate($name) ?: '';
diff --git a/core/lib/Drupal/Core/Template/TwigEnvironment.php b/core/lib/Drupal/Core/Template/TwigEnvironment.php
index d6db9fbbe6b2..258d9c022223 100644
--- a/core/lib/Drupal/Core/Template/TwigEnvironment.php
+++ b/core/lib/Drupal/Core/Template/TwigEnvironment.php
@@ -105,7 +105,7 @@ public function __construct($root, CacheBackendInterface $cache, $twig_extension
   /**
    * {@inheritdoc}
    */
-  public function compileSource(Source $source) {
+  public function compileSource(Source $source): string {
     // Note: always use \Drupal\Core\Serialization\Yaml here instead of the
     // "serializer.yaml" service. This allows the core serializer to utilize
     // core related functionality which isn't available as the standalone
@@ -195,7 +195,7 @@ public function getTemplateMetadata(string $name): array {
    * @return string
    *   The template class name.
    */
-  public function getTemplateClass($name, $index = NULL) {
+  public function getTemplateClass(string $name, int $index = NULL): string {
     // We override this method to add caching because it gets called multiple
     // times when the same template is used more than once. For example, a page
     // rendering 50 nodes without any node template overrides will use the same
diff --git a/core/lib/Drupal/Core/Template/TwigPhpStorageCache.php b/core/lib/Drupal/Core/Template/TwigPhpStorageCache.php
index fcffa1cd1358..7c2f44f6b752 100644
--- a/core/lib/Drupal/Core/Template/TwigPhpStorageCache.php
+++ b/core/lib/Drupal/Core/Template/TwigPhpStorageCache.php
@@ -73,7 +73,7 @@ protected function storage() {
   /**
    * {@inheritdoc}
    */
-  public function generateKey($name, $className) {
+  public function generateKey(string $name, string $className): string {
     if (strpos($name, '{# inline_template_start #}') === 0) {
       // $name is an inline template, and can have characters that are not valid
       // for a filename. $suffix is unique for each inline template so we just
@@ -101,14 +101,14 @@ public function generateKey($name, $className) {
   /**
    * {@inheritdoc}
    */
-  public function load($key) {
+  public function load(string $key): void {
     $this->storage()->load($key);
   }
 
   /**
    * {@inheritdoc}
    */
-  public function write($key, $content) {
+  public function write(string $key, string $content): void {
     $this->storage()->save($key, $content);
     // Save the last mtime.
     $cid = 'twig:' . $key;
@@ -118,7 +118,7 @@ public function write($key, $content) {
   /**
    * {@inheritdoc}
    */
-  public function getTimestamp($key) {
+  public function getTimestamp(string $key): int {
     $cid = 'twig:' . $key;
     if ($cache = $this->cache->get($cid)) {
       return $cache->data;
diff --git a/core/lib/Drupal/Core/Template/TwigSandboxPolicy.php b/core/lib/Drupal/Core/Template/TwigSandboxPolicy.php
index bdfc98cd6366..ff92b25c37bc 100644
--- a/core/lib/Drupal/Core/Template/TwigSandboxPolicy.php
+++ b/core/lib/Drupal/Core/Template/TwigSandboxPolicy.php
@@ -75,33 +75,33 @@ public function __construct() {
   /**
    * {@inheritdoc}
    */
-  public function checkSecurity($tags, $filters, $functions) {}
+  public function checkSecurity($tags, $filters, $functions): void {}
 
   /**
    * {@inheritdoc}
    */
-  public function checkPropertyAllowed($obj, $property) {}
+  public function checkPropertyAllowed($obj, $property): void {}
 
   /**
    * {@inheritdoc}
    */
-  public function checkMethodAllowed($obj, $method) {
+  public function checkMethodAllowed($obj, $method): void {
     foreach ($this->allowed_classes as $class => $key) {
       if ($obj instanceof $class) {
-        return TRUE;
+        return;
       }
     }
 
     // Return quickly for an exact match of the method name.
     if (isset($this->allowed_methods[$method])) {
-      return TRUE;
+      return;
     }
 
     // If the method name starts with an allowed prefix, allow it. Note:
     // strpos() is between 3x and 7x faster than preg_match() in this case.
     foreach ($this->allowed_prefixes as $prefix) {
       if (strpos($method, $prefix) === 0) {
-        return TRUE;
+        return;
       }
     }
 
diff --git a/core/modules/help_topics/src/HelpTopicTwigLoader.php b/core/modules/help_topics/src/HelpTopicTwigLoader.php
index cdfeaf616f42..ccf334019627 100644
--- a/core/modules/help_topics/src/HelpTopicTwigLoader.php
+++ b/core/modules/help_topics/src/HelpTopicTwigLoader.php
@@ -69,7 +69,7 @@ protected function addExtension($path) {
   /**
    * {@inheritdoc}
    */
-  public function getSourceContext($name) {
+  public function getSourceContext(string $name): Source {
     $path = $this->findTemplate($name);
 
     $contents = file_get_contents($path);
diff --git a/core/modules/help_topics/tests/src/Unit/HelpTopicTwigTest.php b/core/modules/help_topics/tests/src/Unit/HelpTopicTwigTest.php
index 13e360ccf322..8748bc709e8a 100644
--- a/core/modules/help_topics/tests/src/Unit/HelpTopicTwigTest.php
+++ b/core/modules/help_topics/tests/src/Unit/HelpTopicTwigTest.php
@@ -5,6 +5,8 @@
 use Drupal\Core\Cache\Cache;
 use Drupal\help_topics\HelpTopicTwig;
 use Drupal\Tests\UnitTestCase;
+use Twig\Template;
+use Twig\TemplateWrapper;
 
 /**
  * Unit test for the HelpTopicTwig class.
@@ -94,48 +96,16 @@ protected function getTwigMock() {
       ->disableOriginalConstructor()
       ->getMock();
 
+    $template = $this->getMockForAbstractClass(Template::class, [$twig], '', TRUE, TRUE, TRUE, ['render']);
+    $template
+      ->method('render')
+      ->willReturn(self::PLUGIN_INFORMATION['body']);
+
     $twig
       ->method('load')
-      ->willReturn(new FakeTemplateWrapper(self::PLUGIN_INFORMATION['body']));
+      ->willReturn(new TemplateWrapper($twig, $template));
 
     return $twig;
   }
 
 }
-
-/**
- * Defines a fake template class to mock \Twig\TemplateWrapper.
- *
- * We cannot use getMockBuilder() for this, because the Twig TemplateWrapper
- * class is declared "final" and cannot be mocked.
- */
-class FakeTemplateWrapper {
-
-  /**
-   * Body text to return from the render() method.
-   *
-   * @var string
-   */
-  protected $body;
-
-  /**
-   * Constructor.
-   *
-   * @param string $body
-   *   Body text to return from the render() method.
-   */
-  public function __construct($body) {
-    $this->body = $body;
-  }
-
-  /**
-   * Mocks the \Twig\TemplateWrapper render() method.
-   *
-   * @param array $context
-   *   (optional) Render context.
-   */
-  public function render(array $context = []) {
-    return $this->body;
-  }
-
-}
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 f7731d848340..b0ae55de52bb 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
@@ -13,7 +13,7 @@ class TestLoader implements LoaderInterface {
   /**
    * {@inheritdoc}
    */
-  public function getSourceContext($name) {
+  public function getSourceContext(string $name): Source {
     $name = (string) $name;
     $value = $name === 'kittens' ? 'kittens' : 'cats';
     return new Source($value, $name);
@@ -22,21 +22,21 @@ public function getSourceContext($name) {
   /**
    * {@inheritdoc}
    */
-  public function exists($name) {
+  public function exists(string $name) {
     return TRUE;
   }
 
   /**
    * {@inheritdoc}
    */
-  public function getCacheKey($name) {
+  public function getCacheKey(string $name): string {
     return $name;
   }
 
   /**
    * {@inheritdoc}
    */
-  public function isFresh($name, $time) {
+  public function isFresh(string $name, int $time): bool {
     return TRUE;
   }
 
diff --git a/core/modules/system/tests/src/Functional/Theme/TwigLoaderTest.php b/core/modules/system/tests/src/Functional/Theme/TwigLoaderTest.php
index b98fda092607..37b7558a1740 100644
--- a/core/modules/system/tests/src/Functional/Theme/TwigLoaderTest.php
+++ b/core/modules/system/tests/src/Functional/Theme/TwigLoaderTest.php
@@ -29,10 +29,10 @@ class TwigLoaderTest extends BrowserTestBase {
   public function testTwigLoaderAddition() {
     $environment = \Drupal::service('twig');
 
-    $template = $environment->loadTemplate('kittens');
+    $template = $environment->load('kittens');
     $this->assertEquals('kittens', $template->render([]), 'Passing "kittens" to the custom Twig loader returns "kittens".');
 
-    $template = $environment->loadTemplate('meow');
+    $template = $environment->load('meow');
     $this->assertEquals('cats', $template->render([]), 'Passing something other than "kittens" to the custom Twig loader returns "cats".');
   }
 
diff --git a/core/tests/Drupal/KernelTests/Core/Theme/FrontMatterTest.php b/core/tests/Drupal/KernelTests/Core/Theme/FrontMatterTest.php
index 93d55e7b9823..d33fff88fea7 100644
--- a/core/tests/Drupal/KernelTests/Core/Theme/FrontMatterTest.php
+++ b/core/tests/Drupal/KernelTests/Core/Theme/FrontMatterTest.php
@@ -8,6 +8,7 @@
 use Symfony\Component\DependencyInjection\Definition;
 use Twig\Error\Error;
 use Twig\Error\SyntaxError;
+use Twig\Loader\FilesystemLoader;
 
 /**
  * Tests Twig front matter support.
@@ -44,7 +45,7 @@ protected function setUp(): void {
   public function register(ContainerBuilder $container) {
     parent::register($container);
 
-    $definition = new Definition('Twig_Loader_Filesystem', [[sys_get_temp_dir()]]);
+    $definition = new Definition(FilesystemLoader::class, [[sys_get_temp_dir()]]);
     $definition->setPublic(TRUE);
     $container->setDefinition('twig_loader__file_system', $definition)
       ->addTag('twig.loader');
diff --git a/core/tests/Drupal/KernelTests/Core/Theme/TwigEnvironmentTest.php b/core/tests/Drupal/KernelTests/Core/Theme/TwigEnvironmentTest.php
index 783a0ec9bc26..270b4b24a58c 100644
--- a/core/tests/Drupal/KernelTests/Core/Theme/TwigEnvironmentTest.php
+++ b/core/tests/Drupal/KernelTests/Core/Theme/TwigEnvironmentTest.php
@@ -105,7 +105,7 @@ public function testTemplateNotFoundException() {
     $environment = \Drupal::service('twig');
 
     try {
-      $environment->loadTemplate('this-template-does-not-exist.html.twig')->render([]);
+      $environment->load('this-template-does-not-exist.html.twig')->render([]);
       $this->fail('Did not throw an exception as expected.');
     }
     catch (LoaderError $e) {
diff --git a/core/tests/Drupal/KernelTests/Core/Theme/TwigWhiteListTest.php b/core/tests/Drupal/KernelTests/Core/Theme/TwigWhiteListTest.php
index 11983e4868c9..a1044efb60a2 100644
--- a/core/tests/Drupal/KernelTests/Core/Theme/TwigWhiteListTest.php
+++ b/core/tests/Drupal/KernelTests/Core/Theme/TwigWhiteListTest.php
@@ -131,7 +131,7 @@ public function testWhiteListChaining() {
       'field_term' => $this->term->id(),
     ]);
     $node->save();
-    $template = $environment->loadTemplate($this->getThemePath('test_theme') . '/templates/node.html.twig');
+    $template = $environment->load($this->getThemePath('test_theme') . '/templates/node.html.twig');
     $markup = $template->render(['node' => $node]);
     $this->setRawContent($markup);
     $this->assertText('Sometimes people are just jerks');
diff --git a/core/themes/engines/twig/twig.engine b/core/themes/engines/twig/twig.engine
index bcc984a02e24..665407c79a24 100644
--- a/core/themes/engines/twig/twig.engine
+++ b/core/themes/engines/twig/twig.engine
@@ -52,7 +52,7 @@ function twig_render_template($template_file, array $variables) {
     'debug_suffix' => '',
   ];
   try {
-    $output['rendered_markup'] = $twig_service->loadTemplate($template_file)->render($variables);
+    $output['rendered_markup'] = $twig_service->load($template_file)->render($variables);
   }
   catch (RuntimeError $e) {
     // In case there is a previous exception, re-throw the previous exception,
-- 
GitLab