Chris@0: state = $state; Chris@17: Chris@0: // Ensure that twig.engine is loaded, given that it is needed to render a Chris@0: // template because functions like TwigExtension::escapeFilter() are called. Chris@18: // @todo remove in Drupal 9.0.0 https://www.drupal.org/node/3011393. Chris@0: require_once $root . '/core/themes/engines/twig/twig.engine'; Chris@0: Chris@0: $this->templateClasses = []; Chris@0: Chris@0: $options += [ Chris@0: // @todo Ensure garbage collection of expired files. Chris@0: 'cache' => TRUE, Chris@0: 'debug' => FALSE, Chris@0: 'auto_reload' => NULL, Chris@0: ]; Chris@0: // Ensure autoescaping is always on. Chris@0: $options['autoescape'] = 'html'; Chris@0: if ($options['cache'] === TRUE) { Chris@17: $current = $state->get(static::CACHE_PREFIX_METADATA_KEY, ['twig_extension_hash' => '']); Chris@0: if ($current['twig_extension_hash'] !== $twig_extension_hash || empty($current['twig_cache_prefix'])) { Chris@0: $current = [ Chris@0: 'twig_extension_hash' => $twig_extension_hash, Chris@0: // Generate a new prefix which invalidates any existing cached files. Chris@0: 'twig_cache_prefix' => uniqid(), Chris@0: Chris@0: ]; Chris@17: $state->set(static::CACHE_PREFIX_METADATA_KEY, $current); Chris@0: } Chris@0: $this->twigCachePrefix = $current['twig_cache_prefix']; Chris@0: Chris@0: $options['cache'] = new TwigPhpStorageCache($cache, $this->twigCachePrefix); Chris@0: } Chris@0: Chris@18: $this->setLoader($loader); Chris@18: parent::__construct($this->getLoader(), $options); Chris@18: $policy = new TwigSandboxPolicy(); Chris@18: $sandbox = new \Twig_Extension_Sandbox($policy, TRUE); Chris@18: $this->addExtension($sandbox); Chris@0: } Chris@0: Chris@0: /** Chris@17: * Invalidates all compiled Twig templates. Chris@17: * Chris@17: * @see \drupal_flush_all_caches Chris@17: */ Chris@17: public function invalidate() { Chris@17: PhpStorageFactory::get('twig')->deleteAll(); Chris@17: $this->templateClasses = []; Chris@17: $this->state->delete(static::CACHE_PREFIX_METADATA_KEY); Chris@17: } Chris@17: Chris@17: /** Chris@0: * Get the cache prefixed used by \Drupal\Core\Template\TwigPhpStorageCache Chris@0: * Chris@0: * @return string Chris@0: * The file cache prefix, or empty string if the cache is disabled. Chris@0: */ Chris@0: public function getTwigCachePrefix() { Chris@0: return $this->twigCachePrefix; Chris@0: } Chris@0: Chris@0: /** Chris@0: * Gets the template class associated with the given string. Chris@0: * Chris@0: * @param string $name Chris@0: * The name for which to calculate the template class name. Chris@0: * @param int $index Chris@0: * The index if it is an embedded template. Chris@0: * Chris@0: * @return string Chris@0: * The template class name. Chris@0: */ Chris@0: public function getTemplateClass($name, $index = NULL) { Chris@0: // We override this method to add caching because it gets called multiple Chris@0: // times when the same template is used more than once. For example, a page Chris@0: // rendering 50 nodes without any node template overrides will use the same Chris@0: // node.html.twig for the output of each node and the same compiled class. Chris@0: $cache_index = $name . (NULL === $index ? '' : '_' . $index); Chris@0: if (!isset($this->templateClasses[$cache_index])) { Chris@18: $this->templateClasses[$cache_index] = parent::getTemplateClass($name, $index); Chris@0: } Chris@0: return $this->templateClasses[$cache_index]; Chris@0: } Chris@0: Chris@0: /** Chris@0: * Renders a twig string directly. Chris@0: * Chris@0: * Warning: You should use the render element 'inline_template' together with Chris@0: * the #template attribute instead of this method directly. Chris@0: * On top of that you have to ensure that the template string is not dynamic Chris@0: * but just an ordinary static php string, because there may be installations Chris@0: * using read-only PHPStorage that want to generate all possible twig Chris@0: * templates as part of a build step. So it is important that an automated Chris@0: * script can find the templates and extract them. This is only possible if Chris@0: * the template is a regular string. Chris@0: * Chris@0: * @param string $template_string Chris@0: * The template string to render with placeholders. Chris@0: * @param array $context Chris@0: * An array of parameters to pass to the template. Chris@0: * Chris@0: * @return \Drupal\Component\Render\MarkupInterface|string Chris@0: * The rendered inline template as a Markup object. Chris@0: * Chris@0: * @see \Drupal\Core\Template\Loader\StringLoader::exists() Chris@0: */ Chris@0: public function renderInline($template_string, array $context = []) { Chris@0: // Prefix all inline templates with a special comment. Chris@0: $template_string = '{# inline_template_start #}' . $template_string; Chris@18: return Markup::create($this->createTemplate($template_string)->render($context)); Chris@0: } Chris@0: Chris@0: }