31

Why Twig documentation recommends to use extending rather than including? Symfony 2 documentation says because "In Symfony2, we like to think about this problem differently: a template can be decorated by another one." but nothing more. It's just author's whim or something more? Thanks for help.

5 Answers 5

46

When to use inheritance:

You have 50 pages sharing the same layout - you create a layout.twig as a parent, and each page extends that layout.twig. So the parent is the generic and the child is the specific.

When to use include:

Out of the 50 pages, there are 6 pages that share a chunk of HTML - you create a shared-chunk.twig and include it in those 6 pages.

Another usage:

You notice that your layout.twig is bit cluttered and you would like to modularize it, so you split sidebar.twig into a separate file and include it in layout.twig.

Can you use include for the inheritance use-case:

Sure, create chunks for header, footer and what have you, and use includes in each of the 50 pages. But that's wrong design as explained above.

Can you use inheritance for the include use-case:

Sure, create an empty block for the shared chunk in the parent layout.twig, and create a second level child layout-with-chunk.twig that extends layout.twig and fills in the chunk block, and the 6 pages in the above example that share the chunk can then extend layout-with-chunk.twig instead of layout.twig. But this again is wrong design because the chunk block is not shared by all children and shouldn't go into the base parent. Plus you have cluttered the inheritance tree.

So:

As explained above - it's a matter of design not programmability. It's not about: I can achieve this same result using a different programming technique, its about which usage is better design.

1
  • "Sure, create chunks for header, footer... But that's wrong design as explained above." -- I don't think it's "wrong" if it fits your design or mindset better. But in general, you will probably have to use multiple includes (header+footer at a minimum) to mimic inheritance, which is probably less efficient and adds complexity.
    – Simon E.
    Oct 7, 2011 at 0:28
8

I liked Arms answer, but I think you missed what he said. Include and extend are different things: if you extend, you can change the parent, with an include you can not.

E.g. I extend my base layout, like so:

{% extends "layout/default.html" %}

What extending give me now, is to use the blocks from the parent! You don't have that with an include. Now you can e.g. make a title specifically for every page:

{% block title %}My title just for this page{% endblock %}

Now, including gives you more rigid and fixed html, e.g:

{% include 'header.html' %}

and at most maybe entitiy repitition, e.g. table rows:

{% include 'foo' with {'foo': 'bar'} %}

So you build your layouts with includes, and you extend your base layouts to make sure your site follows the designated design.

1
  • "What extending give me now, is to use the blocks from the parent! You don't have that with an include. " I have - {% set title %}My title just for this page{% endset %} and {{ title }}. It is the same functionality but in other direction, only difference is that - in block I can set default content in block but when I include, to set default content I must use condition.
    – Isinlor
    Aug 14, 2011 at 12:09
6

Just to add another, hybrid, option into the mix, you might consider embed as well. It lets you leverage the inheritance from extends but also allows multiple reuses like include does.

Trivial example:

"partials/titleize.twig":

<h2 class="title">{% block title %}Default Title{% endblock %}</h2>

"some-template.twig" will inherit from it using embed:

{% embed "partials/titleize.twig" %}
    {% block title %}Section 1{% endblock %}
{% endembed %}

...

{% embed "partials/titleize.twig" %}
    {% block title %}Section 2{% endblock %}
{% endembed %}

Renders

<h2 class="title">Section 1</h2>
...
<h2 class="title">Section 2</h2>
4

It depends on what you're trying to accomplish. By extending a view, you're using the Decorator pattern. If you're familiar with Symfony 1, this is the same as having your layout.php file which outputs $sf_content. You use this method when you have a common html 'shell' you want to use across the project.

Including a view on the other hand lets you inject one view in another.

Let's say you have a personal site with 'about' and 'contact' pages. You would have 3 views: base.html.twig
about.html.twig
contact.html.twig

base.html.twig contains the common HTML that your site uses across the board. This could include your header, navigation, footer etc (all the stuff that doesn't/shouldn't change across pages.)

about.html.twig and contact.html.twig contain ONLY the HTML for those specific sections. Both of these views extend base.html.twig. This eliminates code duplication. If you want to make a change to the header, you just need to make the change in one place - base.html.twig.

Now let's say you have some other piece of content you want to display on the 'about' and 'contact' pages (but not necessarily on other pages) - you could create a separate view for this and include it within about.html.twig and contact.html.twig.

The docs don't actually recommend extending over including, they're two separate methods that should be used for specific purposes.

Hope this helps!

6
  • OK, but wouldn't be easier to use only include? Base.html.twig would be: Header.html.twig and Footer.html.twig And About.html.twig will look like this: <code>include Header.html.twig include PieceOfContent.html.twig about etc include Footer.html.twig</code> I don't see any benefits from using extending. Althought, if Base.html.twig will look like this: <code>Header Block of specific content from about, contact etc Menu - the same for all pages Another block of specific content Footer</code> Then we will have 2 files less than using only include - that's all?
    – Isinlor
    Aug 13, 2011 at 23:07
  • Including header.html.twig and footer.html.twig in all the 'page' views of your site is bad programming. Those elements are common to your site, so they should be included only once, in base.html.php. Think about when you no longer want to include header.html.twig, but want to include someOtherHeader.html.twig. Now you have to change all the includes amongst your views. You're better off putting it in base.html.twig. The general rule of thumb is any HTML that gets repeated across your site belongs in base.html.twig Aug 13, 2011 at 23:44
  • Also, your example has a big problem: you're including header and footer twice. Once in base.html.twig, then once again in about.html.twig. You want about.html.twig to contain ONLY the HTML relevant to that page. The header and footer are completely separate from the about page, and your setup should reflect that. Aug 13, 2011 at 23:45
  • "Think about when you no longer want to include header.html.twig, but want to include someOtherHeader.html.twig." The same happens if I no longer want extends Base.html.twig but someOtherBase.html.twig. And about including twice - I had in mind header and footer instead of base, not with base ;).
    – Isinlor
    Aug 14, 2011 at 0:33
  • The layout (base.html.twig) is meant to contain the common HTML for your site, so that other views need only worry about displaying specific content. It's not a question of extend versus include, it's a question of when & where do you use both of them. You're going to quickly realize what a pain updating HTML can be site wide if you don't use a layout. Read up more on the decorator pattern and Symfony 1 templating to get a better idea. Aug 14, 2011 at 1:35
1

Twig extension is different and far more powerful than include. Try thinking about extension as coming at it from the opposite of the way you are thinking about include. With extension you can start with the end view (i.e. about.htm) and working backwards, adding the layers that you need to make the page on the site. At each level, with extension the blocks of content either overwrite or add to the parent content for that block.

"Include" isn't as flexible, you are starting with the base template and work your way out to the about.htm view, and you can't work with common blocks of content across the different files.

Check out this bit on three-level inheritance, which is a common extension pattern: http://symfony.com/doc/current/book/templating.html#three-level-inheritance

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.