Mark Notton
Mark Notton

Reputation: 5076

Can I extract an associative array into variables?

Lets say I have an associative array like so:

{% set settings = { 'foo':'bar', 'cat':'mouse', 'apple':'banana' } %}

To use this data I would do the following:

{{ settings.foo }}
{{ settings.cat }}
{{ settings.apple }}

However, I wondered if there is a way to extract the keys to variables, and the values to values? Essentially the same as the PHP Extract function. So I can just do this instead:

{{ foo }}
{{ cat }}
{{ apple }} 

My very amateurish attempt to do this started out like this:

{% for key,val in settings %}
  {% set key = val %}
{% endfor %}

But obviously that doesn't work (or I wouldn't be here). Is there another approach I could take?

Thanks,

Mark

Upvotes: 0

Views: 1259

Answers (1)

DarkBee
DarkBee

Reputation: 15622

As most things in Twig this can be done by extending Twig

ProjectTwigExtension.php

class ProjectTwigExtension extends Twig_Extension {

    public function getFunctions() {
        return array(
            new Twig_SimpleFunction('extract', array($this, 'extract'), ['needs_context' => true, ]),
        );
    }

    public function extract(&$context, $value) {
        foreach($value as $k => $v) $context[$k] = $v;
    }       

    public function getName() {
        return 'ProjectTwigExtension';
    }        
}

Register class in Twig

$twig = new Twig_Environment($loader);
$twig->addExtension(new ProjectTwigExtension());

template.twig

{{ extract({'foo': 'bar', }) }}
{{ foo }} {# output : bar #}

(sidenote) Seems you can't do this by using a closure (see example below) because the compiler of Twig passes the variables in an array, thus creating a copy

With closure

$twig->addFunction(new Twig_SimpleFunction('extract',   function (&$context, $value) {
    foreach($value as $k => $v) $context[$k] = $v;
}, ['needs_context' => true, ]));

Compiled result

echo twig_escape_filter($this->env, call_user_func_array($this->env->getFunction('extract')->getCallable(), array($context, array("foo" => "bar", "foobar" => "foo"))), "html", null, true);

Upvotes: 3

Related Questions