TwigPhpStorageCache.php 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. <?php
  2. namespace Drupal\Core\Template;
  3. use Drupal\Component\Utility\Crypt;
  4. use Drupal\Core\Cache\CacheBackendInterface;
  5. use Drupal\Core\PhpStorage\PhpStorageFactory;
  6. /**
  7. * Provides an alternate cache storage for Twig using PhpStorage.
  8. *
  9. * This class is designed to work on setups with multiple webheads using a local
  10. * filesystem for the twig cache. When generating the cache key, a hash value
  11. * depending on the enabled extensions is included. This prevents stale
  12. * templates from being reused when twig extensions are enabled or disabled.
  13. *
  14. * @see \Drupal\Core\DependencyInjection\Compiler\TwigExtensionPass
  15. */
  16. class TwigPhpStorageCache implements \Twig_CacheInterface {
  17. /**
  18. * The maximum length for each part of the cache key suffix.
  19. */
  20. const SUFFIX_SUBSTRING_LENGTH = 25;
  21. /**
  22. * The cache object used for auto-refresh via mtime.
  23. *
  24. * @var \Drupal\Core\Cache\CacheBackendInterface
  25. */
  26. protected $cache;
  27. /**
  28. * The PhpStorage object used for storing the templates.
  29. *
  30. * @var \Drupal\Component\PhpStorage\PhpStorageInterface
  31. */
  32. protected $storage;
  33. /**
  34. * The template cache filename prefix.
  35. *
  36. * @var string
  37. */
  38. protected $templateCacheFilenamePrefix;
  39. /**
  40. * Store cache backend and other information internally.
  41. *
  42. * @param \Drupal\Core\Cache\CacheBackendInterface $cache
  43. * The cache bin.
  44. * @param string $twig_cache_prefix
  45. * A Twig cache file prefix that changes when Twig extensions change.
  46. */
  47. public function __construct(CacheBackendInterface $cache, $twig_cache_prefix) {
  48. $this->cache = $cache;
  49. $this->templateCacheFilenamePrefix = $twig_cache_prefix;
  50. }
  51. /**
  52. * Gets the PHP code storage object to use for the compiled Twig files.
  53. *
  54. * @return \Drupal\Component\PhpStorage\PhpStorageInterface
  55. */
  56. protected function storage() {
  57. if (!isset($this->storage)) {
  58. $this->storage = PhpStorageFactory::get('twig');
  59. }
  60. return $this->storage;
  61. }
  62. /**
  63. * {@inheritdoc}
  64. */
  65. public function generateKey($name, $className) {
  66. if (strpos($name, '{# inline_template_start #}') === 0) {
  67. // $name is an inline template, and can have characters that are not valid
  68. // for a filename. $suffix is unique for each inline template so we just
  69. // use the generic name 'inline-template' here.
  70. $name = 'inline-template';
  71. }
  72. else {
  73. $name = basename($name);
  74. }
  75. // Windows (and some encrypted Linux systems) only support 255 characters in
  76. // a path. On Windows a requirements error is displayed and installation is
  77. // blocked if Drupal's public files path is longer than 120 characters.
  78. // Thus, to always be less than 255, file paths may not be more than 135
  79. // characters long. Using the default PHP file storage class, the Twig cache
  80. // file path will be 124 characters long at most, which provides a margin of
  81. // safety.
  82. $suffix = substr($name, 0, self::SUFFIX_SUBSTRING_LENGTH) . '_';
  83. $suffix .= substr(Crypt::hashBase64($className), 0, self::SUFFIX_SUBSTRING_LENGTH);
  84. // The cache prefix is what gets invalidated.
  85. return $this->templateCacheFilenamePrefix . '_' . $suffix;
  86. }
  87. /**
  88. * {@inheritdoc}
  89. */
  90. public function load($key) {
  91. $this->storage()->load($key);
  92. }
  93. /**
  94. * {@inheritdoc}
  95. */
  96. public function write($key, $content) {
  97. $this->storage()->save($key, $content);
  98. // Save the last mtime.
  99. $cid = 'twig:' . $key;
  100. $this->cache->set($cid, REQUEST_TIME);
  101. }
  102. /**
  103. * {@inheritdoc}
  104. */
  105. public function getTimestamp($key) {
  106. $cid = 'twig:' . $key;
  107. if ($cache = $this->cache->get($cid)) {
  108. return $cache->data;
  109. }
  110. else {
  111. return 0;
  112. }
  113. }
  114. }