Video Tutorial Create a shared block
Today I propose to answer a question that is asked me quite often on Symfony: How to manage a common element between several pages (sidebar, footer) that uses dynamic elements.
The wrong approach: Global variable
The first approach, which may seem most obvious at first glance, is to use a global variable that we will inject into all Twig views.
# config / packages / twig.yaml
twig:
globals:
sidebar: '@App Twig SidebarService'
This approach is not ideal because the variable will be loaded with twig (even if the variable is not used by one of your pages).
The right approach: Create a twig function
A better solution is to create a twig function that can be used later only if needed.
We can just return variables to use in the view:
{% set data = sidebar ()%}
Latest articles
{% for post in data.posts%}
- {{post.title}}
{% endfor%}
But we can also use dependency injection to use twig in our function.
postRepository = $ postRepository;
$ this-> twig = $ twig;
$ this-> commentRepository = $ commentRepository;
}
public function getFunctions (): array
{
return (
new TwigFunction ('sidebar', ($ this, 'renderSidebar'), ('is_safe' => ('html')))
);
}
This allows to directly render the HTML content.
private function renderSidebar (): string
{
$ posts = $ this-> postRepository-> findForSidebar ();
$ comments = $ this-> commentRepository-> findForSidebar ();
return $ this-> twig-> render ('partials / sidebar.html.twig', (
'posts' => $ posts,
'comments' => $ comments
));
}
Cache cache!
If the content of your block is not very dynamic it may be interesting to use the cache so as not to repeat external calls unnecessarily.
It will be necessary to use a system of cache which implements the interface TagAwareInterface
to tag our cache for simpler invalidation later.
public function getSidebar (): string {
return $ this-> cache-> get ('sidebar', function (ItemInterface $ item) {
$ item-> tag (('comments', 'posts'));
return $ this-> renderSidebar ();
});
}