Meliborn
Meliborn

Reputation: 6645

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?

Upvotes: 20

Views: 41801

Answers (4)

Berry Langerak
Berry Langerak

Reputation: 18859

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}}

Upvotes: 28

D. Rordorf
D. Rordorf

Reputation: 11

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 %}

Upvotes: 1

RealBlueSky
RealBlueSky

Reputation: 466

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.

Upvotes: 19

adavea
adavea

Reputation: 1602

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

Upvotes: 4

Related Questions