Instanceof operator in Twig/Symfony 2?
Asked Answered
S

10

20

I've a mixed array like this one (mobile numbers and entities):

$targets = array();

$targets[] = '+32647651212';
$targets[] = new Customer();

In my Twig template i have to call getMobile() if target is a Customer or just print the number if it's actually a number (string).

Is there something like instanceof operator in Twig?

<ul>
{% for target in targets %}
   <li>{{ target instance of MyEntity ? target.getMobile : target }}</li>
   {% else %}
       <li>Nothing found.</li>
</ul>
Shipper answered 28/5, 2012 at 17:2 Comment(0)
P
45

In \Twig_Extension you can add tests

public function getTests()
{
    return [
        'instanceof' =>  new \Twig_Function_Method($this, 'isInstanceof')
    ];
}

/**
 * @param $var
 * @param $instance
 * @return bool
 */
public function isInstanceof($var, $instance) {
    return  $var instanceof $instance;
}

And then use like

{% if value is instanceof('DateTime') %}
Pameliapamelina answered 20/11, 2014 at 11:53 Comment(3)
Looks like \Twig_Function_Method is deprecated. I'm looking to do this in the current version of Twig - any pointer on how to replicate?Clotheshorse
Twig_Filter_MethodPameliapamelina
for me \Twig_SimpleTest() worked (from Zombkey's answer)Interdiction
B
23

UPDATE 10-2021

Please be aware this answer has been written for symfony 3, and twig 2. If you use a more recent version, please refer to the answer of @Garri Figueroa on this post.

As you can see in the twig documentation the class \Twig_Extension, \Twig_SimpleTest are now deprecated.

If you use a more recent version of symfony (I recommend it), please use the new class AbstractExtension, TwigFunction, etc https://symfony.com/doc/5.3/templating/twig_extension.html


OLD VERSION : symfony 3.4

Here a nice way to do instanceof operator in twig with Extension :

1) Create your extention file where you want

(ex: src/OC/YourBundle/Twig/InstanceOfExtension.php )

With \Twig_Extension you can do many things, filter, fonction, but now we will create a Test.

So we implement function getTests(), and inside it we create a new \Twig_SimpleTest

The 1st arugment is the name of test you create, and the seconde a callable. (can be a function() {}).

<?php

namespace OC\YourBundle\Twig;

class InstanceOfExtension extends \Twig_Extension {

    public function getTests() {
        return array(
            new \Twig_SimpleTest('instanceof', array($this, 'isInstanceOf')),
         );
     }

    public function isInstanceOf($var, $instance) {
        $reflexionClass = new \ReflectionClass($instance);
        return $reflexionClass->isInstance($var);
    }
}

2) Register it in services.yml

(ex: src/OC/YourBundle/Resources/config/services.yml)

services:

    [...may you have other services ...]

    app.twig_extension:
        class: OC\YourBundle\Twig\InstanceOfExtension
        public: false
        tags:
          - { name: twig.extension }

3) Then use it in twig like this

{{ myvar is instanceof('\\OC\\YourBundle\\Entity\\YourEntityOrWhatEver') }}

Source from Adrien Brault => https://gist.github.com/adrienbrault/7045544

Briefing answered 20/10, 2017 at 11:10 Comment(1)
This answer worked for me, the only thing I made different was to use the isInstanceOf method of @PameliapamelinaInterdiction
H
8

My solution for Symfony 4.3

1) Create the AppExtension class in src/Twig folder. (The class is automatically detected).

2) Extend the AbstractExtension class:

namespace App\Twig;

use Twig\Extension\AbstractExtension;
use Twig\TwigTest;

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

    /**
     * @param $var
     * @param $instance
     * @return bool
     */
    public function isInstanceof($var, $instance) {
        return  $var instanceof $instance;
    }
}

3) Then use same code of valdas.mistolis answer:

{% if value is instanceof('DateTime') %}

4) Thanks valdas.mistolis and symfony documentation i got my own solution: Twig Extension templating

Heartless answered 16/10, 2019 at 18:35 Comment(0)
P
5

Since PHP 5.5.0 you can compare class names next way:

{{ constant('class', exception) is constant('\\Symfony\\Component\\HttpKernel\\Exception\\HttpException') }}

This snippet can help in particular cases when you need strict comparison of class names. If you need to check implementation of interface or to check inheritance would be better to create twig extension described above.

Proboscidean answered 25/7, 2018 at 13:42 Comment(1)
actually, this code isn't working for me. Are you sure, its working? What's your twig version?Sheppard
A
1

Another example when iterating through Symfony forms:

namespace App\Twig;

use Twig\Extension\AbstractExtension;
use Twig\TwigTest;
use App\Document\Embeded\Image;
use App\Document\Embeded\Gallery;
use App\Document\Embeded\Article;

class AppExtension extends AbstractExtension
{
    public function getTests()
    {
        return [
            new TwigTest('image', [$this, 'isImage']),
            new TwigTest('gallery', [$this, 'isGallery']),
            new TwigTest('article', [$this, 'isArticle']),
        ];
    }

    public function isImage($var) {
        return $var instanceof Image;
    }

    public function isGallery($var) {
        return $var instanceof Gallery;
    }

    public function isArticle($var) {
        return $var instanceof Article;
    }
}

Twig

{% if form.vars.data is gallery %}
    This is a Gallery 
{% elseif  form.vars.data is article %}
    This is an Article
{% endif %}
Agree answered 12/5, 2020 at 7:28 Comment(0)
T
0

Another solution :

class A {
    ...
    public function isInstanceOfB() {
        return $this instanceof B;
    }
}

class B extends A {}
class C extends A {}

then in your twig :

{{ a.isInstanceOfB ? ... something for B instance ... : ... something for C instance ... }}

OR

{% if a.isInstanceOfB %}
    ... do something for B instance ...
{% else %}
    ... do something for C instance ...
{% endif %}
Tenuous answered 16/1, 2017 at 15:25 Comment(0)
K
0

Other solution without ReflectionClass with a twig filter :

First you need a TwigExtension class. Then, add a function as twig filter or twig function,

namespace App\Twig;

use Twig\Extension\AbstractExtension;
use Twig\TwigFilter;
use Twig\TwigFunction;

class TwigExtension extends AbstractExtension

    /**
     * @return array|\Twig_Filter[]
     */
    public function getFilters()
    {
        return [           
            new TwigFilter('is_instance_of', [$this, 'isInstanceOf'])
        ];
    }

    /**
     * @param $object
     * @param $class
     * @return bool
     */
    public function isInstanceOf($object, $class): bool
    {
        return is_a($object, $class, true);
    }
}

And in twig template :


{% if true is same as (object|is_instance_of('ClassName')) %}
   // do some stuff
{% endif %} 

Check http://php.net/manual/fr/function.is-a.php

Karie answered 10/5, 2018 at 12:47 Comment(1)
How is that usable in Twig context?Mincemeat
T
-1

From Symfony 5, this works:

{% if target is instanceof('DateTime') %}

You don't need Twig extension

Tanya answered 13/2, 2024 at 19:25 Comment(1)
this does not work without an extension. there is github.com/lelyfoto/twig-instanceof which enables the syntax you describeGag
C
-6

Use default filter in Twig like this:

{{ target.mobile|default(target) }}
Carminacarminative answered 28/5, 2012 at 19:15 Comment(1)
I don't think that's what he's asking for.Konstanze
G
-10

Quite old, but I can't see here one more good possibility to achive this:

Enity:

public function __toString()
{
    return 'NameOfYourEntity';
}

Twig:

{{ entity }}
Guyot answered 8/5, 2016 at 19:28 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.