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.
Would
extends FosUserBundle/Resources/views/layout.html.twig
work before Symfony 3.4 ?@Peierre-Charles: nope, this is why it has been added in 3.4 :)
These features will allow alot of bundles to be overridable in a much better way! Defining standard blocks has never become so easy :)
Nice! I have been confronted with this issue several times