Mantener el contenido de la barra de navegación dinámica separado del código del controlador - 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).

Algo como esto tal vez:

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.

preguntado el 05 de mayo de 13 a las 18:05

1 Respuestas

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 Herencia de plantilla)

Cache the embedded fragment separately from the page html:

You can use a reverse proxy (like Barniz, o el caché de aplicaciones), 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.

Para información ver: http://symfony.com/doc/2.1/book/templating.html#asynchronous-content-with-hinclude-js

contestado el 05 de mayo de 13 a las 19:05

Hi. Thanks for the help. I may be mistaken, but I think there are two problems with this: (1) I mentioned I want to ignore JS (2) I have no static content that could be included in a CDN - it is all database generated with lots of processing. I just want to keep generation of dynamic nav bar parts (which change on every page request) separate to the controller generation (e.g. a controller which generates search results) - so the controller part could be cached for say 30 minutes, but the nav bars would always be fresh. I don't think ESI is the best thing personally. - user2143356

If you are looking to cache the whole controller output (doesn't matter if its generated from a db, after the view is rendered is cacheable like a static content), a reverse proxy is one of the easiest way. Amazon CloudFront can be used as a reverse proxy (see: aws.typepad.com/aws/2010/11/…). - Madarco

Ok, thanks. I think I'm getting the idea. Also, these ESI-embedded pages. Don't they (the first time before they are cached) conduct a number of HTTP requests (one for each part). That doesn't sound great performance to me. - user2143356

Yes, Varnish will fetch the embedded part AFTER the after it has loaded the first part. Howver, ESI per se is quite complete as a language, you can use conditionals to send the content in the page for the first request, and get the embedded parts for the subsequent: esi-examples.akamai.com/viewsource/ad.html - Madarco

I know you didn't want to use JS, but the asynchronous load of the navbar can be a simpler way. And since it applies only to authenticated users, it doesn't affect SEO. (However since we are effectively decoupling the main page from the navbar, there are always two requests to be done in the worst case scenario) - Madarco

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.