How to conditionally extend a template or import a Macro in Twig

The conditionals statements are the bread of everyday in the life of a programmer. Conditional statements are decisions that need to be made based on a certain condition: if the condition is met, a certain piece of code is executed. Thanks captain obvious. Why would I say something so obvious? Well, if you think in the obvious way with Twig when you want to extend conditionally your layout on some view for example using an if statement:

{# Example: THIS DOESN'T WORK #}

{% set condition = true %}

{# Check condition to see which layout to render #}

{% if condition %}
    {% extends '::layout_1.html.twig' %}
{% else %}
    {% extends '::layout_2.html.twig' %}
{% endif %}

You will get the following exception:

Multiple extends tags are forbidden in YourBundle:yourfile.html.twig at line X

Because as said in the error, you can't use the extends tag twice on a view. And now what? Probably you don't want to add more logic to your project with PHP to render some template because you can (or explicitly need to) verify it in the view, therefore it's good for you to know, that is possible to extend conditionally a template, however not in the way you expected. As the template name for the parent can be any valid Twig expression, it's possible to make the inheritance mechanism conditional with a shorthand if like syntax.

Conditional extend

To understand how this works, we'll use an analogy with PHP. The following function showText


function showText($text){
    echo $text;

To call it, we'll send just a string as first argument:


// Displays Hello World
showText("Hello World");

If you want to display some text according to a condition, then you can do:


$todayWillRain = true;

    showText("Today will rain");
    showText("There will be a lot of sun");

But that's much code for a simple thing to do, therefore a lot of developers would like to write a shorthand assign instead:


$todayWillRain = true;

// If today rains, it will show "Today will rain", otherwise "There will be a lot of sun"
    ($todayWillRain == true ? "Today will rain" : "There will be a lot of sun")

That's what the shorthand function does. Although the argument isn't inside an if statement, it's being evaluated with a shorthand if inside the parentheses and it returns a string anyway. This translated in twig for the extends function, would be:

{% extends (condition) ? ("template if its true") : ("template if its false") %}

Which means that you can simply extend different layouts according to a condition in your views following this mechanism:

{% set condition = true %}

    Using a boolean after the extends tag, allows you to
    use a shorthand if to render conditionally a layout

    In this case if the condition is true, then the
    layout 1 will be rendered, otherwise the layout 2
{% extends condition     
    ? '::layout_1.html.twig' 
    : '::layout_2.html.twig' %}

Conditional macro

Unlike the extends tag, import can obviously be used many times as you wish, so you can still assign a macro with a simple logic if statement:

{% set condition = true %}

{# Conditional declaration of "tools" #}
{% if condition  %}
    {% import "Macros/macro1_prod.html.twig" as tools %}
{% else%}    
    {% import "Macros/macro2_dev.html.twig"  as tools %}
{% endif %}

{# Use the macro as you need #}
{{ tool.someToolInsideMacro() }}

But if you want to make your code uncomplicated, sweet and shorter, you can assign the macro conditionally to tools using the same shorthand if statement as mentioned in the conditional extends:

{% set condition = true %}

{% import condition ? "Macros/macro1_prod.html.twig" : "Macros/macro2_dev.html.twig" as tools%}

{# Use the macro as you need #}
{{ tool.someToolInsideMacro() }}

Remember that the condition should return (as expected on every if statement) a boolean namely true or false. Usually the developers use the is_granted method to render a custom layout according to the role of the user.

Happy coding !

Become a more social person