diff --git a/core/composer.json b/core/composer.json index abb57e6..0d83258 100644 --- a/core/composer.json +++ b/core/composer.json @@ -17,7 +17,7 @@ "symfony/validator": "2.7.*", "symfony/process": "2.7.*", "symfony/yaml": "2.7.*", - "twig/twig": "~1.21.2", + "twig/twig": "1.x-dev", "doctrine/common": "2.5.*", "doctrine/annotations": "1.2.*", "guzzlehttp/guzzle": "~6.1", diff --git a/core/composer.lock b/core/composer.lock index e8b72c0..2ab10c4 100644 --- a/core/composer.lock +++ b/core/composer.lock @@ -4,7 +4,8 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "hash": "001134bc15b65d095dbe87b89ddd0ef2", + "hash": "f193c94c598d7fc173f5e1e86d7393e4", + "content-hash": "4baf7e87b846834c93b6bac358028791", "packages": [ { "name": "doctrine/annotations", @@ -1778,16 +1779,16 @@ }, { "name": "twig/twig", - "version": "v1.21.2", + "version": "1.x-dev", "source": { "type": "git", "url": "https://github.com/twigphp/Twig.git", - "reference": "ddce1136beb8db29b9cd7dffa8ab518b978c9db3" + "reference": "9fde02fe552256722466c9985520b6f50c9c759b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/twigphp/Twig/zipball/ddce1136beb8db29b9cd7dffa8ab518b978c9db3", - "reference": "ddce1136beb8db29b9cd7dffa8ab518b978c9db3", + "url": "https://api.github.com/repos/twigphp/Twig/zipball/9fde02fe552256722466c9985520b6f50c9c759b", + "reference": "9fde02fe552256722466c9985520b6f50c9c759b", "shasum": "" }, "require": { @@ -1800,7 +1801,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.21-dev" + "dev-master": "1.22-dev" } }, "autoload": { @@ -1835,7 +1836,7 @@ "keywords": [ "templating" ], - "time": "2015-09-09 05:28:51" + "time": "2015-09-16 08:32:19" }, { "name": "zendframework/zend-diactoros", @@ -3372,6 +3373,7 @@ "aliases": [], "minimum-stability": "dev", "stability-flags": { + "twig/twig": 20, "behat/mink-goutte-driver": 20 }, "prefer-stable": true, diff --git a/core/lib/Drupal/Core/Template/TwigCacheChain.php b/core/lib/Drupal/Core/Template/TwigCacheChain.php new file mode 100644 index 0000000..fc5c41b --- /dev/null +++ b/core/lib/Drupal/Core/Template/TwigCacheChain.php @@ -0,0 +1,87 @@ +caches = $caches; + } + + /** + * {@inheritdoc} + */ + public function generateKey($name, $className) { + foreach ($this->caches as $cache) { + $key = $cache->generateKey($name, $className); + return $key; + } + } + + /** + * {@inheritdoc} + */ + public function has($key) { + foreach ($this->caches as $cache) { + if ($has = $cache->has($key)) { + return $has; + } + } + } + + /** + * {@inheritdoc} + */ + public function load($key) { + foreach ($this->caches as $cache) { + if ($cache->has($key)) { + $cache->load($key); + return; + } + } + } + + /** + * {@inheritdoc} + */ + public function write($key, $content) { + // We want to write to all of them. + foreach ($this->caches as $cache) { + $cache->write($key, $content); + } + } + + /** + * {@inheritdoc} + */ + public function getTimestamp($key) { + foreach ($this->caches as $cache) { + if ($timestamp = $cache->getTimestamp($key)) { + return $timestamp; + } + } + } + +} diff --git a/core/lib/Drupal/Core/Template/TwigCacheNull.php b/core/lib/Drupal/Core/Template/TwigCacheNull.php new file mode 100644 index 0000000..3992836 --- /dev/null +++ b/core/lib/Drupal/Core/Template/TwigCacheNull.php @@ -0,0 +1,22 @@ +buffer[$key]); + } + +} diff --git a/core/lib/Drupal/Core/Template/TwigEnvironment.php b/core/lib/Drupal/Core/Template/TwigEnvironment.php index cb4df85..e59b4ac 100644 --- a/core/lib/Drupal/Core/Template/TwigEnvironment.php +++ b/core/lib/Drupal/Core/Template/TwigEnvironment.php @@ -9,7 +9,6 @@ use Drupal\Component\Utility\SafeMarkup; use Drupal\Core\Cache\CacheBackendInterface; -use Drupal\Core\PhpStorage\PhpStorageFactory; use Drupal\Core\Render\SafeString; /** @@ -23,27 +22,6 @@ 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. * * @var array @@ -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'; @@ -84,118 +59,18 @@ public function __construct($root, CacheBackendInterface $cache, $twig_extension // Ensure autoescaping is always on. $options['autoescape'] = 'html'; - $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); - } + // We set up a chain of cache classes in case there is a failure or race + // condition. The null cache is roughly equivalent to disabling the Twig + // cache entirely. + $php_storage_cache = new TwigPhpStorageCache($cache, $twig_extension_hash); + $null_cache = new TwigCacheNull(); - /** - * {@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; + if ($options['cache'] === TRUE) { + $options['cache'] = new TwigCacheChain([$php_storage_cache, $null_cache]); } - $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; + $this->loader = $loader; + parent::__construct($this->loader, $options); } /** diff --git a/core/lib/Drupal/Core/Template/TwigPhpStorageCache.php b/core/lib/Drupal/Core/Template/TwigPhpStorageCache.php new file mode 100644 index 0000000..44bbd27 --- /dev/null +++ b/core/lib/Drupal/Core/Template/TwigPhpStorageCache.php @@ -0,0 +1,120 @@ +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) { + // 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 + $hash = hash('sha256', $className); + + // The first part is what is invalidated. + return $this->templateCacheFilenamePrefix . '_' . basename($name) . '_' . $hash; + } + + /** + * {@inheritdoc} + */ + public function has($key) { + return $this->storage()->exists($key); + } + + /** + * {@inheritdoc} + */ + public function load($key) { + if (!$this->storage()->load($key)) { + throw new \RuntimeException(sprintf('Failed to load Twig cache file "%s".', $key)); + } + } + + /** + * {@inheritdoc} + */ + public function write($key, $content) { + if (!$this->storage()->save($key, $content)) { + throw new \RuntimeException(sprintf('Failed to write Twig cache file "%s".', $key)); + } + // 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 REQUEST_TIME; + } + } + +} diff --git a/core/modules/system/src/Tests/Theme/TwigSettingsTest.php b/core/modules/system/src/Tests/Theme/TwigSettingsTest.php index 36cc48d..f581fa62 100644 --- a/core/modules/system/src/Tests/Theme/TwigSettingsTest.php +++ b/core/modules/system/src/Tests/Theme/TwigSettingsTest.php @@ -114,8 +114,7 @@ function testTwigCacheOverride() { $this->rebuildContainer(); // This should return false after rebuilding the service container. - $new_cache_filename = $this->container->get('twig')->getCacheFilename($template_filename); - $this->assertFalse($new_cache_filename, 'Twig environment does not return cache filename after caching is disabled.'); + $this->assertFalse($this->container->get('twig')->getCache(), 'Twig environment has caching disabled.'); } /** diff --git a/core/vendor/composer/installed.json b/core/vendor/composer/installed.json index b539d27..3ca2ada 100644 --- a/core/vendor/composer/installed.json +++ b/core/vendor/composer/installed.json @@ -3354,129 +3354,129 @@ "homepage": "https://symfony.com" }, { - "name": "twig/twig", - "version": "v1.21.2", - "version_normalized": "1.21.2.0", + "name": "symfony/translation", + "version": "v2.7.4", + "version_normalized": "2.7.4.0", "source": { "type": "git", - "url": "https://github.com/twigphp/Twig.git", - "reference": "ddce1136beb8db29b9cd7dffa8ab518b978c9db3" + "url": "https://github.com/symfony/Translation.git", + "reference": "485877661835e188cd78345c6d4eef1290d17571" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/twigphp/Twig/zipball/ddce1136beb8db29b9cd7dffa8ab518b978c9db3", - "reference": "ddce1136beb8db29b9cd7dffa8ab518b978c9db3", + "url": "https://api.github.com/repos/symfony/Translation/zipball/485877661835e188cd78345c6d4eef1290d17571", + "reference": "485877661835e188cd78345c6d4eef1290d17571", "shasum": "" }, "require": { - "php": ">=5.2.7" + "php": ">=5.3.9" + }, + "conflict": { + "symfony/config": "<2.7" }, "require-dev": { - "symfony/debug": "~2.7", - "symfony/phpunit-bridge": "~2.7" + "psr/log": "~1.0", + "symfony/config": "~2.7", + "symfony/intl": "~2.4", + "symfony/phpunit-bridge": "~2.7", + "symfony/yaml": "~2.2" }, - "time": "2015-09-09 05:28:51", + "suggest": { + "psr/log": "To use logging capability in translator", + "symfony/config": "", + "symfony/yaml": "" + }, + "time": "2015-09-06 08:36:38", "type": "library", "extra": { "branch-alias": { - "dev-master": "1.21-dev" + "dev-master": "2.7-dev" } }, "installation-source": "dist", "autoload": { - "psr-0": { - "Twig_": "lib/" + "psr-4": { + "Symfony\\Component\\Translation\\": "" } }, "notification-url": "https://packagist.org/downloads/", "license": [ - "BSD-3-Clause" + "MIT" ], "authors": [ { "name": "Fabien Potencier", - "email": "fabien@symfony.com", - "homepage": "http://fabien.potencier.org", - "role": "Lead Developer" - }, - { - "name": "Armin Ronacher", - "email": "armin.ronacher@active-4.com", - "role": "Project Founder" + "email": "fabien@symfony.com" }, { - "name": "Twig Team", - "homepage": "http://twig.sensiolabs.org/contributors", - "role": "Contributors" + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" } ], - "description": "Twig, the flexible, fast, and secure template language for PHP", - "homepage": "http://twig.sensiolabs.org", - "keywords": [ - "templating" - ] + "description": "Symfony Translation Component", + "homepage": "https://symfony.com" }, { - "name": "symfony/translation", - "version": "v2.7.4", - "version_normalized": "2.7.4.0", + "name": "twig/twig", + "version": "1.x-dev", + "version_normalized": "1.9999999.9999999.9999999-dev", "source": { "type": "git", - "url": "https://github.com/symfony/Translation.git", - "reference": "485877661835e188cd78345c6d4eef1290d17571" + "url": "https://github.com/twigphp/Twig.git", + "reference": "9fde02fe552256722466c9985520b6f50c9c759b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/Translation/zipball/485877661835e188cd78345c6d4eef1290d17571", - "reference": "485877661835e188cd78345c6d4eef1290d17571", + "url": "https://api.github.com/repos/twigphp/Twig/zipball/9fde02fe552256722466c9985520b6f50c9c759b", + "reference": "9fde02fe552256722466c9985520b6f50c9c759b", "shasum": "" }, "require": { - "php": ">=5.3.9" - }, - "conflict": { - "symfony/config": "<2.7" + "php": ">=5.2.7" }, "require-dev": { - "psr/log": "~1.0", - "symfony/config": "~2.7", - "symfony/intl": "~2.4", - "symfony/phpunit-bridge": "~2.7", - "symfony/yaml": "~2.2" - }, - "suggest": { - "psr/log": "To use logging capability in translator", - "symfony/config": "", - "symfony/yaml": "" + "symfony/debug": "~2.7", + "symfony/phpunit-bridge": "~2.7" }, - "time": "2015-09-06 08:36:38", + "time": "2015-09-16 08:32:19", "type": "library", "extra": { "branch-alias": { - "dev-master": "2.7-dev" + "dev-master": "1.22-dev" } }, "installation-source": "dist", "autoload": { - "psr-4": { - "Symfony\\Component\\Translation\\": "" + "psr-0": { + "Twig_": "lib/" } }, "notification-url": "https://packagist.org/downloads/", "license": [ - "MIT" + "BSD-3-Clause" ], "authors": [ { "name": "Fabien Potencier", - "email": "fabien@symfony.com" + "email": "fabien@symfony.com", + "homepage": "http://fabien.potencier.org", + "role": "Lead Developer" }, { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" + "name": "Armin Ronacher", + "email": "armin.ronacher@active-4.com", + "role": "Project Founder" + }, + { + "name": "Twig Team", + "homepage": "http://twig.sensiolabs.org/contributors", + "role": "Contributors" } ], - "description": "Symfony Translation Component", - "homepage": "https://symfony.com" + "description": "Twig, the flexible, fast, and secure template language for PHP", + "homepage": "http://twig.sensiolabs.org", + "keywords": [ + "templating" + ] } ] diff --git a/core/vendor/twig/twig/CHANGELOG b/core/vendor/twig/twig/CHANGELOG index ee447b0..3966a3e 100644 --- a/core/vendor/twig/twig/CHANGELOG +++ b/core/vendor/twig/twig/CHANGELOG @@ -1,3 +1,22 @@ +* 1.22.2 (2015-XX-XX) + + * fixed Twig_Cache_Null logic + +* 1.22.1 (2015-09-15) + + * fixed regression in template_from_string + +* 1.22.0 (2015-09-13) + + * made Twig_Test_IntegrationTestCase more flexible + * added an option to force PHP bytecode invalidation when writing a compiled template into the cache + * fixed the profiler duration for the root node + * changed template cache names to take into account enabled extensions + * deprecated Twig_Environment::clearCacheFiles(), Twig_Environment::getCacheFilename(), + Twig_Environment::writeCacheFile(), and Twig_Environment::getTemplateClassPrefix() + * added a way to override the filesystem template cache system + * added a way to get the original template source from Twig_Template + * 1.21.2 (2015-09-09) * fixed variable names for the deprecation triggering code diff --git a/core/vendor/twig/twig/composer.json b/core/vendor/twig/twig/composer.json index 2d3438e..5d31ac1 100644 --- a/core/vendor/twig/twig/composer.json +++ b/core/vendor/twig/twig/composer.json @@ -40,7 +40,7 @@ }, "extra": { "branch-alias": { - "dev-master": "1.21-dev" + "dev-master": "1.22-dev" } } } diff --git a/core/vendor/twig/twig/doc/deprecated.rst b/core/vendor/twig/twig/doc/deprecated.rst index 1489174..23b22de 100644 --- a/core/vendor/twig/twig/doc/deprecated.rst +++ b/core/vendor/twig/twig/doc/deprecated.rst @@ -117,7 +117,7 @@ Loaders ------- * As of Twig 1.x, ``Twig_Loader_String`` is deprecated and will be removed in - 2.0. + 2.0. You can render a string via ``Twig_Environment::createTemplate()``. Node Visitors ------------- @@ -140,8 +140,9 @@ Globals Miscellaneous ------------- -* As of Twig 1.x, ``Twig_Environment::clearTemplateCache()`` is deprecated and - will be removed in 2.0. +* As of Twig 1.x, ``Twig_Environment::clearTemplateCache()``, ``Twig_Environment::writeCacheFile()``, + ``Twig_Environment::clearCacheFiles()``, ``Twig_Environment::getCacheFilename()``, and + ``Twig_Environment::getTemplateClassPrefix()`` are deprecated and will be removed in 2.0. * As of Twig 1.x, ``Twig_Template::getEnvironment()`` and ``Twig_TemplateInterface::getEnvironment()`` are deprecated and will be diff --git a/core/vendor/twig/twig/doc/recipes.rst b/core/vendor/twig/twig/doc/recipes.rst index 450ce55..6ad5327 100644 --- a/core/vendor/twig/twig/doc/recipes.rst +++ b/core/vendor/twig/twig/doc/recipes.rst @@ -337,24 +337,33 @@ Refreshing modified Templates when OPcache or APC is enabled When using OPcache with ``opcache.validate_timestamps`` set to ``0`` or APC with ``apc.stat`` set to ``0`` and Twig cache enabled, clearing the template -cache won't update the cache. To get around this, one can extend -``Twig_Environment`` and force the update of the cache when Twig rewrites the -cache:: +cache won't update the cache. - class Twig_Environment_APC extends Twig_Environment - { - protected function writeCacheFile($file, $content) - { - parent::writeCacheFile($file, $content); +To get around this, force Twig to invalidate the bytecode cache:: + + $twig = new Twig_Environment($loader, array( + 'cache' => new Twig_Cache_Filesystem('/some/cache/path', Twig_Cache_Filesystem::FORCE_BYTECODE_INVALIDATION), + // ... + )); - // Compile cached file into bytecode cache - if (extension_loaded('Zend OPcache') && ini_get('opcache.enable')) { - opcache_invalidate($file); - } elseif (extension_loaded('apc') && ini_get('apc.enabled')) { - apc_compile_file($file); +.. note:: + + Before Twig 1.22, you should extend ``Twig_Environment`` instead:: + + class OpCacheAwareTwigEnvironment extends Twig_Environment + { + protected function writeCacheFile($file, $content) + { + parent::writeCacheFile($file, $content); + + // Compile cached file into bytecode cache + if (function_exists('opcache_invalidate')) { + opcache_invalidate($file, true); + } elseif (function_exists('apc_compile_file')) { + apc_compile_file($file); + } } } - } Reusing a stateful Node Visitor ------------------------------- @@ -485,4 +494,25 @@ logical name, and not the path from the filesystem:: Now that the ``base.twig`` templates is defined in an array loader, you can remove it from the database, and everything else will still work as before. +Loading a Template from a String +-------------------------------- + +From a template, you can easily load a template stored in a string via the +``template_from_string`` function (available as of Twig 1.11 via the +``Twig_Extension_StringLoader`` extension):: + +.. code-block:: jinja + + {{ include(template_from_string("Hello {{ name }}")) }} + +From PHP, it's also possible to load a template stored in a string via +``Twig_Environment::createTemplate()`` (available as of Twig 1.18):: + + $template = $twig->createTemplate('hello {{ name }}'); + echo $template->render(array('name' => 'Fabien')); + +.. note:: + + Never use the ``Twig_Loader_String`` loader, which has severe limitations. + .. _callback: http://www.php.net/manual/en/function.is-callable.php diff --git a/core/vendor/twig/twig/ext/twig/php_twig.h b/core/vendor/twig/twig/ext/twig/php_twig.h index 27be05b..258ab2f 100644 --- a/core/vendor/twig/twig/ext/twig/php_twig.h +++ b/core/vendor/twig/twig/ext/twig/php_twig.h @@ -15,7 +15,7 @@ #ifndef PHP_TWIG_H #define PHP_TWIG_H -#define PHP_TWIG_VERSION "1.21.2" +#define PHP_TWIG_VERSION "1.22.2-DEV" #include "php.h" diff --git a/core/vendor/twig/twig/lib/Twig/Cache/Filesystem.php b/core/vendor/twig/twig/lib/Twig/Cache/Filesystem.php new file mode 100644 index 0000000..c33fa90 --- /dev/null +++ b/core/vendor/twig/twig/lib/Twig/Cache/Filesystem.php @@ -0,0 +1,103 @@ + + */ +class Twig_Cache_Filesystem implements Twig_CacheInterface +{ + const FORCE_BYTECODE_INVALIDATION = 1; + + private $directory; + private $invalidateBytecode; + + /** + * @param $directory string The root cache directory + * @param $options int A set of options + */ + public function __construct($directory, $options = 0) + { + $this->directory = $directory; + $this->options = $options; + } + + /** + * {@inheritdoc} + */ + public function generateKey($name, $className) + { + $hash = hash('sha256', $className); + + return $this->directory.'/'.$hash[0].'/'.$hash[1].'/'.$hash.'.php'; + } + + /** + * {@inheritdoc} + */ + public function has($key) + { + return is_file($key); + } + + /** + * {@inheritdoc} + */ + public function load($key) + { + require_once $key; + } + + /** + * {@inheritdoc} + */ + public function write($key, $content) + { + $dir = dirname($key); + if (!is_dir($dir)) { + if (false === @mkdir($dir, 0777, true)) { + clearstatcache(false, $dir); + if (!is_dir($dir)) { + throw new RuntimeException(sprintf('Unable to create the cache directory (%s).', $dir)); + } + } + } elseif (!is_writable($dir)) { + throw new RuntimeException(sprintf('Unable to write in the cache directory (%s).', $dir)); + } + + $tmpFile = tempnam($dir, basename($key)); + if (false !== @file_put_contents($tmpFile, $content) && @rename($tmpFile, $key)) { + @chmod($key, 0666 & ~umask()); + + if (self::FORCE_BYTECODE_INVALIDATION == ($this->options & self::FORCE_BYTECODE_INVALIDATION)) { + // Compile cached file into bytecode cache + if (function_exists('opcache_invalidate')) { + opcache_invalidate($key, true); + } elseif (function_exists('apc_compile_file')) { + apc_compile_file($key); + } + } + + return; + } + + throw new RuntimeException(sprintf('Failed to write cache file "%s".', $key)); + } + + /** + * {@inheritdoc} + */ + public function getTimestamp($key) + { + return filemtime($key); + } +} diff --git a/core/vendor/twig/twig/lib/Twig/Cache/Null.php b/core/vendor/twig/twig/lib/Twig/Cache/Null.php new file mode 100644 index 0000000..6a9a29b --- /dev/null +++ b/core/vendor/twig/twig/lib/Twig/Cache/Null.php @@ -0,0 +1,63 @@ + + */ +class Twig_Cache_Null implements Twig_CacheInterface +{ + private $buffer = array(); + + /** + * {@inheritdoc} + */ + public function generateKey($name, $className) + { + return $className; + } + + /** + * {@inheritdoc} + */ + public function has($key) + { + return false; + } + + /** + * {@inheritdoc} + */ + public function write($key, $content) + { + $this->buffer[$key] = $content; + } + + /** + * {@inheritdoc} + */ + public function load($key) + { + eval('?>'.$this->buffer[$key]); + + unset($this->buffer[$key]); + } + + /** + * {@inheritdoc} + */ + public function getTimestamp($key) + { + // never called as has() always returns false + return 0; + } +} diff --git a/core/vendor/twig/twig/lib/Twig/CacheInterface.php b/core/vendor/twig/twig/lib/Twig/CacheInterface.php new file mode 100644 index 0000000..fedd366 --- /dev/null +++ b/core/vendor/twig/twig/lib/Twig/CacheInterface.php @@ -0,0 +1,65 @@ + + */ +interface Twig_CacheInterface +{ + /** + * Generates a cache key for the given template class name. + * + * @param string $name The template name + * @param string $className The template class name + * + * @return string + */ + public function generateKey($name, $className); + + /** + * Checks if the cache key exists. + * + * @param string $key The cache key + * + * @return bool true if the cache key exists, false otherwise + */ + public function has($key); + + /** + * Writes the compiled template to cache. + * + * @param string $key The cache key + * @param string $content The template representation as a PHP class + */ + public function write($key, $content); + + /** + * Loads a template from the cache. + * + * @param string $key The cache key + */ + public function load($key); + + /** + * Returns the modification timestamp of a key. + * + * @param string $key The cache key + * + * @return int + */ + public function getTimestamp($key); +} diff --git a/core/vendor/twig/twig/lib/Twig/Environment.php b/core/vendor/twig/twig/lib/Twig/Environment.php index 6813a30..565ec47 100644 --- a/core/vendor/twig/twig/lib/Twig/Environment.php +++ b/core/vendor/twig/twig/lib/Twig/Environment.php @@ -16,7 +16,7 @@ */ class Twig_Environment { - const VERSION = '1.21.2'; + const VERSION = '1.22.2-DEV'; protected $charset; protected $loader; @@ -45,6 +45,10 @@ class Twig_Environment protected $filterCallbacks = array(); protected $staging; + private $originalCache; + private $bcWriteCacheFile = false; + private $bcGetCacheFilename = false; + /** * Constructor. * @@ -58,8 +62,9 @@ class Twig_Environment * * base_template_class: The base template class to use for generated * templates (default to Twig_Template). * - * * cache: An absolute path where to store the compiled templates, or - * false to disable compilation cache (default). + * * cache: An absolute path where to store the compiled templates, + * a Twig_Cache_Interface implementation, + * or false to disable compilation cache (default). * * * auto_reload: Whether to reload the template if the original source changed. * If you don't provide the auto_reload option, it will be @@ -112,6 +117,23 @@ public function __construct(Twig_LoaderInterface $loader = null, $options = arra $this->addExtension(new Twig_Extension_Escaper($options['autoescape'])); $this->addExtension(new Twig_Extension_Optimizer($options['optimizations'])); $this->staging = new Twig_Extension_Staging(); + + // For BC + if (is_string($this->originalCache)) { + $r = new ReflectionMethod($this, 'writeCacheFile'); + if ($r->getDeclaringClass()->getName() !== __CLASS__) { + @trigger_error('The Twig_Environment::writeCacheFile method is deprecated and will be removed in Twig 2.0.', E_USER_DEPRECATED); + + $this->bcWriteCacheFile = true; + } + + $r = new ReflectionMethod($this, 'getCacheFilename'); + if ($r->getDeclaringClass()->getName() !== __CLASS__) { + @trigger_error('The Twig_Environment::getCacheFilename method is deprecated and will be removed in Twig 2.0.', E_USER_DEPRECATED); + + $this->bcGetCacheFilename = true; + } + } } /** @@ -213,24 +235,39 @@ public function isStrictVariables() } /** - * Gets the cache directory or false if cache is disabled. + * Gets the current cache implementation. * - * @return string|false + * @param bool $original Whether to return the original cache option or the real cache instance + * + * @return Twig_CacheInterface|string|false A Twig_CacheInterface implementation, + * an absolute path to the compiled templates, + * or false to disable cache */ - public function getCache() + public function getCache($original = true) { - return $this->cache; + return $original ? $this->originalCache : $this->cache; } /** - * Sets the cache directory or false if cache is disabled. + * Sets the current cache implementation. * - * @param string|false $cache The absolute path to the compiled templates, - * or false to disable cache + * @param Twig_CacheInterface|string|false $cache A Twig_CacheInterface implementation, + * an absolute path to the compiled templates, + * or false to disable cache */ public function setCache($cache) { - $this->cache = $cache ? $cache : false; + if (is_string($cache)) { + $this->originalCache = $cache; + $this->cache = new Twig_Cache_Filesystem($cache); + } elseif (false === $cache) { + $this->originalCache = $cache; + $this->cache = new Twig_Cache_Null(); + } elseif ($cache instanceof Twig_CacheInterface) { + $this->originalCache = $this->cache = $cache; + } else { + throw new LogicException(sprintf('Cache can only be a string, false, or a Twig_CacheInterface implementation.')); + } } /** @@ -239,16 +276,16 @@ public function setCache($cache) * @param string $name The template name * * @return string|false The cache file name or false when caching is disabled + * + * @deprecated since 1.22 (to be removed in 2.0) */ public function getCacheFilename($name) { - if (false === $this->cache) { - return false; - } + @trigger_error(sprintf('The %s method is deprecated and will be removed in Twig 2.0.', __METHOD__), E_USER_DEPRECATED); - $class = substr($this->getTemplateClass($name), strlen($this->templateClassPrefix)); + $key = $this->cache->generateKey($name, $this->getTemplateClass($name)); - return $this->getCache().'/'.$class[0].'/'.$class[1].'/'.$class.'.php'; + return !$key ? false : $key; } /** @@ -261,16 +298,22 @@ public function getCacheFilename($name) */ public function getTemplateClass($name, $index = null) { - return $this->templateClassPrefix.hash('sha256', $this->getLoader()->getCacheKey($name)).(null === $index ? '' : '_'.$index); + $key = $this->getLoader()->getCacheKey($name).'__'.implode('__', array_keys($this->extensions)); + + return $this->templateClassPrefix.hash('sha256', $key).(null === $index ? '' : '_'.$index); } /** * Gets the template class prefix. * * @return string The template class prefix + * + * @deprecated since 1.22 (to be removed in 2.0) */ public function getTemplateClassPrefix() { + @trigger_error(sprintf('The %s method is deprecated and will be removed in Twig 2.0.', __METHOD__), E_USER_DEPRECATED); + return $this->templateClassPrefix; } @@ -326,15 +369,21 @@ public function loadTemplate($name, $index = null) } if (!class_exists($cls, false)) { - if (false === $cache = $this->getCacheFilename($name)) { - eval('?>'.$this->compileSource($this->getLoader()->getSource($name), $name)); + if ($this->bcGetCacheFilename) { + $key = $this->getCacheFilename($name); } else { - if (!is_file($cache) || ($this->isAutoReload() && !$this->isTemplateFresh($name, filemtime($cache)))) { - $this->writeCacheFile($cache, $this->compileSource($this->getLoader()->getSource($name), $name)); - } + $key = $this->cache->generateKey($name, $cls); + } - require_once $cache; + if (!$this->cache->has($key) || ($this->isAutoReload() && !$this->isTemplateFresh($name, $this->cache->getTimestamp($key)))) { + if ($this->bcWriteCacheFile) { + $this->writeCacheFile($key, $this->compileSource($this->getLoader()->getSource($name), $name)); + } else { + $this->cache->write($key, $this->compileSource($this->getLoader()->getSource($name), $name)); + } } + + $this->cache->load($key); } if (!$this->runtimeInitialized) { @@ -453,16 +502,18 @@ public function clearTemplateCache() /** * Clears the template cache files on the filesystem. + * + * @deprecated since 1.22 (to be removed in 2.0) */ public function clearCacheFiles() { - if (false === $this->cache) { - return; - } + @trigger_error(sprintf('The %s method is deprecated and will be removed in Twig 2.0.', __METHOD__), E_USER_DEPRECATED); - foreach (new RecursiveIteratorIterator(new RecursiveDirectoryIterator($this->cache), RecursiveIteratorIterator::LEAVES_ONLY) as $file) { - if ($file->isFile()) { - @unlink($file->getPathname()); + if (is_string($this->originalCache)) { + foreach (new RecursiveIteratorIterator(new RecursiveDirectoryIterator($this->originalCache), RecursiveIteratorIterator::LEAVES_ONLY) as $file) { + if ($file->isFile()) { + @unlink($file->getPathname()); + } } } } @@ -593,7 +644,13 @@ public function compile(Twig_NodeInterface $node) public function compileSource($source, $name = null) { try { - return $this->compile($this->parse($this->tokenize($source, $name))); + $compiled = $this->compile($this->parse($this->tokenize($source, $name)), $source); + + if (isset($source[0])) { + $compiled .= '/* '.str_replace(array('*/', "\r\n", "\r", "\n"), array('*//* ', "\n", "\n", "*/\n/* "), $source)."*/\n"; + } + + return $compiled; } catch (Twig_Error $e) { $e->setTemplateFile($name); throw $e; @@ -1272,30 +1329,11 @@ protected function initExtension(Twig_ExtensionInterface $extension) } } + /** + * @deprecated since 1.22 (to be removed in 2.0) + */ protected function writeCacheFile($file, $content) { - $dir = dirname($file); - if (!is_dir($dir)) { - if (false === @mkdir($dir, 0777, true)) { - clearstatcache(false, $dir); - if (!is_dir($dir)) { - throw new RuntimeException(sprintf('Unable to create the cache directory (%s).', $dir)); - } - } - } elseif (!is_writable($dir)) { - throw new RuntimeException(sprintf('Unable to write in the cache directory (%s).', $dir)); - } - - $tmpFile = tempnam($dir, basename($file)); - if (false !== @file_put_contents($tmpFile, $content)) { - // rename does not work on Win32 before 5.2.6 - if (@rename($tmpFile, $file) || (@copy($tmpFile, $file) && unlink($tmpFile))) { - @chmod($file, 0666 & ~umask()); - - return; - } - } - - throw new RuntimeException(sprintf('Failed to write cache file "%s".', $file)); + $this->cache->write($file, $content); } } diff --git a/core/vendor/twig/twig/lib/Twig/Extension/Core.php b/core/vendor/twig/twig/lib/Twig/Extension/Core.php index 4980ceb..3716f02 100644 --- a/core/vendor/twig/twig/lib/Twig/Extension/Core.php +++ b/core/vendor/twig/twig/lib/Twig/Extension/Core.php @@ -536,12 +536,17 @@ function twig_date_converter(Twig_Environment $env, $date = null, $timezone = nu return $date; } + if (null === $date || 'now' === $date) { + return new DateTime($date, false !== $timezone ? $timezone : $env->getExtension('core')->getTimezone()); + } + $asString = (string) $date; if (ctype_digit($asString) || (!empty($asString) && '-' === $asString[0] && ctype_digit(substr($asString, 1)))) { - $date = '@'.$date; + $date = new DateTime('@'.$date); + } else { + $date = new DateTime($date, $env->getExtension('core')->getTimezone()); } - $date = new DateTime($date, $env->getExtension('core')->getTimezone()); if (false !== $timezone) { $date->setTimezone($timezone); } diff --git a/core/vendor/twig/twig/lib/Twig/Extension/StringLoader.php b/core/vendor/twig/twig/lib/Twig/Extension/StringLoader.php index 4e1a546..d96673c 100644 --- a/core/vendor/twig/twig/lib/Twig/Extension/StringLoader.php +++ b/core/vendor/twig/twig/lib/Twig/Extension/StringLoader.php @@ -37,11 +37,11 @@ public function getName() * * * @param Twig_Environment $env A Twig_Environment instance - * @param string $template A template as a string + * @param string $template A template as a string or object implementing __toString() * * @return Twig_Template A Twig_Template instance */ function twig_template_from_string(Twig_Environment $env, $template) { - return $env->createTemplate($template); + return $env->createTemplate((string) $template); } diff --git a/core/vendor/twig/twig/lib/Twig/Loader/Chain.php b/core/vendor/twig/twig/lib/Twig/Loader/Chain.php index 7919eda..81d57ad 100644 --- a/core/vendor/twig/twig/lib/Twig/Loader/Chain.php +++ b/core/vendor/twig/twig/lib/Twig/Loader/Chain.php @@ -60,7 +60,7 @@ public function getSource($name) } } - throw new Twig_Error_Loader(sprintf('Template "%s" is not defined (%s).', $name, implode(', ', $exceptions))); + throw new Twig_Error_Loader(sprintf('Template "%s" is not defined%s.', $name, $exceptions ? ' ('.implode(', ', $exceptions).')' : '')); } /** @@ -112,7 +112,7 @@ public function getCacheKey($name) } } - throw new Twig_Error_Loader(sprintf('Template "%s" is not defined (%s).', $name, implode(' ', $exceptions))); + throw new Twig_Error_Loader(sprintf('Template "%s" is not defined%s.', $name, $exceptions ? ' ('.implode(', ', $exceptions).')' : '')); } /** @@ -133,6 +133,6 @@ public function isFresh($name, $time) } } - throw new Twig_Error_Loader(sprintf('Template "%s" is not defined (%s).', $name, implode(' ', $exceptions))); + throw new Twig_Error_Loader(sprintf('Template "%s" is not defined%s.', $name, $exceptions ? ' ('.implode(', ', $exceptions).')' : '')); } } diff --git a/core/vendor/twig/twig/lib/Twig/Loader/Filesystem.php b/core/vendor/twig/twig/lib/Twig/Loader/Filesystem.php index a68876c..1bc75a1 100644 --- a/core/vendor/twig/twig/lib/Twig/Loader/Filesystem.php +++ b/core/vendor/twig/twig/lib/Twig/Loader/Filesystem.php @@ -233,7 +233,7 @@ protected function parseName($name, $default = self::MAIN_NAMESPACE) protected function normalizeName($name) { - return preg_replace('#/{2,}#', '/', strtr((string) $name, '\\', '/')); + return preg_replace('#/{2,}#', '/', str_replace('\\', '/', (string) $name)); } protected function validateName($name) diff --git a/core/vendor/twig/twig/lib/Twig/Loader/String.php b/core/vendor/twig/twig/lib/Twig/Loader/String.php index e7fff3e..9bfd856 100644 --- a/core/vendor/twig/twig/lib/Twig/Loader/String.php +++ b/core/vendor/twig/twig/lib/Twig/Loader/String.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -@trigger_error('The Twig_Loader_String class is deprecated since version 1.18.1 and will be removed in 2.0. Use Twig_Loader_Array instead.', E_USER_DEPRECATED); +@trigger_error('The Twig_Loader_String class is deprecated since version 1.18.1 and will be removed in 2.0. Use Twig_Loader_Array instead or Twig_Environment::createTemplate().', E_USER_DEPRECATED); /** * Loads a template from a string. diff --git a/core/vendor/twig/twig/lib/Twig/Node/For.php b/core/vendor/twig/twig/lib/Twig/Node/For.php index 36e9de8..a8d199a 100644 --- a/core/vendor/twig/twig/lib/Twig/Node/For.php +++ b/core/vendor/twig/twig/lib/Twig/Node/For.php @@ -39,8 +39,7 @@ public function compile(Twig_Compiler $compiler) { $compiler ->addDebugInfo($this) - // the (array) cast bypasses a PHP 5.2.6 bug - ->write("\$context['_parent'] = (array) \$context;\n") + ->write("\$context['_parent'] = \$context;\n") ->write("\$context['_seq'] = twig_ensure_traversable(") ->subcompile($this->getNode('seq')) ->raw(");\n") diff --git a/core/vendor/twig/twig/lib/Twig/Profiler/Profile.php b/core/vendor/twig/twig/lib/Twig/Profiler/Profile.php index ec9e254..104bc05 100644 --- a/core/vendor/twig/twig/lib/Twig/Profiler/Profile.php +++ b/core/vendor/twig/twig/lib/Twig/Profiler/Profile.php @@ -86,6 +86,16 @@ public function addProfile(Twig_Profiler_Profile $profile) */ public function getDuration() { + if ($this->isRoot() && $this->profiles) { + // for the root node with children, duration is the sum of all child durations + $duration = 0; + foreach ($this->profiles as $profile) { + $duration += $profile->getDuration(); + } + + return $duration; + } + return isset($this->ends['wt']) && isset($this->starts['wt']) ? $this->ends['wt'] - $this->starts['wt'] : 0; } diff --git a/core/vendor/twig/twig/lib/Twig/Template.php b/core/vendor/twig/twig/lib/Twig/Template.php index e2ab05a..36d4162 100644 --- a/core/vendor/twig/twig/lib/Twig/Template.php +++ b/core/vendor/twig/twig/lib/Twig/Template.php @@ -305,6 +305,33 @@ public function getBlocks() } /** + * Returns the template source code. + * + * @return string|null The template source code or null if it is not available + */ + public function getSource() + { + $reflector = new ReflectionClass($this); + $file = $reflector->getFileName(); + + if (!file_exists($file)) { + return; + } + + $source = file($file, FILE_IGNORE_NEW_LINES); + array_splice($source, 0, $reflector->getEndLine()); + + $i = 0; + while (isset($source[$i]) && '/* */' === substr_replace($source[$i], '', 3, -2)) { + $source[$i] = str_replace('*//* ', '*/', substr($source[$i], 3, -2)); + ++$i; + } + array_splice($source, $i); + + return implode("\n", $source); + } + + /** * {@inheritdoc} */ public function display(array $context, array $blocks = array()) diff --git a/core/vendor/twig/twig/lib/Twig/Test/IntegrationTestCase.php b/core/vendor/twig/twig/lib/Twig/Test/IntegrationTestCase.php index 96892a4..1ec575e 100644 --- a/core/vendor/twig/twig/lib/Twig/Test/IntegrationTestCase.php +++ b/core/vendor/twig/twig/lib/Twig/Test/IntegrationTestCase.php @@ -17,10 +17,44 @@ */ abstract class Twig_Test_IntegrationTestCase extends PHPUnit_Framework_TestCase { - abstract protected function getExtensions(); + /** + * @return string + */ abstract protected function getFixturesDir(); /** + * @return Twig_ExtensionInterface[] + */ + protected function getExtensions() + { + return array(); + } + + /** + * @return Twig_SimpleFilter[] + */ + protected function getTwigFilters() + { + return array(); + } + + /** + * @return Twig_SimpleFunction[] + */ + protected function getTwigFunctions() + { + return array(); + } + + /** + * @return Twig_SimpleTest[] + */ + protected function getTwigTests() + { + return array(); + } + + /** * @dataProvider getTests */ public function testIntegration($file, $message, $condition, $templates, $exception, $outputs) @@ -34,7 +68,7 @@ public function testIntegration($file, $message, $condition, $templates, $except */ public function testLegacyIntegration($file, $message, $condition, $templates, $exception, $outputs) { - $this->testIntegration($file, $message, $condition, $templates, $exception, $outputs); + $this->doIntegrationTest($file, $message, $condition, $templates, $exception, $outputs); } public function getTests($name, $legacyTests = false) @@ -72,7 +106,7 @@ public function getTests($name, $legacyTests = false) $tests[] = array(str_replace($fixturesDir.'/', '', $file), $message, $condition, $templates, $exception, $outputs); } - if (!$tests) { + if ($legacyTests && empty($tests)) { // add a dummy test to avoid a PHPUnit message return array(array('not', '-', '', array(), '', array())); } @@ -107,6 +141,18 @@ protected function doIntegrationTest($file, $message, $condition, $templates, $e $twig->addExtension($extension); } + foreach ($this->getTwigFilters() as $filter) { + $twig->addFilter($filter); + } + + foreach ($this->getTwigTests() as $test) { + $twig->addTest($test); + } + + foreach ($this->getTwigFunctions() as $function) { + $twig->addFunction($function); + } + // avoid using the same PHP class name for different cases // only for PHP 5.2+ if (PHP_VERSION_ID >= 50300) { @@ -119,7 +165,7 @@ protected function doIntegrationTest($file, $message, $condition, $templates, $e $template = $twig->loadTemplate('index.twig'); } catch (Exception $e) { if (false !== $exception) { - $this->assertEquals(trim($exception), trim(sprintf('%s: %s', get_class($e), $e->getMessage()))); + $this->assertSame(trim($exception), trim(sprintf('%s: %s', get_class($e), $e->getMessage()))); return; } @@ -137,7 +183,7 @@ protected function doIntegrationTest($file, $message, $condition, $templates, $e $output = trim($template->render(eval($match[1].';')), "\n "); } catch (Exception $e) { if (false !== $exception) { - $this->assertEquals(trim($exception), trim(sprintf('%s: %s', get_class($e), $e->getMessage()))); + $this->assertSame(trim($exception), trim(sprintf('%s: %s', get_class($e), $e->getMessage()))); return; } @@ -158,7 +204,7 @@ protected function doIntegrationTest($file, $message, $condition, $templates, $e $expected = trim($match[3], "\n "); - if ($expected != $output) { + if ($expected !== $output) { printf("Compiled templates that failed on case %d:\n", $i + 1); foreach (array_keys($templates) as $name) { diff --git a/core/vendor/twig/twig/test/Twig/Tests/EnvironmentTest.php b/core/vendor/twig/twig/test/Twig/Tests/EnvironmentTest.php index e4bef74..83a98ef 100644 --- a/core/vendor/twig/twig/test/Twig/Tests/EnvironmentTest.php +++ b/core/vendor/twig/twig/test/Twig/Tests/EnvironmentTest.php @@ -138,17 +138,28 @@ public function testGlobals() */ } + public function testCompileSourceInlinesSource() + { + $twig = new Twig_Environment($this->getMock('Twig_LoaderInterface')); + + $source = "\r\nbar\n"; + $expected = "/* */\n/* bar*/\n/* */\n"; + $compiled = $twig->compileSource($source, 'index'); + + $this->assertContains($expected, $compiled); + $this->assertNotContains('/**', $compiled); + } + public function testExtensionsAreNotInitializedWhenRenderingACompiledTemplate() { - $options = array('cache' => sys_get_temp_dir().'/twig', 'auto_reload' => false, 'debug' => false); + $cache = new Twig_Cache_Filesystem($dir = sys_get_temp_dir().'/twig'); + $options = array('cache' => $cache, 'auto_reload' => false, 'debug' => false); // force compilation $twig = new Twig_Environment($loader = new Twig_Loader_Array(array('index' => '{{ foo }}')), $options); - $cache = $twig->getCacheFilename('index'); - if (!is_dir(dirname($cache))) { - mkdir(dirname($cache), 0777, true); - } - file_put_contents($cache, $twig->compileSource('{{ foo }}', 'index')); + + $key = $cache->generateKey('index', $twig->getTemplateClass('index')); + $cache->write($key, $twig->compileSource('{{ foo }}', 'index')); // check that extensions won't be initialized when rendering a template that is already in the cache $twig = $this @@ -164,7 +175,7 @@ public function testExtensionsAreNotInitializedWhenRenderingACompiledTemplate() $output = $twig->render('index', array('foo' => 'bar')); $this->assertEquals('bar', $output); - unlink($cache); + unlink($key); } public function testAddExtension() diff --git a/core/vendor/twig/twig/test/Twig/Tests/FileCachingTest.php b/core/vendor/twig/twig/test/Twig/Tests/FileCachingTest.php index 6f5bfee..14e0144 100644 --- a/core/vendor/twig/twig/test/Twig/Tests/FileCachingTest.php +++ b/core/vendor/twig/twig/test/Twig/Tests/FileCachingTest.php @@ -38,6 +38,9 @@ public function tearDown() $this->removeDir($this->tmpDir); } + /** + * @group legacy + */ public function testWritingCacheFiles() { $name = 'index'; @@ -48,6 +51,9 @@ public function testWritingCacheFiles() $this->fileName = $cacheFileName; } + /** + * @group legacy + */ public function testClearingCacheFiles() { $name = 'index2'; diff --git a/core/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/replace_invalid_arg.test b/core/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/replace_invalid_arg.test index 08ecfd4..2143a86 100644 --- a/core/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/replace_invalid_arg.test +++ b/core/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/replace_invalid_arg.test @@ -3,6 +3,6 @@ --TEMPLATE-- {{ 'test %foo%'|replace(stdClass) }} --DATA-- -return array('stdClass' => new \stdClass()) +return array('stdClass' => new stdClass()) --EXCEPTION-- Twig_Error_Runtime: The "replace" filter expects an array or "Traversable" as replace values, got "stdClass" in "index.twig" at line 2. diff --git a/core/vendor/twig/twig/test/Twig/Tests/LegacyIntegrationTest.php b/core/vendor/twig/twig/test/Twig/Tests/LegacyIntegrationTest.php index 02ec3cb..055a617 100644 --- a/core/vendor/twig/twig/test/Twig/Tests/LegacyIntegrationTest.php +++ b/core/vendor/twig/twig/test/Twig/Tests/LegacyIntegrationTest.php @@ -22,6 +22,15 @@ public function getFixturesDir() { return dirname(__FILE__).'/LegacyFixtures/'; } + + public function getTests($name, $legacyTests = false) + { + if (!$legacyTests) { + return array(array('not', '-', '', array(), '', array())); + } + + return parent::getTests($name, true); + } } class LegacyTwigTestExtension extends Twig_Extension diff --git a/core/vendor/twig/twig/test/Twig/Tests/Node/ForTest.php b/core/vendor/twig/twig/test/Twig/Tests/Node/ForTest.php index b289592..b2c6fa4 100644 --- a/core/vendor/twig/twig/test/Twig/Tests/Node/ForTest.php +++ b/core/vendor/twig/twig/test/Twig/Tests/Node/ForTest.php @@ -51,7 +51,7 @@ public function getTests() $tests[] = array($node, <<getVariableGetter('items')}); foreach (\$context['_seq'] as \$context["key"] => \$context["item"]) { echo {$this->getVariableGetter('foo')}; @@ -73,7 +73,7 @@ public function getTests() $tests[] = array($node, <<getVariableGetter('values')}); \$context['loop'] = array( 'parent' => \$context['_parent'], @@ -116,7 +116,7 @@ public function getTests() $tests[] = array($node, <<getVariableGetter('values')}); \$context['loop'] = array( 'parent' => \$context['_parent'], @@ -149,7 +149,7 @@ public function getTests() $tests[] = array($node, <<getVariableGetter('values')}); \$context['_iterated'] = false; \$context['loop'] = array( diff --git a/core/vendor/twig/twig/test/Twig/Tests/Node/ModuleTest.php b/core/vendor/twig/twig/test/Twig/Tests/Node/ModuleTest.php index 5688af8..19a4be9 100644 --- a/core/vendor/twig/twig/test/Twig/Tests/Node/ModuleTest.php +++ b/core/vendor/twig/twig/test/Twig/Tests/Node/ModuleTest.php @@ -46,7 +46,7 @@ public function getTests() getMock('Twig_LoaderInterface')), false); + + $this->assertSame("\n", $template->getSource()); + } + /** * @dataProvider getGetAttributeWithSandbox */ @@ -463,6 +470,8 @@ public function getAttribute($object, $item, array $arguments = array(), $type = } } } +/* */ +/* */ class Twig_TemplateArrayAccessObject implements ArrayAccess {