How do I access a member in Twig determined by a variable?
Solution 1
I wrote my own twig extension to do this. You would use it in the way that I wanted:
{% set keyVariable = 'propertyName' %}
{{ obj.access(keyVariable) }}
{# the above prints $obj->propertyName #}
Here is it:
// filename: Acme/MainBundle/Extension/AccessTwigExtension.php
namespace Acme\MainBundle\Extension;
class AccessTwigExtension extends \Twig_Extension
{
public function getFilters()
{
return array(
'access' => new \Twig_Filter_Method($this, 'accessFilter'),
);
}
public function getName()
{
return 'access_twig_extension';
}
// Description:
// Dynamically retrieve the $key of the $obj, in the same order as
// $obj.$key would have done.
// Reference:
// http://twig.sensiolabs.org/doc/templates.html
public function accessFilter($obj, $key)
{
if (is_array($obj)) {
if (array_key_exists($key, $obj)) {
return $obj[$key];
}
} elseif (is_object($obj)) {
$reflect = new \ReflectionClass($obj);
if (property_exists($obj, $key) && $reflect->getProperty($key)->isPublic()) {
return $obj->$key;
}
if (method_exists($obj, $key) && $reflect->getMethod($key)->isPublic()) {
return $obj->$key();
}
$newKey = 'get' . ucfirst($key);
if (method_exists($obj, $newKey) && $reflect->getMethod($newKey)->isPublic()) {
return $obj->$newKey();
}
$newKey = 'is' . ucfirst($key);
if (method_exists($obj, $newKey) && $reflect->getMethod($newKey)->isPublic()) {
return $obj->$newKey();
}
}
return null;
}
}
To use it in my program, I also had to add a few lines to my dependency injection:
//filename: Acme/MainBundle/DependencyInjection/AcmeMainInjection.php
// other stuff is here....
public function load(array $configs, ContainerBuilder $container)
{
// other stuff here...
$definition = new Definition('Lad\MainBundle\Extension\AccessTwigExtension');
$definition->addTag('twig.extension');
$container->setDefinition('access_twig_extension', $definition);
// other stuff here...
Solution 2
Short answer: not directly / natively possible ... yet.
Apparently they added a new function to Twig 1.2 called attribute() which addresses exactly that need.
But as up to this day you can only download Twig 1.1.2; so 1.2 is probably not shipped with SF2 - though I cannot find a version number. (1.2 is available now!)
I tried to solve that with different tricks, but to no avail; 1.2 will fix it.
New in version 1.2: The attribute function was added in Twig 1.2.
attribute can be used to access a “dynamic” attribute of a variable:
{{ attribute(object, method) }}
{{ attribute(object, method,arguments) }}
{{ attribute(array, item) }}
But what you can do though is add a method to your class that takes care of whatever you need. something like that:
php:
class C
{
public $a = 1;
public $b = 2;
public function getValueForKey($k)
{
return $this->$k;
}
}
[ providing an instance of C to the template as 'obj' ]
twig:
{% set x = "a" %}
{{ obj.getValueForKey(x) }}
will output '1'
Solution 3
Use brackets syntax: bldg[key]
Related videos on Youtube
Robert Martin
Latte art is much, much more difficult than even I imagined.
Updated on June 04, 2022Comments
-
Robert Martin almost 2 years
I want to do the following code:
{% set rooms = [] %} {% set opts = { 'hasStudio': 'Studio', 'has1Bed': '1 BR', 'has2Bed': '2 BR', 'has3Bed': '3 BR', 'has4BedPlus': '4 BR+' } %} {% for key, val in opts %} {% if bldg.{key} is none %} {# PROBLEM HERE.. HOW TO FIND THIS MEMBER!? #} {{ val }}? {% elseif bldg.{key} %} {{ val }} {% else %} No {{ val }} {% endif %} {% endfor %}
How do I call the member properties of bldg that are named by the value of
key
? I want to get the values ofbldg.hasStudio bldg.has1Bed bldg.has2Bed etc....
-
Robert Martin over 12 yearsThanks for the info. My problem with this solution is that I didn't want to muddy my Entity classes with getters that are only there because twig needs them...
-
Ajay Patel over 10 yearsattribute feature in twig 1.2 is awesome