Include Twig template which Extends - symfony

I am rendering a Twig template as below:
$this->render('base.html.twig');
The content (simplified) of this Twig template looks as below:
{% block headers %}
...
{% endblock %}
{% block pagecontent %}
...
{# I want to include another template (A) here #}
{# I want to include another template (B) here #}
{% endblock %}
{% block footers %}
...
{% endblock %}
I have another Twig template which I am not rendering, but I want to include in the above template (where I have placed my Twig comment). The content is as follows:
{% extends '::base' %}
{% block headers %}
{{ parent() }}
{% endblock %}
{% block pagecontent %}
{{ parent() }}
...
{% endblock %}
I want to eventually render several Twig templates inside of base.html.twig.
Is what I am attempting to do achievable, and if so, how do I achieve it?

You just need to render child template (the one extending base.html.twig).
Change in your controller:
$this->render('child_template_extending_base.html.twig');
Replace child_template_extending_base with your real template name.
You can also embed another controllers views in your template with this code:
{{ render(controller(
'AppBundle:Article:recentArticles',
{ 'max': 3 }
)) }}
Read more about this feature here: http://symfony.com/doc/current/book/templating.html#embedding-controllers

base.html.twig
{% block headers %}
...
{% endblock %}
{% block pagecontent %}
...
{# I want to include another template (A) here #}
{# I want to include another template (B) here #}
{% endblock %}
{% block footers %}
...
{% endblock %}
Your controller:
$this->render('base.html.twig');
Normally, $this->render('view.html.twig'); accepts only one twig.
If you want to have several templates, you can build it like this:
view.html.twig
{% extends '::base' %}
{% block pagecontent %}
{# Controller function with template 1 #}
{{ render(controller('AppBundle:Article:recentArticles',{ 'max': 3 })) }}
{# Controller with template 2 #}
{{ render(controller('AppBundle:Article:relatedArticles',{ 'max': 4 })) }}
{% endblock %}
ANOTHER POSSIBLE SOLUTION IS :
You can break one block into several blocks.

Related

SonataAdminBundle templates - list and show fields template content duplication

My list and show fields contain the same content, but due the extending of base_list_field and base_show_field templates I have to create two separate templates.
list/location.html.twig:
{% extends 'SonataAdminBundle:CRUD:base_list_field.html.twig' %}
{% block field %}
{{ object.getCity }}, {{ object.getCountry.getName }}
{% endblock %}
show/location.html.twig:
{% extends 'SonataAdminBundle:CRUD:base_show_field.html.twig' %}
{% block field %}
{{ object.getCity }}, {{ object.getCountry.getName }}
{% endblock %}
As you can see huge part of code is duplicated. Is there a way to check the page I am currently in in twig and then extend certain base template? In this case I would be able to use one file instead of two for same content.
In twig it's possible to extend/include a dynamic template :
{# do test here on which page you are or pass through controller #}
{% if true %}
{% set template = 'SonataAdminBundle:CRUD:base_show_field.html.twig' %}
{% else %}
{% set template = 'SonataAdminBundle:CRUD:base_list_field.html.twig' %
{% endif %}
{% extends template %}
{% block field %}
{{ object.getCity }}, {{ object.getCountry.getName }}
{% endblock %}
(edit) if you don't want the hardcoded if I would pass the template variable through the controller and change the twig template to something like
{% extends template|default('SonataAdminBundle:CRUD:base_show_field.html.twig') %}

Twig simple overriding with include

I have a simple Twig template, were I wan to override a block from the include.
base.html.twig:
{% block razem %}
{% include '_ga.code.html.twig' %}
{% endblock %}
_ga.code.html.twig:
{% block wspolny %}
should be common
{% endblock %}
{% block googleAnalitics %}
for overridden
{% endblock %}
success.html.twig
{% extends 'base.hmtl.twig' %}
{% block razem %}
{{ parent('wspolny') }}
{% block googleAnalitics %}
overriding part
{% endblock %}
{% endblock %}
Where is the error? http://twigfiddle.com/jsuk6a
I expected to render something like this:
should be common
overriding part
In twig you can not override blocks in a include. For this you have to use embed, but have to do this in the using template, not in the base one.
base.html.twig:
{% block razem %}{% endblock %}
_ga.code.html.twig:
{% block wspolny %}
should be common
{% endblock %}
{% block googleAnalitics %}
for overridden
{% endblock %}
success.html.twig
{% extends 'base.hmtl.twig' %}
{% block razem %}
{% embed '_ga.code.html.twig' %}
{% block googleAnalitics %}
overriding part
{% endblock %}
{% endembed %}
{% endblock %}
I think that the best way to override a block and reuse some others is to extend the base template where you want to perform an overriding (maybe adding some code to the pre-existing one) and to apply the so called horizontal reuse:
Horizontal reuse is an advanced Twig feature that is hardly ever needed in regular templates. It is mainly used by projects that need to make template blocks reusable without using inheritance.
Starting from that point, you should simply use the base.html.twig template and extend _ga.code.html.twig as follows:
success.html.twig
{% extends '_ga.code.hmtl.twig' %}
{# Simply use base - without overriding #}
{% use 'base.hmtl.twig' %}
{% block googleAnalitics %}
overriding part
{% endblock %}
If you want to make an overload of a single block you could also use the parent() function; so, you can add some other information to an extended block.
If you need something more complex you should go for dynamic inheritance.
{% extends ['base.html.twig', '_ga.code.html.twig'] %}

How to pass a block to an included template?

The structure of my Twig files looks like this:
- "skeleton_main"
- includes "skeleteon_header"
- render "block content"
- "skeleteon_header" should render "block breadcrumb"
- "partial"
- extends "skeleton_main"
- fills "block breadcrumb"
Now I can output "block breadcrumb" in "sekeleton_main" but it isn't passed to "skeleton_header". How can I access and render the block from within the included template? I tried using {% include '' with {} %} but without luck.
# skeleton_main
{% include 'header' %}
{% block content %}{% endblock %}
# header
{% block breadcrumb %}{% endblock %}
# partial
{% extends 'skeleton_main' %}
{% block breadcrumb %} Breadcrumb {% endblock %}
{% block content %} Content {% endblock %}
Maybe there's something wrong with this approach?
You are using include which does not permit overriding blocks.
Is there a reason to use include instead of extend ?
Another solution would be to use embed which does the same function as include, but permits overriding blocks at the same time:
http://twig.sensiolabs.org/doc/tags/embed.html
I think you have a wrong approch.
You should define header as a block, not as a separate template.
{# skeleton_main #}
{% block header %}
{% block breadcrumb %}{% endblock %}
{% endblock %}
{% block content %}{% endblock %}
{# partial #}
{% extends 'skeleton_main' %}
{% block breadcrumb %} Breadcrumb {% endblock %}
{% block content %} Content {% endblock %}

Twig use function multiple parameter

I am looking for using function "{% use %}" with multiple parameter in twig template.
all page template
{% use "common.html.twig" with
container as containerParent,
title as titleParent
%}
{# Some code ... #}
common.html.twig
{% block title %}{{ block(titleParent) }} - Admin{% endblock %}
{% block container %}
{# Some code ... #}
{{ block(containerParent) }}
{# Some code ... #}
{% endblock %}
When I tried that, my block container and title are not modified.
Maybe I didn't understood the doc ? http://twig.sensiolabs.org/doc/tags/use.html
I just want have access to function twig {{ parent() }} in my twig file which is included by {% use ... %}
Any suggestion ?
Sorry for my English, I am learning it...

Override block within included template in Twig

Currently using Symfony2 and Twig, I'm trying to override block within an included template. Let me explain :
{# base.html.twig #}
{% block content %}{% endblock content %}
<!--Some html Code -->
{% block javascripts %}
<!--Some scripts included like jQuery-->
{% endblock javascripts %}
In a other file:
{# page.html.twig #}
{% extends 'base.html.twig' %}
{% block content %}
{% include 'form.html.twig' %}
{% endblock content %}
And finally:
{# form.html.twig #}
<form method="post" action="something">
</form>
{# I am trying somehow to override the "javascripts" block here,
unfortunately I didn't figured out how to to that
#}
{% block javascripts %}
{{ parent() }}
<!--Some JS here-->
{% endblock javascripts %}
Is there a way to do what I want ?
What you need here is multiple inheritance. But just like php, twig does not have multiple inheritance. And just like php has traits, twig has a palliative for this called use. Remember that twig is compiled to php. I think a block that is used in a use statement ends up compiled in a trait.
First, create your a "trait" with the blocks you want to reuse in different places:
{% block my_form %}
<form method="post" action="something">
</form>
{% endblock %}
{% block form_specific_javascript %}
<!--Some JS here-->
{% endblock}
Then, in your page template, call the "trait", and reuse the blocks:
{# page.html.twig #}
{% extends 'base.html.twig' %}
{% block content %}
{% use 'form.html.twig' %}
{{ block('my_form') }}
{% endblock content %}
{# override the javascript block #}
{% block javascripts %}
{{parent()}}
{{block('form_specific_javascript')}}
{% endblock %}
So as you see, you can't do it all from the form template, you have to do some
wiring in your page template. Still, calling a block is better than copy / pasting
its contents, isn't it ?
Since i was looking for the same answer and actually found the solution.
It lies within TWIG with the embed tag.
Available in twig version 1.8, embed tag allows us to "include" a template, which has its own defined blocks who can then be overriden.
More information here: http://twig.sensiolabs.org/doc/tags/embed.html
You could just simply include form.html.twig within the javascripts block
base.html.twig
{% block content %}
<!--Some html Code -->
{% endblock content %}
{% block javascripts %}
<!--Some scripts included like jQuery-->
{% endblock javascripts %}
page.html.twig
{% extends 'base.html.twig' %}
{% block javascripts %}
{{ parent() }}
{% include 'form.html.twig' %}
{% endblock javascripts %}
form.html.twig
<!--Some JS here-->
I have exactly the same problem. I was looking for solution, but I didn't find any. Unfortunately include, embed and use does not solve this problem. But I figured two possible workarounds.
Option 1 (simpler, but needs more code)
Separate form into two files _form.html.twig and _form_js.html.twig and import them in the appropriate blocks.
Option 2
Invert hierarchy of templates. Extend form directly from base.
# form.html.twig
{% extends 'layouts/base.html.twig' %}
{% block body %}
{{ block('page_header') }}
{{ form_start(form) }}
{{ form_widget(form) }}
{{ form_end(form) }}
{% endblock %}
{% block javascripts %}
{{ parent() }}
<script>
# ...
</script>
{% endblock %}
And then extend form in other templates like new and edit.
# new.twig.html
{% extends 'form.html.twig' %}
{% block page_header %}
# custom content here
{% endblock %}
Using your own files, this is the approach I used and it worked for me:
{# base.html.twig #}
{% block content %}
{% endblock %}
<!--Some html Code -->
{% block javascripts %}
<script>console.log('1st print')</script>
{% endblock %}
In other file:
{# page.html.twig #}
{% extends 'base.html.twig' %}
{% block content %}
<h1>Welcome to page.html.twig.</h1>
<p>Here is a form for you to complete:</p>
{{ block("content", "form.html.twig") }}
{% endblock %}
{% block javascripts %}
{{ parent() }}
<script>console.log('2nd print')</script>
{{ block("formjavascripts", "form.html.twig") }}
{% endblock %}
And finally:
{# form.html.twig #}
{% block content %}
<form method="post" action="something">
</form>
{% endblock %}
{% block formjavascripts %}
<script>console.log('3rd print')</script>
{% endblock %}
Please notice the use of block function, you can find more info here https://twig.symfony.com/doc/3.x/functions/block.html
Also notice I used "formjavascripts" you could have used "javascripts" as well because that is the block name being retrieved from forms.html.twig file.
Note: You could try using Block function again in forms.html.twig and see if you can do a 4th print and call a 4th twig file! (Not sure if this last thing will work though :P)

Resources