73

Is it possible to check if given variable is string in Twig ?

Expected solution:

messages.en.yml:

hello:
  stranger: Hello stranger !
  known: Hello %name% !

Twig template:

{% set title='hello.stranger' %}
{% set title=['hello.known',{'%name%' : 'hsz'}] %}

{% if title is string %}
  {{ title|trans }}
{% else %}
  {{ title[0]|trans(title[1]) }}
{% endif %}

Is it possible to do it this way ? Or maybe you have better solution ?

1

5 Answers 5

162

Can be done with the test iterable, added in twig1.7, as Wouter J stated in the comment :

{# evaluates to true if the users variable is iterable #}
{% if users is iterable %}
    {% for user in users %}
        Hello {{ user }}!
    {% endfor %}
{% else %}
    {# users is probably a string #}
    Hello {{ users }}!
{% endif %}

Reference : iterable

1
  • 2
    Note: other objects can also be iterable even though they are not an array. Iterable is not a true test if something is an array. I have an answer how to make an array test like {% if value is array %} below. stackoverflow.com/a/29642662/417822 Commented Apr 30, 2015 at 16:37
15

Ok, I did it with:

{% if title[0] is not defined %}
    {{ title|trans }}
{% else %}
    {{ title[0]|trans(title[1]) }}
{% endif %}

Ugly, but works.

1
  • dont even need the "is not defined" bit Commented Jun 29, 2023 at 2:41
15

I found iterable to not be good enough since other objects can also be iterable, and are clearly different than an array.

Therefore adding a new Twig_SimpleTest to check if an item is_array is much more explicit. You can add this to your app configuration / after twig is bootstrapped.

$isArray= new Twig_SimpleTest('array', function ($value) {
    return is_array($value);
});
$twig->addTest($isArray);

Usage becomes very clean:

{% if value is array %}
    <!-- handle array -->
{% else %}
    <!-- handle non-array -->
{% endif % }
5
  • 2
    A sidenote here : This test will return false for every custom object implementing ArrayAcces, Traverseable, ...
    – DarkBee
    Commented May 1, 2015 at 9:09
  • 1
    Right, but the core issue is that not all iterable items are equal. The structure of an iterable can look different depending on type. Commented Jun 10, 2015 at 16:50
  • 1
    Where this class file should be put in Symfony2?
    – Aerendir
    Commented Aug 14, 2015 at 12:27
  • 1
    Not sure for Symfony2. You'll need to find a spot during your app boot or early on in a controller - but after twig has been loaded. Commented Aug 14, 2015 at 13:43
  • 2
    You put your test into a TwigExtension subclass (in the getTests method), register it as a service, and add the tag twig.extension to the service definition. The tag is what makes the TwigBundle take care of the addExtension for you. More details here: symfony.com/doc/current/templating/twig_extension.html Commented May 15, 2017 at 6:44
4

There is no way to check it correctly using code from the box. It's better to create custom TwigExtension and add custom check (or use code from OptionResolver).

So, as the result, for Twig 3, it will be smth like this

class CoreExtension extends AbstractExtension
{
    public function getTests(): array
    {
        return [
            new TwigTest('instanceof', [$this, 'instanceof']),
        ];
    }

    public function instanceof($value, string $type): bool
    {
        return ('null' === $type && null === $value)
               || (\function_exists($func = 'is_'.$type) && $func($value))
               || $value instanceof $type;
    }
}
-3

Assuming you know for a fact that a value is always either a string or an array:

{% if value is iterable and value is not string %}
    ...
{% else %}
    ...
{% endif %}

This worked good enough for me in a project I was working on. I realize you may need another solution.

1
  • 1
    Which version of twig are you using then? Can't reproduce
    – DarkBee
    Commented Jul 29, 2021 at 4:39

Not the answer you're looking for? Browse other questions tagged or ask your own question.