Encodera

Thanks for reading!

Donate to the site — we work hard for you.

Contents

Caching

A heavy database query or a call to an external service need not run every time a page is opened. The result is saved in a cache and served ready-made for a while. Symfony has the CacheInterface service for that.

Get or compute

use Symfony\Contracts\Cache\CacheInterface;
use Symfony\Contracts\Cache\ItemInterface;
 
#[Route('/', name: 'home')]
public function index(CacheInterface $cache, PostRepository $posts): Response
{
    $popular = $cache->get('popular_posts', function (ItemInterface $item) use ($posts) {
        $item->expiresAfter(3600);
 
        return $posts->findPopular(10);
    });
 
    return $this->render('home.html.twig', ['popular' => $popular]);
}

The get() method looks an item up by key. If there is none, it runs the function, saves the result and returns it. expiresAfter() sets the lifetime in seconds.

Deleting

When data changes, the item is deleted — on the next access it is computed again:

$cache->delete('popular_posts');

Keys with parameters

$post = $cache->get('post_' . $id, function (ItemInterface $item) use ($id, $posts) {
    $item->expiresAfter(600);
 
    return $posts->find($id);
});

Tags

Tags let you reset a whole group of items at once:

use Symfony\Contracts\Cache\TagAwareCacheInterface;
 
public function index(TagAwareCacheInterface $cache): Response
{
    $popular = $cache->get('popular_posts', function (ItemInterface $item) {
        $item->tag(['posts']);
 
        return $this->posts->findPopular(10);
    });
 
    // …
}
$cache->invalidateTags(['posts']);

Where the cache is stored

By default — in files in the var/cache folder. Busy sites connect Redis:

# config/packages/cache.yaml
framework:
    cache:
        app: cache.adapter.redis
        default_redis_provider: '%env(REDIS_URL)%'

The application code does not change.

Clearing

php bin/console cache:pool:clear cache.app
php bin/console cache:clear

The first command removes application data, the second Symfony's internal cache: settings, routes, templates.

Caching a response

A whole page can be cached — in the browser and on intermediate servers:

use Symfony\Component\HttpKernel\Attribute\Cache;
 
#[Route('/about', name: 'about')]
#[Cache(maxage: 3600, public: true)]
public function about(): Response
{
    return $this->render('about.html.twig');
}

Only pages identical for every visitor are cached this way.

Common mistake

A cache without deletion shows stale data: the post was changed, and the old title stays on the home page for another hour. For every cached item decide when it becomes wrong, and delete it at that moment — after saving the entity. And mind the keys: the characters {}()/\@: are not allowed in them.

Thanks for reading!

Donate to the site — we work hard for you.