user2143356
user2143356

Reputation: 5597

Keeping dynamic navigation bar content separate from the controller code - Symfony2

I'm new to Symfony2 and I've been thinking of the best way to generate navigation bar HTML that is used on every page request - especially with regards to caching.

So imagine if every page request shows the logged in user and a number indicating how many messages are unread (in fact like stackoverflow for that). I'm guessing that could be generated in every controller to ensure the info is up-to-date (using a function or something of course) - but I'm also looking at caching the whole controller output, and think it might be good to keep this dynamic part separate.

Would creating a controller extension for all this kind of stuff be a good way to go? So this way the controller only deals with that specific function (e.g. getting blog posts from a DB etc.) and the controller extension adds all the dynamic content. That way I can cache the controller result and speed up pages without caching the full page (which can't really be done due to lots of dynamic HTML content).

Something like this maybe:

class ControllerExtension extends Controller
{
    public function render($view, array $parameters = array(), Response $response = null)
    {

        //get number of messages for this user
        $parameters['messages'] =

        //are they logged in
        $parameters['logged_in'] =

        // render as normal
        return parent::render($view, $parameters, $response);

    }
}

For this I want to ignore use of JS. I know some of these things could be populated with JS, but I would prefer not for this.

Upvotes: 1

Views: 1192

Answers (1)

Madarco
Madarco

Reputation: 2114

You can solve this by caching the navbar fragment separably from the page html with ESI or Hinclude and can be simply and elegantly solved with Symfony2.

Embed a controller inside a template

You can render a controller inside a template:

<div id="sidebar">
    {% render url('latest_articles', { 'max': 3 }) %}
</div>

This will render the controller with the route "latest_articles", inside your html.

This can be done in you controller template, or in the global layout template (where you define the header, footer, js, css ecc of all your pages, see Template Inheritance)

Cache the embedded fragment separately from the page html:

You can use a reverse proxy (like Varnish, or the AppCache), to cache the two part of the html separately:

<div id="sidebar">
    {% render url('latest_articles', { 'max': 3 }, {'standalone': true}) %}
</div>

That's it, just add {'standalone': true}

You'll need an external program on front of your web server (like Varnish, or Nginx with a mod), but this is the fastest way.

Load the fragment with javascript:

You can also tell symfony to asynchronously load the fragment in javascript:

<div id="sidebar">
    {% render url('latest_articles', { 'max': 3 }, {'standalone': 'js'}) %}
</div>

This is a nice approach, since you can cache the entire html in a CDN (for example with Amazon CDN CloudFront), and still show user specific content.

For info see: http://symfony.com/doc/2.1/book/templating.html#asynchronous-content-with-hinclude-js

Upvotes: 4

Related Questions