HTTP cache management with Symfony2 August 2012

Before reading this post, you should read the Symfony documentation about cache. As usual, it's clear, and it allows me to not have to explain everything :).

For this blog, the strategy I've chosen is this: to display a post, I use the its last modification date to define the "Last-Modified" HTTP header. If I see through the request that the client has already this version in the cache, then I can stop the process and return the 304 "Not Modified" HTTP code. Otherwise, I continue the process to serve the page to the client, so he can store it in his cache.

So my controller looks like this:

public function displayAction(Post $post)
{
    $response = new Response();
    $response->setLastModified($post->getModificationDate());
    $response->setPublic();

    if ($response->isNotModified($this->getRequest())) {
        return $response; // this will return the 304 if the cache is OK
    }

    // Do some stuff here...

    return $this->render('...:display.html.twig', array(
        'post' => $post,
        // ...
    ), $response);
}

The first 3 lines allow to define the strategy used for cache management. Note the setPublic() call to define that the cache is the same for all the users, and not private to the current user. It allows the shared caches (proxy caches and gateway caches) to also store the cache. Thereby, if user A has already displayed a post, user B can use the cache generated by user A, without generating the whole page. In my case, Symfony2 is the gateway cache.

Then I call the $response->isNotModified() method, giving the request as parameter. So it's the framework that decides if a 304 code must be returned or not, by comparing the "Last-Modified" header date (we've just defined it) with the "If-Modified-Since" header date provided by the client (the date of the post version he has in the cache). If the post hasn't been modified since it has been cached, we just have to return the response object, that represent the 304 "Not Modified" code.

Otherwise, we continue the controller process. In my case, I just need to prepare the comment form. Then I render the template. Don't forget to give the $response object as 3rd parameter of the $this->render() method, so the Last-Modified header will be added to the response; if you forget it, Symfony will create a default Response object, without any cache control header, so the clients will never store the page in the cache!

I'll soon talk about the edge side includes to handle the blog left column caching strategy, and about the event listeners to handle the post modification date, taking the comments into account...

See you later!

Tags: Symfony, cache