5

I have enabled ESI in my Symfony 3 app and I have this in app_dev.php:

$kernel = new AppKernel('dev', true);
$kernel = new AppCache($kernel);

Now I have config.yml:

framework:
    esi: { enabled: true }
    fragments: { path: /_fragment }

In my controller:

/**
 * @Route("/foo/bar/{fooId}", name="AppBundle_Foo_bar")
 */
public function barAction(int $fooId, Request $request)
{
    //some database querying from repositroy
    $response = $this->render('AppBundle:Foo:bar.html.twig',['foo' => $foo]);
    $response->setETag(md5($response->getContent()));
    $response->setPublic();
    $response->isNotModified($request);

    return $response;
}

This is the view (bar.html.twig) that I want to cache and looks like:

{{foo}}

Now, I have another method that renders the main view.

/**
 * @Route("/baz/{fooId}", name="AppBundle_Foo_baz")
 * @Template
 */
public function bazAction(int $fooId)
{
    return [
        'fooId' => $fooId
    ];
}

And my baz.html.twig looks like:

{% extends 'AppBundle::layout.html.twig' %}
{% block content %}
    {{ render_esi(controller('AppBundle:Foo:bar', { 'fooId': fooId })) }}
{% endblock content %}

So I want to have mainly non cached view (baz) and nest barAction() inside it and have it cached.

But, I got:

Cache-Control:must-revalidate, no-cache, private 

even when I explicit set it to public, I got:

X-Symfony-Cache:GET /baz/1: miss; 

every time I refresh page and I got:

GET /_fragment?_hash=aO.....Details: stale, invalid, store 

and if I refresh invalid becomes valid. But I can't set cache.

EDIT:

I read about ESI and validation cache and it seems that they don't work together. So I tried validation cache and added

$response->setSharedMaxAge(15);
$response->headers->addCacheControlDirective('must-revalidate', true);

instead of ETag. And still same result...

KondukterCRO
  • 543
  • 2
  • 16
  • 31
  • I have followed your code/setup but I added a timestamp to be printed in `bar.html.twig`. It definitely caches the ESI block. The response headers you mentioned, are those on the main request or the ESI block? The main request still can be private even though you are caching public blocks. Try adding a timestamp to the template and see if it being cached or changes. – jkrnak Feb 19 '17 at 16:36
  • Hmm, I thought that when one controller is invoked in other headers will be merged. I will try to add timestamp to check cache. I'll add login button on main request, too. So when I log in via chrome it will print my username instead of login button and when I open page in firefox I should see login button not username from chrome session. I'll report results. – KondukterCRO Feb 21 '17 at 07:15
  • Try thinking of it outside of Symfony. ESI can be supported by many reverse proxies (eg: Varnish). In your case it's the AppCache class. What is happening when you got a reverse proxy which constructs the page that is being sent to the client: 1. proxy loads the page 2. checks for ESI include tags 3. if tag found makes another HTTP request for the block (or serves from cache if public or vary headers allow) 4. sends the constructed HTML to the client Note: be very careful with the blocks you cache, it should not contain private info (except when using vary but that's another story)! – jkrnak Feb 21 '17 at 08:38
  • Yes, you are right about that. I will try later today construct ESI from my example and report results. – KondukterCRO Feb 21 '17 at 08:47

0 Answers0