Symfony 6 Certification New exam with updated questions 100% online Show your expertise

New in Symfony 3.4: Improved the overriding of templates

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:

{# 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:

{# 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:

{# 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.

New in Symfony 3.4: Improved the overriding of templates

Tweet this


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

Comments are closed.

To ensure that comments stay relevant, they are closed for old posts.