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:clearThe 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.