diff --git a/CHANGELOG b/CHANGELOG index f1354f9d8..9224bbf6d 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -15,6 +15,7 @@ * 1.22.0 (2015-XX-XX) + * 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(), diff --git a/doc/recipes.rst b/doc/recipes.rst index 2d24b8507..cb0fa557a 100644 --- a/doc/recipes.rst +++ b/doc/recipes.rst @@ -334,24 +334,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) +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), + // ... + )); + +.. note:: + + Before Twig 1.22, you should extend ``Twig_Environment`` instead:: + + class OpCacheAwareTwigEnvironment extends Twig_Environment { - parent::writeCacheFile($file, $content); + protected function writeCacheFile($file, $content) + { + parent::writeCacheFile($file, $content); - // 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); + // Compile cached file into bytecode cache + if (function_exists('opcache_invalidate') && ini_get('opcache.enable')) { + opcache_invalidate($file); + } elseif (function_exists('apc_compile_file') && ini_get('apc.enabled')) { + apc_compile_file($file); + } } } - } Reusing a stateful Node Visitor ------------------------------- @@ -481,16 +490,26 @@ 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. +<<<<<<< HEAD Rendering a Template Stored in a String --------------------------------------- The ``template_from_string`` Twig function allows a template stored in a string to be rendered from another template: +======= +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):: +>>>>>>> 1.x .. code-block:: jinja {{ include(template_from_string("Hello {{ name }}")) }} +<<<<<<< HEAD Doing the same in PHP is also possible:: $twig = new \Twig_Environment(new \Twig_Loader_Array(array())); @@ -498,5 +517,16 @@ Doing the same in PHP is also possible:: $template = $twig->createTemplate('Hello {{ name }}'); $rendered = $template->render(array('name' => 'Bob')); +======= +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. +>>>>>>> 1.x .. _callback: http://www.php.net/manual/en/function.is-callable.php diff --git a/lib/Twig/Cache/Filesystem.php b/lib/Twig/Cache/Filesystem.php index f3946016a..8675e0750 100644 --- a/lib/Twig/Cache/Filesystem.php +++ b/lib/Twig/Cache/Filesystem.php @@ -16,14 +16,19 @@ */ 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) + public function __construct($directory, $options = 0) { $this->directory = $directory; + $this->options = $options; } /** @@ -73,6 +78,15 @@ class Twig_Cache_Filesystem implements Twig_CacheInterface 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') && ini_get('opcache.enable')) { + opcache_invalidate($key); + } elseif (function_exists('apc_compile_file') && ini_get('apc.enabled')) { + apc_compile_file($key); + } + } + return; }