Check if a variable is defined AND truthy at once in Twig
Asked Answered
C

3

25

In PHP I can do

<?php if ($someVar): ?>

This checks if a variable exists and if its value is different from a zero-like value like 0, null, '', and so on.

Is there any way to do so in Twig or do I need to write my own filter for that? At the moment, I must do

{% if someVar is defined and someVar %}

which is a pain when it comes to more complex templates.

Clemmie answered 17/1, 2018 at 13:22 Comment(0)
S
31

There are (at least) two ways of doing this without extending Twig. A third option is to extend Twig by creating e.g. a Twig function. I would probably choose the first way (using the default filter).


By using the default filter

As @The_Unknown pointed out, you can also use the default filter:

{% if someVar|default(null) %}

You can omit passing the default value to the filter, and even omit the parentheses. Then the value will default to an empty string (which is falsey). I.e. these two are equal and valid:

{% if someVar|default() %}
{% if someVar|default %}

Whichever style you choose (default to null, omit the value or omit the parens), stick to it. Be consistent.

See TwigFiddle for a demonstration that truthy values evaluate to true and falsey values evaluate to false (based on the table below).


By setting strict_variables to false

By setting the environment variable strict_variables to false, you can skip the if someVar is defined part and do just {% if someVar %}. As described in Twig's documentation:

strict_variables boolean

If set to false, Twig will silently ignore invalid variables (variables and or attributes/methods that do not exist) and replace them with a null value. When set to true, Twig throws an exception instead (default to false).

Set the variable to false when creating a Twig_Environment instance:

$twig = new Twig_Environment($loader, ['strict_variables' => false]);

If someVar is undefined, then {% if someVar %} is obviously false. The if tag's documentation page describes the edge case rules for defined variables:

The rules to determine if an expression is true or false are the same as in PHP; here are the edge cases rules:

Value                     Boolean evaluation

empty string              false
numeric zero              false
whitespace-only string    true
empty array               false
null                      false
non-empty array           true
object                    true

See TwigFiddle for a demonstration (strict_variables is set to false behind the "More options..." link in the header).


By extending Twig

(Disclaimer: I wrote this approach before @The_Unknown pointed out that the default filter can also be used.)

If the idea of setting strict_variables to false is too general, you can also extend Twig. I'd argue that it's better to set strict_variables to true to avoid accidental errors caused by e.g. typos in variable names, so this approach might be better.

I don't think that you can create a filter to do this, as an undefined variable would still throw an exception. You might be able to create a custom tag, test or extension (see Extending Twig for ways to extend Twig); I'm going to create a custom function as it's probably the simplest approach.

$twig->addFunction(new Twig_Function('istruthy', function($context, $var) {
     return array_key_exists($var, $context) && $context[$var];
 }, ['needs_context' => true]));

The ['needs_context' => true] part is essential here, as then you will have access to $context, which contains the variables present in the current context. (You can e.g. put var_dump($context) above the return statement to see it yourself.)

If you want istruthy to support checking multiple variables at once, you can do this:

$twig->addFunction(new Twig_Function('istruthy', function($context, ...$vars) {
     foreach ($vars as $var) {
         if (!array_key_exists($var, $context) || !$context[$var]) {
             return false;
         }
     }

     return true;
 }, ['needs_context' => true]));

Then in Twig you can do:

{% if istruthy('foo') %} ... {% endif %}

{% if istruthy('foo') or istruthy('bar') %} ... {% endif %}


{# These two are the same: #}

{% if istruthy('foo') and istruthy('bar') and istruthy('baz') %} ... {% endif %}

{% if istruthy('foo', 'bar', 'baz') %} ... {% endif %}


{# Ternary operator can also be used: #}

{{ istruthy('foo') ? 'yep' : 'nope' }}

You might want to check in the istruthy function whether the arguments are strings or something else and then act accordingly. array_key_exists expects the first argument to be either a string or an integer.

Spaulding answered 17/1, 2018 at 13:46 Comment(5)
Interesting, but seems like not a good idea to do so :-) It‘s very general.Clemmie
I agree that it's best to set strict_variables to true. I updated my answer with an alternative approach.Spaulding
Thanks for the answers. But I suspect, I found an even easier solution: what about {% if someVar|default() %}? It also works with arrays like {% if someArray.property|default() %}. Or do I get something wrong?Clemmie
After quick testing looks like it would also work. You can add your own answer or I can add it to my answer with details.Spaulding
@The_Unknown, I edited my answer with details about the default filter. Please feel free to add your own answer if you want as the idea of using the filter was yours. :-)Spaulding
C
6

The following works well:

{% if someVar ?? false %}
Commemorate answered 22/3, 2022 at 13:57 Comment(0)
H
0

In addition to what @matias-kinnunen and @Sébastien said, it's written in the documentation that we must use ?? syntax only when we're using boolean variables. Otherwise, we must use the default filter. It's valid for every version of Twig (1.x, 2.x, 3.x).

Hiero answered 11/4, 2023 at 22:35 Comment(1)
This does not provide an answer to the question. Once you have sufficient reputation you will be able to comment on any post; instead, provide answers that don't require clarification from the asker. - From ReviewGeriatric

© 2022 - 2024 — McMap. All rights reserved.