F21 F21 - 1 year ago 85
Twig Question

Parse/search for a certain function in twig templates

In the latest version of twig, customer functions are to be implemented as

s as the old method is being deprecated.

I have a custom translation function for dealing with message formatters using resource bundles:

{{ trans('key') }}

I am building a PHP script to go through all my templates to retrieve those keys. I do not wish to render the templates in this script because I do not have all the variables to pass to the template. Functions are not called when a template is loaded using
(which is important for performance), so I will need a lexer to parse my templates.

Unfortunately, there haven't really been much information regarding this, so it's hard to tell where to start.

How does one go about adding a customer lexer to parse functions like
{{ trans('key') }}

Alternatively, if there's a better/simpler way to achieve this, I would certainly love to know!

F21 F21
Answer Source

The solution is quite simple really. We need to grab all templates, load each template and then run the parser on it to generate the AST. Then we just walk through the AST to pick out the things we want. There's no need to compile the template.

Here's how this can be done:

public function process($node) 
    // Process nodes that are function expressions
    if ($node instanceof \Twig_Node_Expression_Function) {
        // Check the function name
        if ($node->getAttribute('name') == 'trans') {
            // Grab the argument
            foreach ($node->getNode('arguments') as $argument) { 
                $key = eval('return ' . $this->twig->compile($argument) . ';' );

                if (!in_array($key, $translationKeys)) {
                    $this->trans[] = $key;

                // I only needed the first argument in my implementation

    // Recursively loop through the AST
    foreach ($node as $child) {
        if ($child instanceof \Twig_Node) {

Tip: If you are loading templates from external files, not strings, then you need to use getContent() to get the template in text form:

$parsed = $twig->parse($twig->tokenize($loader->getSource($template)));