48
votes

I use Symfony 2 with Twig and my question is pretty straightforward:

In a view I want to extend one of the layouts based on a variable. If the variable is false I want to extend UdoWebsiteBundle::layout.html.twig and if it's true I want to extend UdoWebsiteBundle::layout_true.html.twig.

Here is the code I tried:

{% block layout_extender %}

    {% if intro == 'false' %}
        {% extends 'UdoWebsiteBundle::layout.html.twig' %}
    {% else %}
        {% extends 'UdoWebsiteBundle::layout_true.html.twig' %}
    {% endif %}

{% endblock %}

I get this error:

Multiple extends tags are forbidden in "UdoWebsiteBundle:home:home.html.twig" at line 7

Is there any other way to achieve this?

5

5 Answers

61
votes

Try this one:

{% extends intro == 'false' 
    ? 'UdoWebsiteBundle::layout.html.twig' 
    : 'UdoWebsiteBundle::layout_true.html.twig' %}

Idea taken from here: http://jorisdewit.ca/2011/08/27/extending-different-layouts-for-ajax-requests-in-twig-symfony2/

18
votes

To keep it neat you should use Twig dynamic inheritance support by using a variable, defined in your controller, as the base template:

{% extends parent_template_var %}

If the variable evaluates to a Twig_Template object, Twig will use it as the parent template.

Define parent_template_var in your controller:

if($intro == 'false')
    $parent_template_var = 'UdoWebsiteBundle::layout.html.twig';
}else{
    $parent_template_var = 'UdoWebsiteBundle::layout_true.html.twig';
}
return $this->render('::/action.html.twig', array('parent_template_var' => $parent_template_var ));

http://twig.sensiolabs.org/doc/tags/extends.html

7
votes

Answer from the official documentation:

Conditional Inheritance

As the template name for the parent can be any valid Twig expression, it's possible to make the inheritance mechanism conditional:

{% extends standalone ? "minimum.html" : "base.html" %}

In this example, the template will extend the "minimum.html" layout template if the standalone variable evaluates to true, and "base.html" otherwise.

2
votes

You cannot extends multiple template, that's why you've got the error, if you want to so, you need to push them in an array like below.

{% extends ['MyAppCustomBundle::Layout/layout.html.twig', 'FOSUserBundle::layout.html.twig'] %}

But you will need to use Twig version 1.2 to do it. twig documentation

2
votes

This all makes sense to do either this template or that template.

But let me describe another situation. You have a profile form and a form where users can upload personal profile related documents. Since the profile form is already very long the documents moved to a new form.

Everything works great. Now we want to use the bootstrap tabs to do Profile | Documents for user friendliness.

Now I know because we are using two seperate forms if you submit the documents the changes on the profile won't save and vice versa.

I have added the document form in the tab using

<div role="tabpanel" class="tab-pane" id="documents">
    {{ render(controller('ManyAppBundle:Document:createDocument', {'viewOnly': true})) }}
</div>

The 'viewOnly': true is a query parameter and is not required by the action.

My question now becomes if the profile tab renders the document template it must only show the upload widget and the submit where as when you go directly to the document page it must show the title and side bar and everything. So I did try

{% if not viewOnly %}
    {% extends ... %}
{% endif %}

That gave problems because you can't use extends within a if. Like you suggested in other answers try using

{% extends viewOnly == true ? ... %}

This reolved the Twig issue up to the execution of the code when viewOnly is false.

When viewOnly is false it must extend the base template used by all other templates but if it is true I only want to show this:

{{ form_start(form, { 'style': 'horizontal', 'col_size': 'sm' }) }}
    {% if form.documents is defined %}
        {{ form_row(form.documents) }}
    {% endif %}

    {{ form_row(form.submit, { 'attr': { 'class': 'btn btn-success' } }) }}
{{ form_end(form) }}

But now with the top

{% extends viewOnly == true ? ... %}

if viewOnly becomes false it fails with Template "" can't be find.

Is there a way to say extends this specific template that will be the same result of not extending any template?

Or alternatively is there a way of saying extend this when viewOnly true but nothing happens on the fail?