Twig variables in twig variable

I have a twig variable html. To show it in a twig template I do {{html}}.

That variable looks like:

<div>{{region_top}}</div><div>{{region_center}}</div>

region_* is a variable too. When Twig parses my html variable, it doesn't parse the inner variables (regions).

What I should do?


I have twig variable html. To show it in twig template I do {{html}}. That variable look like {{region_top}}{{region_center}}. region_* is variables too. When twig parse my html variable he didn't parse inner variables (regions). What can I should do?

Twig takes your strings as a literal string, meaning you'll see the content of the variable, escaped. If you want it to be able to display {{region_top}} as well, I'd recommend something like this:

{{html|replace({'{{region_top}}': region_top, '{{region_center}}': region_center})}}

If the content of your html variable is also dynamic (meaning it can contain more than just those two variables), I'd write a twig plugin which can do what you want. Writing plugins is pretty easy to do.

EDIT: Here's the extension I just finished writing.

EDIT 2: The extension now uses the environment to render the string, so it evaluates the string, instead of just replacing variables. This means your variable can contain anything a template can, and it will be render and escaped by Twig itself. I'm awesome.

<?php

/**
* A twig extension that will add an "evaluate" filter, for dynamic evaluation.
*/
class EvaluateExtension extends \Twig_Extension {
    /**
    * Attaches the innervars filter to the Twig Environment.
    * 
    * @return array
    */
    public function getFilters( ) {
        return array(
            'evaluate' => new \Twig_Filter_Method( $this, 'evaluate', array(
                'needs_environment' => true,
                'needs_context' => true,
                'is_safe' => array(
                    'evaluate' => true
                )
            ))
        );
    }

    /**
     * This function will evaluate $string through the $environment, and return its results.
     * 
     * @param array $context
     * @param string $string 
     */
    public function evaluate( \Twig_Environment $environment, $context, $string ) {
        $loader = $environment->getLoader( );

        $parsed = $this->parseString( $environment, $context, $string );

        $environment->setLoader( $loader );
        return $parsed;
    }

    /**
     * Sets the parser for the environment to Twig_Loader_String, and parsed the string $string.
     * 
     * @param \Twig_Environment $environment
     * @param array $context
     * @param string $string
     * @return string 
     */
    protected function parseString( \Twig_Environment $environment, $context, $string ) {
        $environment->setLoader( new \Twig_Loader_String( ) );
        return $environment->render( $string, $context );
    }

    /**
     * Returns the name of this extension.
     * 
     * @return string
     */
    public function getName( ) {
        return 'evaluate';
    }
}

Example usage:

$twig_environment->addExtension( new EvaluateExtension( ) );

In the template:

{% set var = 'inner variable' %}
{{'this is a string with an {{var}}'|evaluate}}

See http://twig.sensiolabs.org/doc/functions/template_from_string.html

It seems that this is frequently missed as most folks think (and search for) "eval" when expecting a filter/function to evaluate in the current language they're drafting in. Template from string isn't the first search query that comes to mind.


One option is to render your templates as strings. You can do that like this:

$env = new \Twig_Environment(new \Twig_Loader_String());
echo $env->render(
  "Hello {{ name }}",
  array("name" => "World")
);

I'll leave it to you to decide how exactly to structure your code to make this work, but it might go something like this: 1) Fetch the inner template text that contains the variables that aren't being replaced. 2) Render that inner template text into an $html variable. Be sure to pass in any vars you need. 3) Render your original template that contains {{html}}. Be sure to pass in 'html' => $html in the vars array


You can also pass an array or an object to the view, and then use the twig attribute() method: http://twig.sensiolabs.org/doc/functions/attribute.html

{% if attribute(array, key) is defined %}
    {{ attribute(array, key) }}
{% endif %}