Skip to content

Instantly share code, notes, and snippets.

@carteni
Last active May 12, 2021 08:30
Show Gist options
  • Save carteni/8f58cb2f0389641a6214ef4d87b04a15 to your computer and use it in GitHub Desktop.
Save carteni/8f58cb2f0389641a6214ef4d87b04a15 to your computer and use it in GitHub Desktop.
[Twig] Refreshing modified Templates when OPcache or APC is enabled.
<?php
/**
* @file src/AppBundle/AppBundle.php
*/
namespace AppBundle;
use AppBundle\DependencyInjection\Compiler\TwigCacheFileSystemPass;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\HttpKernel\Bundle\Bundle;
class AppBundle extends Bundle
{
public function build(ContainerBuilder $container)
{
$container->addCompilerPass(new TwigCacheFileSystemPass());
}
}
<?php
/**
* @file src/AppBundle/DependencyInjection/Compiler/TwigCacheFileSystemPass.php
*/
/**
* 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, force Twig to invalidate the bytecode cache.
*/
namespace AppBundle\DependencyInjection\Compiler;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\Reference;
/**
* Class TwigCacheFileSystemPass
* @package AppBundle\DependencyInjection\Compiler
*/
class TwigCacheFileSystemPass implements CompilerPassInterface
{
/**
* You can modify the container here before it is dumped to PHP code.
*
* @param ContainerBuilder $container
*/
public function process(ContainerBuilder $container)
{
if (false === $container->hasDefinition('twig')) {
return;
}
// AppBundle\Twig\Cache\TwigCacheForceByteCodeRefreshFactory factory.
$container->register(
'app.twig.fileSystem_cache_refresh_factory',
'AppBundle\Twig\Cache\TwigCacheForceByteCodeRefreshFactory'
)
->addArgument($container->getParameter('kernel.cache_dir').'/twig')
->setPublic(false);
/** @var Definition $twigCacheFileSystem */
$twigCacheFileSystem = (
new Definition(
'Twig_Cache_Filesystem'
)
)
->setPublic(false)
->setFactory(
array(
new Reference('app.twig.fileSystem_cache_refresh_factory'),
'factory',
)
);
$options = array('cache' => $twigCacheFileSystem);
/** @var Definition $twigDef */
$twigDef = $container->findDefinition('twig');
$twigDef->replaceArgument(
1,
array_merge((array)$twigDef->getArgument(0), $options)
);
}
}
<?php
/**
* @file src/AppBundle/Twig/Cache/TwigCacheForceByteCodeRefreshFactory.php
*/
namespace AppBundle\Twig\Cache;
/**
* Class TwigCacheForceByteCodeRefreshFactory
* @package AppBundle\Twig\Cache
*/
class TwigCacheForceByteCodeRefreshFactory
{
private $cacheDir;
public function __construct($cacheDir)
{
$this->cacheDir = $cacheDir;
}
/**
* @return \Twig_Cache_Filesystem
*/
public function factory()
{
return new \Twig_Cache_Filesystem(
$this->cacheDir,
\Twig_Cache_Filesystem::FORCE_BYTECODE_INVALIDATION
);
}
}
@yellow1912
Copy link

It's weird that it's not yet a setting inside twig bundle.

@quentint
Copy link

I've forked it to work with Symfony 5, but I did not see any improvement: the cache is still not cleared on restart (ap hosted on Platform.sh).

Looking for a trick 😒

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment