Update to drupal 8.0.0-rc1. For more information, see https://www.drupal.org/node/2582663
This commit is contained in:
parent
eb34d130a8
commit
f32e58e4b1
8476 changed files with 211648 additions and 170042 deletions
|
@ -7,7 +7,9 @@
|
|||
|
||||
namespace Drupal\Core\Template;
|
||||
|
||||
use Drupal\Component\Utility\SafeStringInterface;
|
||||
use Drupal\Component\Render\PlainTextOutput;
|
||||
use Drupal\Component\Utility\SafeMarkup;
|
||||
use Drupal\Component\Render\MarkupInterface;
|
||||
|
||||
/**
|
||||
* Collects, sanitizes, and renders HTML attributes.
|
||||
|
@ -39,12 +41,34 @@ use Drupal\Component\Utility\SafeStringInterface;
|
|||
* {# Produces <cat class="cat black-cat white-cat black-white-cat my-custom-class" id="socks"> #}
|
||||
* @endcode
|
||||
*
|
||||
* The attribute keys and values are automatically sanitized for output with
|
||||
* Html::escape() and the entire attribute string is marked safe for output.
|
||||
* The attribute keys and values are automatically escaped for output with
|
||||
* Html::escape(). No protocol filtering is applied, so when using user-entered
|
||||
* input as a value for an attribute that expects an URI (href, src, ...),
|
||||
* UrlHelper::stripDangerousProtocols() should be used to ensure dangerous
|
||||
* protocols (such as 'javascript:') are removed. For example:
|
||||
* @code
|
||||
* $path = 'javascript:alert("xss");';
|
||||
* $path = UrlHelper::stripDangerousProtocols($path);
|
||||
* $attributes = new Attribute(array('href' => $path));
|
||||
* echo '<a' . $attributes . '>';
|
||||
* // Produces <a href="alert("xss");">
|
||||
* @endcode
|
||||
*
|
||||
* The attribute values are considered plain text and are treated as such. If a
|
||||
* safe HTML string is detected, it is converted to plain text with
|
||||
* PlainTextOutput::renderFromHtml() before being escaped. For example:
|
||||
* @code
|
||||
* $value = t('Highlight the @tag tag', ['@tag' => '<em>']);
|
||||
* $attributes = new Attribute(['value' => $value]);
|
||||
* echo '<input' . $attributes . '>';
|
||||
* // Produces <input value="Highlight the <em> tag">
|
||||
* @endcode
|
||||
*
|
||||
* @see \Drupal\Component\Utility\Html::escape()
|
||||
* @see \Drupal\Component\Render\PlainTextOutput::renderFromHtml()
|
||||
* @see \Drupal\Component\Utility\UrlHelper::stripDangerousProtocols()
|
||||
*/
|
||||
class Attribute implements \ArrayAccess, \IteratorAggregate, SafeStringInterface {
|
||||
class Attribute implements \ArrayAccess, \IteratorAggregate, MarkupInterface {
|
||||
|
||||
/**
|
||||
* Stores the attribute data.
|
||||
|
@ -100,15 +124,26 @@ class Attribute implements \ArrayAccess, \IteratorAggregate, SafeStringInterface
|
|||
}
|
||||
// An array value or 'class' attribute name are forced to always be an
|
||||
// AttributeArray value for consistency.
|
||||
if (is_array($value) || $name == 'class') {
|
||||
if ($name == 'class' && !is_array($value)) {
|
||||
// Cast the value to string in case it implements MarkupInterface.
|
||||
$value = [(string) $value];
|
||||
}
|
||||
if (is_array($value)) {
|
||||
// Cast the value to an array if the value was passed in as a string.
|
||||
// @todo Decide to fix all the broken instances of class as a string
|
||||
// in core or cast them.
|
||||
$value = new AttributeArray($name, (array) $value);
|
||||
$value = new AttributeArray($name, $value);
|
||||
}
|
||||
elseif (is_bool($value)) {
|
||||
$value = new AttributeBoolean($name, $value);
|
||||
}
|
||||
// As a development aid, we allow the value to be a safe string object.
|
||||
elseif (SafeMarkup::isSafe($value)) {
|
||||
// Attributes are not supposed to display HTML markup, so we just convert
|
||||
// the value to plain text.
|
||||
$value = PlainTextOutput::renderFromHtml($value);
|
||||
$value = new AttributeString($name, $value);
|
||||
}
|
||||
elseif (!is_object($value)) {
|
||||
$value = new AttributeString($name, $value);
|
||||
}
|
||||
|
|
|
@ -25,7 +25,7 @@ namespace Drupal\Core\Template\Loader;
|
|||
* @see \Drupal\Core\Render\Element\InlineTemplate
|
||||
* @see twig_render_template()
|
||||
*/
|
||||
class StringLoader extends \Twig_Loader_String {
|
||||
class StringLoader implements \Twig_LoaderInterface, \Twig_ExistsLoaderInterface {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
|
@ -39,4 +39,25 @@ class StringLoader extends \Twig_Loader_String {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getSource($name) {
|
||||
return $name;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getCacheKey($name) {
|
||||
return $name;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function isFresh($name, $time) {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -9,8 +9,7 @@ namespace Drupal\Core\Template;
|
|||
|
||||
use Drupal\Component\Utility\SafeMarkup;
|
||||
use Drupal\Core\Cache\CacheBackendInterface;
|
||||
use Drupal\Core\PhpStorage\PhpStorageFactory;
|
||||
use Drupal\Core\Render\SafeString;
|
||||
use Drupal\Core\Render\Markup;
|
||||
|
||||
/**
|
||||
* A class that defines a Twig environment for Drupal.
|
||||
|
@ -22,27 +21,6 @@ use Drupal\Core\Render\SafeString;
|
|||
*/
|
||||
class TwigEnvironment extends \Twig_Environment {
|
||||
|
||||
/**
|
||||
* The cache object used for auto-refresh via mtime.
|
||||
*
|
||||
* @var \Drupal\Core\Cache\CacheBackendInterface
|
||||
*/
|
||||
protected $cache_object = NULL;
|
||||
|
||||
/**
|
||||
* The PhpStorage object used for storing the templates.
|
||||
*
|
||||
* @var \Drupal\Core\PhpStorage\PhpStorageFactory
|
||||
*/
|
||||
protected $storage = NULL;
|
||||
|
||||
/**
|
||||
* The template cache filename prefix.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $templateCacheFilenamePrefix;
|
||||
|
||||
/**
|
||||
* Static cache of template classes.
|
||||
*
|
||||
|
@ -66,9 +44,6 @@ class TwigEnvironment extends \Twig_Environment {
|
|||
* The options for the Twig environment.
|
||||
*/
|
||||
public function __construct($root, CacheBackendInterface $cache, $twig_extension_hash, \Twig_LoaderInterface $loader = NULL, $options = array()) {
|
||||
$this->cache_object = $cache;
|
||||
$this->templateCacheFilenamePrefix = $twig_extension_hash;
|
||||
|
||||
// Ensure that twig.engine is loaded, given that it is needed to render a
|
||||
// template because functions like TwigExtension::escapeFilter() are called.
|
||||
require_once $root . '/core/themes/engines/twig/twig.engine';
|
||||
|
@ -82,122 +57,16 @@ class TwigEnvironment extends \Twig_Environment {
|
|||
'auto_reload' => NULL,
|
||||
);
|
||||
// Ensure autoescaping is always on.
|
||||
$options['autoescape'] = TRUE;
|
||||
$options['autoescape'] = 'html';
|
||||
|
||||
if ($options['cache'] === TRUE) {
|
||||
$options['cache'] = new TwigPhpStorageCache($cache, $twig_extension_hash);
|
||||
}
|
||||
|
||||
$this->loader = $loader;
|
||||
parent::__construct($this->loader, $options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the compiled template needs an update.
|
||||
*/
|
||||
protected function isFresh($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);
|
||||
$this->storage()->save($cache_filename, $compiled_source);
|
||||
// Save the last modification time
|
||||
$cid = 'twig:' . $cache_filename;
|
||||
$this->cache_object->set($cid, REQUEST_TIME);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getCacheFilename($name) {
|
||||
// We override the cache filename in order to avoid issues with not using
|
||||
// shared filesystems. The Twig templates for example rely on available Twig
|
||||
// extensions, so we use the twig extension hash which varies by extensions
|
||||
// and their mtime.
|
||||
// @see \Drupal\Core\DependencyInjection\Compiler\TwigExtensionPass
|
||||
|
||||
if (!$this->cache) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
$class = substr($this->getTemplateClass($name), strlen($this->templateClassPrefix));
|
||||
|
||||
// The first part is what is invalidated.
|
||||
return $this->templateCacheFilenamePrefix . '_' . basename($name) . '_' . $class;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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().
|
||||
*
|
||||
* @param string $name
|
||||
* The template name or the string which should be rendered as template.
|
||||
* @param int $index
|
||||
* The index if it is an embedded template.
|
||||
*
|
||||
* @return \Twig_TemplateInterface
|
||||
* A template instance representing the given template name.
|
||||
*
|
||||
* @throws \Twig_Error_Loader
|
||||
* When the template cannot be found.
|
||||
* @throws \Twig_Error_Syntax
|
||||
* When an error occurred during compilation.
|
||||
*/
|
||||
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) {
|
||||
// If autoreload is on, check that the template has not been
|
||||
// modified since the last compilation.
|
||||
if ($this->isAutoReload() && !$this->isFresh($cache_filename, $name)) {
|
||||
$this->updateCompiledTemplate($cache_filename, $name);
|
||||
}
|
||||
|
||||
if (!$this->storage()->load($cache_filename)) {
|
||||
$this->updateCompiledTemplate($cache_filename, $name);
|
||||
$this->storage()->load($cache_filename);
|
||||
}
|
||||
}
|
||||
if (!class_exists($cls, FALSE)) {
|
||||
$compiled_source = $this->compileSource($this->loader->getSource($name), $name);
|
||||
eval('?' . '>' . $compiled_source);
|
||||
}
|
||||
}
|
||||
|
||||
if (!$this->runtimeInitialized) {
|
||||
$this->initRuntime();
|
||||
}
|
||||
|
||||
return $this->loadedTemplates[$cls] = new $cls($this);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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)) {
|
||||
$this->storage = PhpStorageFactory::get('twig');
|
||||
}
|
||||
return $this->storage;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the template class associated with the given string.
|
||||
*
|
||||
|
@ -238,15 +107,15 @@ class TwigEnvironment extends \Twig_Environment {
|
|||
* @param array $context
|
||||
* An array of parameters to pass to the template.
|
||||
*
|
||||
* @return \Drupal\Component\Utility\SafeStringInterface|string
|
||||
* The rendered inline template as a SafeString object.
|
||||
* @return \Drupal\Component\Render\MarkupInterface|string
|
||||
* The rendered inline template as a Markup object.
|
||||
*
|
||||
* @see \Drupal\Core\Template\Loader\StringLoader::exists()
|
||||
*/
|
||||
public function renderInline($template_string, array $context = array()) {
|
||||
// Prefix all inline templates with a special comment.
|
||||
$template_string = '{# inline_template_start #}' . $template_string;
|
||||
return SafeString::create($this->loadTemplate($template_string, NULL)->render($context));
|
||||
return Markup::create($this->loadTemplate($template_string, NULL)->render($context));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -14,7 +14,9 @@ namespace Drupal\Core\Template;
|
|||
|
||||
use Drupal\Component\Utility\Html;
|
||||
use Drupal\Component\Utility\SafeMarkup;
|
||||
use Drupal\Component\Utility\SafeStringInterface;
|
||||
use Drupal\Component\Render\MarkupInterface;
|
||||
use Drupal\Core\Datetime\DateFormatter;
|
||||
use Drupal\Core\Render\RenderableInterface;
|
||||
use Drupal\Core\Render\RendererInterface;
|
||||
use Drupal\Core\Routing\UrlGeneratorInterface;
|
||||
use Drupal\Core\Theme\ThemeManagerInterface;
|
||||
|
@ -50,6 +52,13 @@ class TwigExtension extends \Twig_Extension {
|
|||
*/
|
||||
protected $themeManager;
|
||||
|
||||
/**
|
||||
* The date formatter.
|
||||
*
|
||||
* @var \Drupal\Core\Datetime\DateFormatter
|
||||
*/
|
||||
protected $dateFormatter;
|
||||
|
||||
/**
|
||||
* Constructs \Drupal\Core\Template\TwigExtension.
|
||||
*
|
||||
|
@ -101,6 +110,19 @@ class TwigExtension extends \Twig_Extension {
|
|||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the date formatter.
|
||||
*
|
||||
* @param \Drupal\Core\Datetime\DateFormatter $date_formatter
|
||||
* The date formatter.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setDateFormatter(DateFormatter $date_formatter) {
|
||||
$this->dateFormatter = $date_formatter;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
@ -115,6 +137,7 @@ class TwigExtension extends \Twig_Extension {
|
|||
new \Twig_SimpleFunction('link', array($this, 'getLink')),
|
||||
new \Twig_SimpleFunction('file_url', 'file_create_url'),
|
||||
new \Twig_SimpleFunction('attach_library', [$this, 'attachLibrary']),
|
||||
new \Twig_SimpleFunction('active_theme_path', [$this, 'getActiveThemePath']),
|
||||
new \Twig_SimpleFunction('active_theme', [$this, 'getActiveTheme']),
|
||||
];
|
||||
}
|
||||
|
@ -132,7 +155,6 @@ class TwigExtension extends \Twig_Extension {
|
|||
// "raw" filter and give it identifiable names. These filters should only
|
||||
// be used in "trans" tags.
|
||||
// @see TwigNodeTrans::compileString()
|
||||
new \Twig_SimpleFilter('passthrough', 'twig_raw_filter', array('is_safe' => array('html'))),
|
||||
new \Twig_SimpleFilter('placeholder', [$this, 'escapePlaceholder'], array('is_safe' => array('html'), 'needs_environment' => TRUE)),
|
||||
|
||||
// Replace twig's escape filter with our own.
|
||||
|
@ -151,6 +173,7 @@ class TwigExtension extends \Twig_Extension {
|
|||
new \Twig_SimpleFilter('clean_id', '\Drupal\Component\Utility\Html::getId'),
|
||||
// This filter will render a renderable array to use the string results.
|
||||
new \Twig_SimpleFilter('render', array($this, 'renderVar')),
|
||||
new \Twig_SimpleFilter('format_date', array($this->dateFormatter, 'format')),
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -272,6 +295,16 @@ class TwigExtension extends \Twig_Extension {
|
|||
return $this->themeManager->getActiveTheme()->getName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the path of the active theme.
|
||||
*
|
||||
* @return string
|
||||
* The path to the active theme.
|
||||
*/
|
||||
public function getActiveThemePath() {
|
||||
return $this->themeManager->getActiveTheme()->getPath();
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines at compile time whether the generated URL will be safe.
|
||||
*
|
||||
|
@ -349,6 +382,9 @@ class TwigExtension extends \Twig_Extension {
|
|||
*
|
||||
* Replacement function for Twig's escape filter.
|
||||
*
|
||||
* Note: This function should be kept in sync with
|
||||
* theme_render_and_autoescape().
|
||||
*
|
||||
* @param \Twig_Environment $env
|
||||
* A Twig_Environment instance.
|
||||
* @param mixed $arg
|
||||
|
@ -363,6 +399,9 @@ class TwigExtension extends \Twig_Extension {
|
|||
*
|
||||
* @return string|null
|
||||
* The escaped, rendered output, or NULL if there is no valid output.
|
||||
*
|
||||
* @todo Refactor this to keep it in sync with theme_render_and_autoescape()
|
||||
* in https://www.drupal.org/node/2575065
|
||||
*/
|
||||
public function escapeFilter(\Twig_Environment $env, $arg, $strategy = 'html', $charset = NULL, $autoescape = FALSE) {
|
||||
// Check for a numeric zero int or float.
|
||||
|
@ -376,7 +415,7 @@ class TwigExtension extends \Twig_Extension {
|
|||
}
|
||||
|
||||
// Keep Twig_Markup objects intact to support autoescaping.
|
||||
if ($autoescape && ($arg instanceOf \Twig_Markup || $arg instanceOf SafeStringInterface)) {
|
||||
if ($autoescape && ($arg instanceOf \Twig_Markup || $arg instanceOf MarkupInterface)) {
|
||||
return $arg;
|
||||
}
|
||||
|
||||
|
@ -386,7 +425,10 @@ class TwigExtension extends \Twig_Extension {
|
|||
$return = (string) $arg;
|
||||
}
|
||||
elseif (is_object($arg)) {
|
||||
if (method_exists($arg, '__toString')) {
|
||||
if ($arg instanceof RenderableInterface) {
|
||||
$arg = $arg->toRenderable();
|
||||
}
|
||||
elseif (method_exists($arg, '__toString')) {
|
||||
$return = (string) $arg;
|
||||
}
|
||||
// You can't throw exceptions in the magic PHP __toString methods, see
|
||||
|
@ -461,7 +503,10 @@ class TwigExtension extends \Twig_Extension {
|
|||
}
|
||||
|
||||
if (is_object($arg)) {
|
||||
if (method_exists($arg, '__toString')) {
|
||||
if ($arg instanceof RenderableInterface) {
|
||||
$arg = $arg->toRenderable();
|
||||
}
|
||||
elseif (method_exists($arg, '__toString')) {
|
||||
return (string) $arg;
|
||||
}
|
||||
// You can't throw exceptions in the magic PHP __toString methods, see
|
||||
|
|
|
@ -136,9 +136,6 @@ class TwigNodeTrans extends \Twig_Node {
|
|||
$argPrefix = '@';
|
||||
while ($args instanceof \Twig_Node_Expression_Filter) {
|
||||
switch ($args->getNode('filter')->getAttribute('value')) {
|
||||
case 'passthrough':
|
||||
$argPrefix = '!';
|
||||
break;
|
||||
case 'placeholder':
|
||||
$argPrefix = '%';
|
||||
break;
|
||||
|
|
121
core/lib/Drupal/Core/Template/TwigPhpStorageCache.php
Normal file
121
core/lib/Drupal/Core/Template/TwigPhpStorageCache.php
Normal file
|
@ -0,0 +1,121 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\Core\Template\TwigPhpStorageCache.
|
||||
*/
|
||||
|
||||
namespace Drupal\Core\Template;
|
||||
|
||||
use Drupal\Core\Cache\CacheBackendInterface;
|
||||
use Drupal\Core\PhpStorage\PhpStorageFactory;
|
||||
|
||||
/**
|
||||
* Provides an alternate cache storage for Twig using PhpStorage.
|
||||
*
|
||||
* This class is designed to work on setups with multiple webheads using a local
|
||||
* filesystem for the twig cache. When generating the cache key, a hash value
|
||||
* depending on the enabled extensions is included. This prevents stale
|
||||
* templates from being reused when twig extensions are enabled or disabled.
|
||||
*
|
||||
* @see \Drupal\Core\DependencyInjection\Compiler\TwigExtensionPass
|
||||
*/
|
||||
class TwigPhpStorageCache implements \Twig_CacheInterface {
|
||||
|
||||
/**
|
||||
* The cache object used for auto-refresh via mtime.
|
||||
*
|
||||
* @var \Drupal\Core\Cache\CacheBackendInterface
|
||||
*/
|
||||
protected $cache;
|
||||
|
||||
/**
|
||||
* The PhpStorage object used for storing the templates.
|
||||
*
|
||||
* @var \Drupal\Component\PhpStorage\PhpStorageInterface
|
||||
*/
|
||||
protected $storage;
|
||||
|
||||
/**
|
||||
* The template cache filename prefix.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $templateCacheFilenamePrefix;
|
||||
|
||||
/**
|
||||
* Store cache backend and other information internally.
|
||||
*
|
||||
* @param \Drupal\Core\Cache\CacheBackendInterface $cache
|
||||
* The cache bin.
|
||||
* @param string $twig_extension_hash
|
||||
* The Twig extension hash.
|
||||
*/
|
||||
public function __construct(CacheBackendInterface $cache, $twig_extension_hash) {
|
||||
$this->cache = $cache;
|
||||
$this->templateCacheFilenamePrefix = $twig_extension_hash;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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)) {
|
||||
$this->storage = PhpStorageFactory::get('twig');
|
||||
}
|
||||
return $this->storage;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function generateKey($name, $className) {
|
||||
$hash = hash('sha256', $className);
|
||||
|
||||
if (strpos($name, '{# inline_template_start #}') === 0) {
|
||||
// $name is an inline template, and can have characters that are not valid
|
||||
// for a filename. $hash is unique for each inline template so we just use
|
||||
// the generic name 'inline-template' here.
|
||||
$name = 'inline-template';
|
||||
}
|
||||
else {
|
||||
$name = basename($name);
|
||||
}
|
||||
|
||||
// The first part is what is invalidated.
|
||||
return $this->templateCacheFilenamePrefix . '_' . $name . '_' . $hash;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function load($key) {
|
||||
$this->storage()->load($key);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function write($key, $content) {
|
||||
$this->storage()->save($key, $content);
|
||||
// Save the last mtime.
|
||||
$cid = 'twig:' . $key;
|
||||
$this->cache->set($cid, REQUEST_TIME);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getTimestamp($key) {
|
||||
$cid = 'twig:' . $key;
|
||||
if ($cache = $this->cache->get($cid)) {
|
||||
return $cache->data;
|
||||
}
|
||||
else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
Reference in a new issue