How to retrieve all Variables from a Twig Template?

前端 未结 14 1474
抹茶落季
抹茶落季 2020-12-08 00:24

Is it possible to retrieve all variables inside a Twig template with PHP?

Example someTemplate.twig.php:

Hello {{ name }}, 
your new email is {{ ema         


        
14条回答
  •  一整个雨季
    2020-12-08 00:53

    I built a Twig2Schema class to infer variables from a Twig AST. To get the variables in a document, you need to recursively "walk" through the Twig AST and have rules in place when you encounter certain types of language nodes.

    This class extracts variable names from Nodes if they are not always defined, and also grabs variables from the value used in ForLoopNodes and IfStatements.

    To use it, you can either call infer for the whole template, or a subset of the tree using inferFromAst.

    getLoader()->getSourceContext($twigTemplateName);
            $tokens = $twig->tokenize($source);
            $ast = $twig->parse($tokens);
            return $this->inferFromAst($ast);
        }
    
        /**
         * @param \Twig\Node\ModuleNode $ast - An abstract syntax tree parsed from Twig
         * @return array - The variables used in the Twig template
         */
        public function inferFromAst(\Twig\Node\ModuleNode $ast)
        {
            $keys = $this->visit($ast);
    
            foreach ($keys as $key => $value) {
                if ($value['always_defined'] || $key === '_self') {
                    unset($keys[$key]);
                }
            }
    
            return $keys;
        }
    
        /**
         * @param \Twig\Node\Node $ast - The tree to traverse and extract variables
         * @return array - The variables found in this tree
         */
        private function visit(\Twig\Node\Node $ast)
        {
            $vars = [];
            switch (get_class($ast)) {
                case \Twig\Node\Expression\AssignNameExpression::class:
                case \Twig\Node\Expression\NameExpression::class:
                    $vars[$ast->getAttribute('name')] = [
                        'type' => get_class($ast),
                        'always_defined' => $ast->getAttribute('always_defined'),
                        'is_defined_test' => $ast->getAttribute('is_defined_test'),
                        'ignore_strict_check' => $ast->getAttribute('ignore_strict_check')
                    ];
                    break;
                case \Twig\Node\ForNode::class:
                    foreach ($ast as $key => $node) {
                        switch ($key) {
                            case 'value_target':
                                $vars[$node->getAttribute('name')] = [
                                    'for_loop_target' => true,
                                    'always_defined' => $node->getAttribute('always_defined')
                                ];
                                break;
                            case 'body':
                                $vars = array_merge($vars, $this->visit($node));
                                break;
                            default:
                                break;
                        }
                    }
                    break;
                case \Twig\Node\IfNode::class:
                    foreach ($ast->getNode('tests') as $key => $test) {
                        $vars = array_merge($vars, $this->visit($test));
                    }
                    foreach ($ast->getNode('else') as $key => $else) {
                        $vars = array_merge($vars, $this->visit($else));
                    }
                    break;
                default:
                    if ($ast->count()) {
                        foreach ($ast as $key => $node) {
                            $vars = array_merge($vars, $this->visit($node));
                        }
                    }
                    break;
            }
            return $vars;
        }
    }
    

提交回复
热议问题