October 9, 2017 Javier Eguiluz

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