ChatGPT解决这个技术问题 Extra ChatGPT

How to access class constants in Twig?

I have a few class constants in my entity class, e.g.:

class Entity {
    const TYPE_PERSON = 0;
    const TYPE_COMPANY = 1;
}

In normal PHP I often do if($var == Entity::TYPE_PERSON) and I would like to do this kind of stuff in Twig. Is it possible?


m
message

Just to save your time. If you need to access class constants under namespace, use

{{ constant('Acme\\DemoBundle\\Entity\\Demo::MY_CONSTANT') }}

Its important to note that the double slashes are important. I wasted a few minutes because I didn't put the double backslashes in.
Wow, that's ugly :-) It would be nice if Twig could make constants look like other properties / variables. eg {% if var == object.MY_CONSTANT %}
f
frzsombor
{% if var == constant('Namespace\\Entity::TYPE_PERSON') %}
{# or #}
{% if var is constant('Namespace\\Entity::TYPE_PERSON') %}

See documentation for the constant function and the constant test.


You should add testing contants with object instance to your anwser {% if var is constant('TYPE_PERSON', object) %}
Worked when i typed the namespace, like @message's message.
a
alexfv

As of 1.12.1 you can read constants from object instances as well:

{% if var == constant('TYPE_PERSON', entity)

This only works if entity is an instance of Entity, I think that the question is about accessing a constant without a defined object in the template.
In that case you just write {{ constant('Namespace\\Classname::CONSTANT_NAME') }} (doc)
What's good about this is that it makes it easy to use a Twig variable instead of a string literal as the constant name.
Just for clarity. If you want to pass constants within a class as twig vriable and use it like {{ constant('TYPE_PERSON', entity) }}, it's possible to do following (instantiate Entity class) $this->render('index.html.twig', ['entity' => new Entity()]);
I wonder if you can use constant('SOME_CONSTANT', form.getFoo()) where getFoo() returns the custom FormType PHP class.
D
Dmitriy Apollonin

If you are using namespaces

{{ constant('Namespace\\Entity::TYPE_COMPANY') }}

Important! Use double slashes, instead of single


C
Community

Edit: I've found better solution, read about it here.

Read more about how to create and register extension in Twig documentation.

Read about Twig extensions in Symfony2 documentation.

Let's say you have class:

namespace MyNamespace;
class MyClass
{
    const MY_CONSTANT = 'my_constant';
    const MY_CONSTANT2 = 'const2';
}

Create and register Twig extension:

class MyClassExtension extends \Twig_Extension
{
    public function getName()
    { 
        return 'my_class_extension'; 
    }

    public function getGlobals()
    {
        $class = new \ReflectionClass('MyNamespace\MyClass');
        $constants = $class->getConstants();

        return array(
            'MyClass' => $constants
        );
    }
}

Now you can use constants in Twig like:

{{ MyClass.MY_CONSTANT }}

So defining a entire twig extension for each class is less "ugly" than using {{ constant('Acme\\DemoBundle\\Entity\\Demo::MY_CONSTANT') }} ? And what do you do when your class names overlaps ? you loose all the benefit of namespaces here
I have a similar solution, I might extract this to a bundle though. The problem with this solution is that you have reflection overhead. In symfony you can write a compiler pass to resolve this when the container is compiled.
@0x1gene You are right, class names can overlap. I silently assumed that MyClass is not just any class, but a class which is very important within project. And used often enough so using constant() with FQN would be bothersome.
@DamianPolac do you know PHPStorm will prompt variable selection in twig file?
C
Chrysweel

In book best practices of Symfony there is a section with this issue:

Constants can be used for example in your Twig templates thanks to the constant() function:

// src/AppBundle/Entity/Post.php
namespace AppBundle\Entity;

class Post
{
    const NUM_ITEMS = 10;

   // ...
}

And use this constant in template twig:

<p>
    Displaying the {{ constant('NUM_ITEMS', post) }} most recent results.
</p>

Here the link: http://symfony.com/doc/current/best_practices/configuration.html#constants-vs-configuration-options


D
Damian Polac

After some years I realized that my previous answer is not really so good. I have created extension that solves problem better. It's published as open source.

https://github.com/dpolac/twig-const

It defines new Twig operator # which let you access the class constant through any object of that class.

Use it like that:

{% if entity.type == entity#TYPE_PERSON %}


Thanks for the idea, I'd never thought of this! If you'd like to use entity class names without instantiating objects, for example User#TYPE_PERSON, the NodeExpression class could be changed to something like this, which worked for me: ->raw('(constant(\'App\\Entity\\' . $this->getNode('left')->getAttribute('name') . '::' . $this->getNode('right')->getAttribute('name') . '\'))'). Of course, this limits your classes to the App\Entity namespace, but I think that covers the most common use case.