Extending or including - what is better in Twig?
Why Twig documentation recommends to use extending rather than including? Symfony 2 documentation says because "In Symfony2, we li开发者_运维百科ke 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.
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.
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.
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>
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!
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
精彩评论