Search code examples
phpsymfonytwigsymfony-cache

How to clear Twig cache fragments from Symfony?


I'm using the twig cache in a Symfony 5.4 project. If I cache something like:

{% cache "customer_1" ttl(3600) tags('customer') %}
Some HTML here
{% endcache %}

I need to be able to invalidate the twig cache with tag customer from within a Symfony controller or service.

I've tried autoloading Symfony\Contracts\Cache\TagAwareCacheInterface $twigCache (found from bin/console debug:autowiring) but this doesn't seem to work.

With this I called $twigCache->invalidateTags(['customer']), but does not appear to do nothing.

Is it possible to access and clear the twig cache from the Symfony side?


Solution

  • Apparently, you are doing it correctly.

    I have just set up a Symfony 5.4 project from scratch and tried it, and it works as expected.

    E.g.:

    composer create-project symfony/skeleton:"5.4.*" twig-cache-5.4
    cd twig-cache-5.4
    composer req twig
    composer req twig/cache-extra
    
    <?php declare(strict_types=1);
    
    namespace App\Controller;
    
    use Symfony\Component\HttpFoundation\Response;
    use Symfony\Component\HttpKernel\Attribute\AsController;
    use Symfony\Component\Routing\Annotation\Route;
    use Symfony\Contracts\Cache\TagAwareCacheInterface;
    use Twig\Environment;
    
    #[AsController]
    #[Route('/super-cache/{tag}', 'super')]
    readonly class SuperController
    {
    
        public function __construct(
            private Environment            $twig,
            private TagAwareCacheInterface $twigCache,
        )
        { }
    
        public function __invoke(?string $tag = null): Response
        {
    
            if ($tag !== null) {
                $this->twigCache->invalidateTags([$tag]);
            }
    
            return new Response($this->twig->render('super.html.twig'));
        }
    }
    

    And the template:

    {% extends 'base.html.twig' %}
    
    {% block body %}
    
    <H1>Hello, content</H1>
    
    {% cache "first-key" tags('foo') %}
        <p>Key "main-key", tag "foo" (cached at: {{ "now"|date("F jS \\a\\t g:ia") }})</p>
    {% endcache %}
    
    
    {% cache "second-key" tags('foo') %}
        <p>Key "second-key", tag "foo" (cached at: {{ "now"|date("F jS \\a\\t g:ia") }})</p>
    {% endcache %}
    
    {% cache "third-key" tags('bar') %}
        <p>Key "third-key", tag "bar" (cached at: {{ "now"|date("F jS \\a\\t g:ia") }})</p>
    {% endcache %}
    
    <p>This is some uncached content.</p>
    
    {% endblock %}
    

    I have verified with bin/console cache:pool:list that the pool twig.cache has been created, so I can autowire that pool directly with $twigCache.

    If I access /super-cache, the first time the template will be cached completely, and the "cached at" string won't change in following calls:

    Execution result

    Now accessing /super-cache/foo, the controller will invalidate the tag foo for the pool, and the template content will be refreshed accordingly (check the "created at" string on the first two blocks):

    Show results with cache invalidated

    Knowing that this should work as intended, you'll need to find if there is something else amiss in your setup.