I have an ecommerce application that I'm try to set up for caching - initially via the Symfony2 Reverse Proxy, but then ultimately via Varnish in production. I'm using Symfony 2.1.8 on Apache2.
My problem is I cannot get the ESI tags to be re-checked for each request when the primary controller action is cached (important for private content like the basket contents), but I don't understand why.
For example, I cache the homepage with the following code:
public function indexAction(Request $request)
{
// check cache
$homepage = $this->getHomepage();
$response = new Response();
$response->setPublic();
$etag = md5('homepage'.$homepage->getUpdated()->getTimestamp());
$response->setETag($etag);
$response->setLastModified($homepage->getUpdated());
if ($response->isNotModified($request))
{
// use cached version
return $response;
}
else
{
return $this->render(
'StoreBundle:Store:index.html.twig',
array(
'page' => $homepage
),
$response
);
}
}
The rendered template extends the base layout template which includes the following ESI to show the basket:
{% render 'PurchaseBundle:Basket:summary' with {}, { 'standalone': true } %}
(Edit: After reading Diego's answer, I have also used the recommended syntax:
{% render url('basket_summary') with {}, {'standalone': true} %}
Unfortunately this had not made any difference.)
I've been playing with the code for the basket summary quite a bit, but this is what I have at present.
public function summaryAction()
{
$response = new Response();
$response->setPrivate();
$response->setVary(array('Accept-Encoding', 'Cookie'));
if ($this->basket->getId())
{
$etag = md5($this->getUniqueEtag());
$response->setLastModified($this->basket->getUpdated());
}
else
{
$etag = md5('basket_summary_empty');
}
$response->setETag($etag);
if ($response->isNotModified($this->request))
{
// use cached version
return $response;
}
else
{
return $this->render(
'PurchaseBundle:Basket:summary.html.twig',
array(
'basket' => $this->basket
),
$response
);
}
}
On pages other than the homepage (which are not cached yet) the basket summary caching works just fine, it always displays the correct data. It's only when you return to the homepage that you'd see outdated information. Logging confirms that summaryAction
is not called on the homepage unless indexAction
actually renders.
Using error_log($kernel->getLog())
after each page request I get this for a non-cached page:
GET /categories/collections: miss; GET /_internal/secure/PurchaseBundle:Basket:summary/none.html: stale, valid, store; GET /_internal/secure/CatalogBundle:Search:form/none.html: miss; GET /esi/menu/main: fresh
And this for the cached homepage:
GET /: fresh
I must be missing something obvious, but the documentation doesn't appear to cover this, yet it implies it's just the sort of thing ESI is supposed to be used for.
It appears that ESI in Symfony2 doesnt work with the Latmodified/Etag cache validation structure that you used. See here: https://groups.google.com/forum/?fromgroups=#!topic/symfony2/V4BItzpLbOs
Similar question here: Edge Side Includes and validation cache in Symfony 2
I've been trying to do the same as you, but can only get ESI to work by using expiration cache.