Loading core/lib/Drupal/Core/DependencyInjection/Compiler/TwigExtensionPass.php +3 −3 Original line number Diff line number Diff line Loading @@ -9,7 +9,7 @@ /** * Adds the twig_extension_hash parameter to the container. * * Parameter twig_extension_hash is a hash of all extension mtimes for Twig * Parameter twig_extension_hash is a crc32 hash of all extensions for Twig * template invalidation. */ class TwigExtensionPass implements CompilerPassInterface { Loading @@ -23,8 +23,8 @@ public function process(ContainerBuilder $container) { $class_name = $container->getDefinition($service_id)->getClass(); $reflection = new \ReflectionClass($class_name); // We use the class names as hash in order to invalidate on new extensions // and mtime for every time we change an existing file. $twig_extension_hash .= $class_name . filemtime($reflection->getFileName()); // and crc32 for every time we change an existing file. $twig_extension_hash .= $class_name . hash_file('crc32', $reflection->getFileName()); } $container->setParameter('twig_extension_hash', Crypt::hashBase64($twig_extension_hash)); Loading core/tests/Drupal/KernelTests/Core/Theme/TwigEnvironmentTest.php +59 −0 Original line number Diff line number Diff line Loading @@ -6,6 +6,7 @@ use Drupal\Component\Utility\Html; use Drupal\Core\DependencyInjection\ContainerBuilder; use Drupal\Core\Site\Settings; use Drupal\Core\Template\TwigEnvironment; use Drupal\Core\Template\TwigPhpStorageCache; use Drupal\KernelTests\KernelTestBase; use Symfony\Component\DependencyInjection\Definition; Loading Loading @@ -229,4 +230,62 @@ public function testTemplateInvalidation() { $this->assertEquals($template_after, $output); } /** * Test twig file prefix change. */ public function testTwigFilePrefixChange() { /** @var \Drupal\Core\Template\TwigEnvironment $environment */ $environment = \Drupal::service('twig'); $cache_prefixes = []; $cache_filenames = []; // Assume this is the service container of webserver A. $container_a = $this->container; $template_name = 'core/modules/system/templates/container.html.twig'; // Request 1 handled by webserver A. $cache_prefixes[] = \Drupal::state()->get(TwigEnvironment::CACHE_PREFIX_METADATA_KEY)['twig_cache_prefix']; $cache_filenames[] = $environment->getCache()->generateKey($template_name, $environment->getTemplateClass($template_name)); // Assume this is the service container of webserver B. // Assume that the files on the webserver B have a different mtime than // webserver A. touch('core/lib/Drupal/Core/Template/TwigExtension.php'); clearstatcache(TRUE, 'core/lib/Drupal/Core/Template/TwigExtension.php'); $container_b = \Drupal::service('kernel')->rebuildContainer(); // Request 2 handled by webserver B. \Drupal::setContainer($container_b); $environment = \Drupal::service('twig'); $cache_prefixes[] = \Drupal::state()->get(TwigEnvironment::CACHE_PREFIX_METADATA_KEY)['twig_cache_prefix']; $cache_filenames[] = $environment->getCache()->generateKey($template_name, $environment->getTemplateClass($template_name)); // Request 3 handled by webserver A. \Drupal::setContainer($container_a); $container = \Drupal::getContainer(); // Emulate twig service reconstruct on new request. $container->set('twig', NULL); $environment = $container->get('twig'); $cache_prefixes[] = \Drupal::state()->get(TwigEnvironment::CACHE_PREFIX_METADATA_KEY)['twig_cache_prefix']; $cache_filenames[] = $environment->getCache()->generateKey($template_name, $environment->getTemplateClass($template_name)); // Request 4 handled by webserver B. \Drupal::setContainer($container_b); $container = \Drupal::getContainer(); // Emulate twig service reconstruct on new request. $container->set('twig', NULL); $environment = $container->get('twig'); $cache_prefixes[] = \Drupal::state()->get(TwigEnvironment::CACHE_PREFIX_METADATA_KEY)['twig_cache_prefix']; $cache_filenames[] = $environment->getCache()->generateKey($template_name, $environment->getTemplateClass($template_name)); // The cache prefix should not have been changed, as this is stored in // state and thus shared between all (web)servers. $this->assertEquals(count(array_unique($cache_prefixes)), 1); // This also applies to twig's file cache resulting in an unlimited growth // of the cache storage directory. $this->assertEquals(count(array_unique($cache_filenames)), 1); } } Loading
core/lib/Drupal/Core/DependencyInjection/Compiler/TwigExtensionPass.php +3 −3 Original line number Diff line number Diff line Loading @@ -9,7 +9,7 @@ /** * Adds the twig_extension_hash parameter to the container. * * Parameter twig_extension_hash is a hash of all extension mtimes for Twig * Parameter twig_extension_hash is a crc32 hash of all extensions for Twig * template invalidation. */ class TwigExtensionPass implements CompilerPassInterface { Loading @@ -23,8 +23,8 @@ public function process(ContainerBuilder $container) { $class_name = $container->getDefinition($service_id)->getClass(); $reflection = new \ReflectionClass($class_name); // We use the class names as hash in order to invalidate on new extensions // and mtime for every time we change an existing file. $twig_extension_hash .= $class_name . filemtime($reflection->getFileName()); // and crc32 for every time we change an existing file. $twig_extension_hash .= $class_name . hash_file('crc32', $reflection->getFileName()); } $container->setParameter('twig_extension_hash', Crypt::hashBase64($twig_extension_hash)); Loading
core/tests/Drupal/KernelTests/Core/Theme/TwigEnvironmentTest.php +59 −0 Original line number Diff line number Diff line Loading @@ -6,6 +6,7 @@ use Drupal\Component\Utility\Html; use Drupal\Core\DependencyInjection\ContainerBuilder; use Drupal\Core\Site\Settings; use Drupal\Core\Template\TwigEnvironment; use Drupal\Core\Template\TwigPhpStorageCache; use Drupal\KernelTests\KernelTestBase; use Symfony\Component\DependencyInjection\Definition; Loading Loading @@ -229,4 +230,62 @@ public function testTemplateInvalidation() { $this->assertEquals($template_after, $output); } /** * Test twig file prefix change. */ public function testTwigFilePrefixChange() { /** @var \Drupal\Core\Template\TwigEnvironment $environment */ $environment = \Drupal::service('twig'); $cache_prefixes = []; $cache_filenames = []; // Assume this is the service container of webserver A. $container_a = $this->container; $template_name = 'core/modules/system/templates/container.html.twig'; // Request 1 handled by webserver A. $cache_prefixes[] = \Drupal::state()->get(TwigEnvironment::CACHE_PREFIX_METADATA_KEY)['twig_cache_prefix']; $cache_filenames[] = $environment->getCache()->generateKey($template_name, $environment->getTemplateClass($template_name)); // Assume this is the service container of webserver B. // Assume that the files on the webserver B have a different mtime than // webserver A. touch('core/lib/Drupal/Core/Template/TwigExtension.php'); clearstatcache(TRUE, 'core/lib/Drupal/Core/Template/TwigExtension.php'); $container_b = \Drupal::service('kernel')->rebuildContainer(); // Request 2 handled by webserver B. \Drupal::setContainer($container_b); $environment = \Drupal::service('twig'); $cache_prefixes[] = \Drupal::state()->get(TwigEnvironment::CACHE_PREFIX_METADATA_KEY)['twig_cache_prefix']; $cache_filenames[] = $environment->getCache()->generateKey($template_name, $environment->getTemplateClass($template_name)); // Request 3 handled by webserver A. \Drupal::setContainer($container_a); $container = \Drupal::getContainer(); // Emulate twig service reconstruct on new request. $container->set('twig', NULL); $environment = $container->get('twig'); $cache_prefixes[] = \Drupal::state()->get(TwigEnvironment::CACHE_PREFIX_METADATA_KEY)['twig_cache_prefix']; $cache_filenames[] = $environment->getCache()->generateKey($template_name, $environment->getTemplateClass($template_name)); // Request 4 handled by webserver B. \Drupal::setContainer($container_b); $container = \Drupal::getContainer(); // Emulate twig service reconstruct on new request. $container->set('twig', NULL); $environment = $container->get('twig'); $cache_prefixes[] = \Drupal::state()->get(TwigEnvironment::CACHE_PREFIX_METADATA_KEY)['twig_cache_prefix']; $cache_filenames[] = $environment->getCache()->generateKey($template_name, $environment->getTemplateClass($template_name)); // The cache prefix should not have been changed, as this is stored in // state and thus shared between all (web)servers. $this->assertEquals(count(array_unique($cache_prefixes)), 1); // This also applies to twig's file cache resulting in an unlimited growth // of the cache storage directory. $this->assertEquals(count(array_unique($cache_filenames)), 1); } }