TwigEnvironment.php 4.06 KB
Newer Older
1 2 3 4 5 6 7 8 9
<?php

/**
 * @file
 * Definition of Drupal\Core\Template\TwigEnvironment.
 */

namespace Drupal\Core\Template;

10 11
use Drupal\Component\PhpStorage\PhpStorageFactory;

12 13 14 15 16 17
/**
 * A class that defines a Twig environment for Drupal.
 *
 * Instances of this class are used to store the configuration and extensions,
 * and are used to load templates from the file system or other locations.
 *
18
 * @see core\vendor\twig\twig\lib\Twig\Environment.php
19 20 21 22 23
 */
class TwigEnvironment extends \Twig_Environment {
  protected $cache_object = NULL;
  protected $storage = NULL;

24 25 26 27 28 29 30
  /**
   * Static cache of template classes.
   *
   * @var array
   */
  protected $templateClasses;

31 32 33 34 35
  /**
   * Constructs a TwigEnvironment object and stores cache and storage
   * internally.
   */
  public function __construct(\Twig_LoaderInterface $loader = NULL, $options = array()) {
36
    // @todo Pass as arguments from the DIC.
37 38
    $this->cache_object = cache();

39 40
    $this->templateClasses = array();

41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59
    parent::__construct($loader, $options);
  }

  /**
   * Checks if the compiled template needs an update.
   */
  public function needsUpdate($cache_filename, $name) {
     $cid = 'twig:' . $cache_filename;
     $obj = $this->cache_object->get($cid);
     $mtime = isset($obj->data) ? $obj->data : FALSE;
     return $mtime !== FALSE && !$this->isTemplateFresh($name, $mtime);
  }

  /**
   * Compile the source and write the compiled template to disk.
   */
  public function updateCompiledTemplate($cache_filename, $name) {
    $source = $this->loader->getSource($name);
    $compiled_source = $this->compileSource($source, $name);
60
    $this->storage()->save($cache_filename, $compiled_source);
61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95
    // Save the last modification time
    $cid = 'twig:' . $cache_filename;
    $this->cache_object->set($cid, REQUEST_TIME);
  }

  /**
   * Implements Twig_Environment::loadTemplate().
   *
   * We need to overwrite this function to integrate with drupal_php_storage().
   *
   * This is a straight copy from loadTemplate() changed to use
   * drupal_php_storage().
   */
  public function loadTemplate($name, $index = NULL) {
    $cls = $this->getTemplateClass($name, $index);

    if (isset($this->loadedTemplates[$cls])) {
      return $this->loadedTemplates[$cls];
    }

    if (!class_exists($cls, FALSE)) {
      $cache_filename = $this->getCacheFilename($name);

      if ($cache_filename === FALSE) {
        $source = $this->loader->getSource($name);
        $compiled_source = $this->compileSource($source, $name);
        eval('?' . '>' . $compiled_source);
      } else {

        // If autoreload is on, check that the template has not been
        // modified since the last compilation.
        if ($this->isAutoReload() && $this->needsUpdate($cache_filename, $name)) {
          $this->updateCompiledTemplate($cache_filename, $name);
        }

96
        if (!$this->storage()->load($cache_filename)) {
97
          $this->updateCompiledTemplate($cache_filename, $name);
98
          $this->storage()->load($cache_filename);
99 100 101 102 103 104 105 106 107 108 109
        }
      }
    }

    if (!$this->runtimeInitialized) {
        $this->initRuntime();
    }

    return $this->loadedTemplates[$cls] = new $cls($this);
  }

110 111 112 113 114 115 116
  /**
   * Gets the PHP code storage object to use for the compiled Twig files.
   *
   * @return \Drupal\Component\PhpStorage\PhpStorageInterface
   */
  protected function storage() {
    if (!isset($this->storage)) {
117
      $this->storage = PhpStorageFactory::get('twig');
118 119 120 121
    }
    return $this->storage;
  }

122 123 124 125 126 127 128 129 130 131 132 133 134 135 136
  /**
   * {@inheritdoc}
   */
  public function getTemplateClass($name, $index = null) {
    // 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
    // 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] = parent::getTemplateClass($name, $index);
    }
    return $this->templateClasses[$cache_index];
  }

137
}