New in Symfony 3.4: Improved the overriding of templates
October 9, 2017 • Published by Javier Eguiluz
Warning: This post is about an unsupported Symfony version. Some of this information may be out of date. Read the most recent Symfony Docs.
Contributed by
Yonel Ceruto
in #24179,
#24264
and #24064.
In Symfony 3.4 we've deprecated bundle inheritance and in Symfony 4.0 we no longer recommend to use bundles for your own code, but overriding templates from third-party bundles is still a common need. That's why in Symfony 3.4 we've improved the overriding of templates in preparation for Symfony 4.
New overriding directory
In Symfony 2 and 3 applications, third-party bundle templates were overridden in
the app/Resources/<BundleName>/views/
directory. In Symfony 4 this directory
would have been moved to src/
, which doesn't look nice to store templates
now that we have a templates/
directory at the project root.
Therefore, in Symfony 3.4 we've created a new directory to override bundle
templates: templates/bundles/<BundleName>/
. For example, if you want to
customize error pages in a Symfony application:
1 2 3 4 5 6 7
{# Symfony 3.3 #}
{# app/Resources/TwigBundle/views/Exception/error404.html.twig #}
Page Not Found!
{# Symfony 3.4 #}
{# templates/bundles/TwigBundle/Exception/error404.html.twig #}
Page Not Found!
Overriding and extending templates
Sometimes you want to override a third-party bundle template but reuse most of
its contents, to avoid code duplication. Imagine that you want to override and
extend the layout.html.twig
template from FOSUserBundle:
1 2 3
{# templates/bundles/FOSUserBundle/layout.html.twig #}
{% extends '@FOSUser/layout.html.twig' %}
{# ... this doesn't work ... #}
If you try this example, you'll see "reached nested level" error because the simultaneous overriding and extending is similar to an infinite loop. In Symfony 3.4 we solved this problem creating a new and exclusive Twig namespace for each bundle.
The new namespace is the same as before but adding !
before the bundle name.
In this case, @FOSUser
refers to the normal Twig namespace which can include
third-party templates and your own overridden templates and @!FOSUser
refers
exclusively to the templates defined by the third-party bundle (no matter if
they have been overridden, you always get the original templates).
Using this new namespace, it's trivial to solve the previous problem:
1 2 3
{# templates/bundles/FOSUserBundle/layout.html.twig #}
{% extends '@!FOSUser/layout.html.twig' %}
{# ... this works as expected ... #}
Better debug:twig
command
Finally, to make these changes easier to debug, the debug:twig
command now
displays the full list of Twig namespaces and their associated file paths in the
same prioritized order used by Symfony.
Help the Symfony project!
As with any Open-Source project, contributing code or documentation is the most common way to help, but we also have a wide range of sponsoring opportunities.
Comments are closed.
To ensure that comments stay relevant, they are closed for old posts.
These features will allow alot of bundles to be overridable in a much better way! Defining standard blocks has never become so easy :)