0

If there any way to discover the variables required from a Twig template? Example, if I had:

Hello {{ user }}! You're {{ age }} years old, well done big man!

I'd be able to load this template and then gather each of the required variables, eventually allowing me to have something like:

Array ( [0] => user [1] => age )

The end goal of this is to be able to define a view and then have the system create a form based on the required variables in a template file.

2
  • Mind if I ask why do you want that? Commented Jan 11, 2013 at 16:43
  • @PedroCordeiro it says so in my last sentence :) Commented Jan 11, 2013 at 16:55

4 Answers 4

2

Working Solution

Thanks to morg for pointing me towards tokenize I was able to get what I wanted using the following (I placed it in my controller for testing):

$lexer = new \Twig_Lexer(new \Twig_Environment());
$stream = $lexer->tokenize(new \Twig_Source('{{test|raw}}{{test2|raw|asd}}{{another}}{{help_me}}', null));
$variables = array();
while (!$stream->isEOF()) {
    $token = $stream->next();
    if($token->getType() === \Twig_Token::NAME_TYPE){
        $variables[] = $token->getValue();
        while (!$stream->isEOF() && $token->getType() !== \Twig_Token::VAR_END_TYPE) {
            $token = $stream->next();
        }
    }
}
$variables = array_unique($variables);

This returns:

Array
(
    [0] => test
    [1] => test2
    [2] => another
    [3] => help_me
)

You'll notice I only get variables and not any of the functions (this is through design), although you could remove the nested while loop if you wish to get both variables and functions.

Sign up to request clarification or add additional context in comments.

1 Comment

Just suggested an edit for Twig 2.x, where tokenize expects a Twig_Source and don't accept a string. Note new \Twig_Environment() as well now needs a loader as its first parameter.
1

You can use the twig tokenizer for this.

$stream = $twig->tokenize($source, $identifier);

The tokenizer has a toString() Method, whose resulting string you can parse for

VAR_START_TYPE()
NAME_TYPE(varname)
VAR_END_TYPE()

Look at this for more detailed information.

Comments

0

You can try using preg_match_all('{{\s*(\w+)\s*}}', 'template {{string }} with {{ var}}', $matchesArray);. The $matchArray is structured as following:

Array(
     0 => array(0 => '{{string }}', 1 => 'string'),
     1 => array(0 => '{{ var}}', 1 => 'var')
)

2 Comments

I did consider this, but: a) it seems a bit hacky. b) it wouldn't take into consideration things like {{ var|raw }} or {{ var|customfunction(10) }}. I'm searching through twig now to see if theres a method I'm able to use or adapt
Searched in twig developer doc and didn't found anything. This regex might works better #{{\s*(\w+).*\s*}}#U. I know it might not be the cleanest way but the only one i can see so far.
0

Another way of doing this from inside PHP code is not elegant, but still more reliable than any regex will be:

$source = "My template string with {{ some }} parameters.";

$stream = $twig->tokenize(new \Twig_Source($source, "source"));

$matches = [];
preg_match_all(
    "/NAME_TYPE\((.*)\)/", $stream->__toString(), $matches
);

if (count($matches) > 1) {
    $params = array_unique($matches[1]);
} else {
    $params = [];
}

This works by using Twig internal mechanisms to tokenize the template string and then extract parameters names with a regex.

Edit: The previous version of my answer used the parse method to create a tree of nodes, but it didn’t seem to work anymore, and matching on NAME_TYPE at the previous step seems more reliable, not sure if I missed something there…

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.