How to retrieve all Variables from a Twig Template?

前端 未结 14 1369
抹茶落季
抹茶落季 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 01:00

    If you need all Twig elements inside of a text, just use:

    preg_match_all('/\{\%\s*(.*)\s*\%\}|\{\{(?!%)\s*((?:[^\s])*)\s*(?<!%)\}\}/i', $text, $matches);
    

    I had a issue where the WSIWYG editor placed HTML tags inside of Twig variables. I filter them with:

    public function cleanHTML($text)
    {
        preg_match_all('/\{\%\s*(.*)\s*\%\}|\{\{(?!%)\s*((?:[^\s])*)\s*(?<!%)\}\}/i', $text, $matches);
    
        if (isset($matches[0]) && count($matches[0])) {
            foreach ($matches[0] as $match) {
                $clean_match = strip_tags($match);
    
                $text = str_replace($match, $clean_match, $text);
            }
        }
    
        return $text;
    }
    

    UPDATE

    Use this expression to find all {{ }} and {% %}

    preg_match_all('/\{\%\s*([^\%\}]*)\s*\%\}|\{\{\s*([^\}\}]*)\s*\}\}/i', $text, $matches);
    
    0 讨论(0)
  • 2020-12-08 01:02

    Create a Twig_Extension and add a function with the needs_context flag:

    class MyTwigExtension extends Twig_Extension{
       public function getFunctions()
        {
            return array(
                new \Twig_SimpleFunction('myTwigFunction', array($this, 'myTwigFunction'), array('needs_context' => true)),
            );
        }
    
        public function myTwigFunction($context)
        {
            var_dump($context);
            return '';
        }
    }
    

    The context will be passed as first parameter to your function, containing all variables.

    On your Twig template you just have to call that function:

    {{myTwigFunction()}}
    

    If you need assistance on creating a Twig Extension, please refer to this documentation:

    http://twig.sensiolabs.org/doc/2.x/advanced.html

    0 讨论(0)
  • 2020-12-08 01:04

    I think 19Gerhard85's answer is pretty good, although it might need some tweaking because it matched some empty strings for me. I like using existing functions where possible and this is an approach mostly using twig's functions. You need access to your application's twig environment.

    /**
     * @param $twigTemplateName
     * @return array
     */
    public function getRequiredKeys($twigTemplateName)
    {
        $twig = $this->twig;
        $source = $twig->getLoader()->getSource($twigTemplateName);
        $tokens = $twig->tokenize($source);
        $parsed = $twig->getParser()->parse($tokens);
        $collected = [];
        $this->collectNodes($parsed, $collected);
    
        return array_keys($collected);
    }
    

    And the only custom part of it is the recursive function to collect only certain types of nodes:

    /**
     * @param \Twig_Node[] $nodes
     * @param array $collected
     */
    private function collectNodes($nodes, array &$collected)
    {
        foreach ($nodes as $node) {
            $childNodes = $node->getIterator()->getArrayCopy();
            if (!empty($childNodes)) {
                $this->collectNodes($childNodes, $collected); // recursion
            } elseif ($node instanceof \Twig_Node_Expression_Name) {
                $name = $node->getAttribute('name');
                $collected[$name] = $node; // ensure unique values
            }
        }
    }
    
    0 讨论(0)
  • 2020-12-08 01:05
    $loader1 = new Twig_Loader_Array([
        'blub.html' => '{{ twig.template.code }}',
    ]);
    $twig = new Twig_Environment($loader1);
    $tokens = $twig->tokenize($loader1->getSource('blub.html'));
    $nodes = $twig->getParser()->parse($tokens);
    
    var_dump($this->getTwigVariableNames($nodes));
    
    
    function getTwigVariableNames($nodes): array
    {
        $variables = [];
        foreach ($nodes as $node) {
            if ($node instanceof \Twig_Node_Expression_Name) {
                $name = $node->getAttribute('name');
                $variables[$name] = $name;
            } elseif ($node instanceof \Twig_Node_Expression_Constant && $nodes instanceof \Twig_Node_Expression_GetAttr) {
                $value = $node->getAttribute('value');
                if (!empty($value) && is_string($value)) {
                    $variables[$value] = $value;
                }
            } elseif ($node instanceof \Twig_Node_Expression_GetAttr) {
                $path = implode('.', $this->getTwigVariableNames($node));
                if (!empty($path)) {
                    $variables[$path] = $path;
                }
            } elseif ($node instanceof \Twig_Node) {
                $variables += $this->getTwigVariableNames($node);
            }
        }
        return $variables;
    }
    

    have fun :-)

    0 讨论(0)
  • 2020-12-08 01:05

    This Question has a douplicate – there I found a useful and kind of more powerfull RegEX than above. This one, I've improved to match more precise:

    \{\{(?!%)\s* # Starts with {{ not followed by % followed by 0 or more spaces
      ((?:(?!\.)[^\s])*?) # Match anything without a point or space in it
      (\|(?:(?!\.)[^\s])*)? # Match filter within variable
    \s*(?<!%)\}\} # Ends with 0 or more spaces not followed by % ending with }}
    | # Or
    \{%\s* # Starts with {% followed by 0 or more spaces
      (?:\s(?!endfor)|(endif)|(else)(\w+))+ # Match the last word which can not be endfor, endif or else
    \s*%\} # Ends with 0 or more spaces followed by %}
    # Flags: i: case insensitive matching | x: Turn on free-spacing mode to ignore whitespace between regex tokens, and allow # comments.
    
    0 讨论(0)
  • 2020-12-08 01:07

    After I spent quite a night, trying all the above answers, I realized, for some unexpected reason, regexps did not work at all with my simple templates. They returned junk or partial information. So I decided to go by erasing all the content between tags instead of counting tags ^_^.

    I mean, if a template is 'AAA {{BB}} CC {{DD}} {{BB}} SS', I just add '}}' in the beginning of the template and '{{ in the end.... and all the content between }} and {{ I'll just strip out, adding comma in between =>}}{{BB,}}{{DD,}}{{BB,}}{{. Then - just erase }} and {{.

    It took me about 15 min to write and test.... but with regexps I've spent about 5 hrs with no success.

    /**
     * deletes ALL the string contents between all the designated characters
     * @param $start - pattern start 
     * @param $end   - pattern end
     * @param $string - input string, 
     * @return mixed - string
     */
     function auxDeleteAllBetween($start, $end, $string) {
        // it helps to assembte comma dilimited strings
        $string = strtr($start. $string . $end, array($start => ','.$start, $end => chr(2)));
        $startPos  = 0;
        $endPos = strlen($string);
        while( $startPos !== false && $endPos !== false){
            $startPos = strpos($string, $start);
            $endPos = strpos($string, $end);
            if ($startPos === false || $endPos === false) {
                return $string;
            }
            $textToDelete = substr($string, $startPos, ($endPos + strlen($end)) - $startPos);
            $string = str_replace($textToDelete, '', $string);
        }
        return $string;
    }
    
    /**
     * This function is intended to replace
     * //preg_match_all('/\{\%\s*([^\%\}]*)\s*\%\}|\{\{\s*([^\}\}]*)\s*\}\}/i', 
     * which did not give intended results for some reason.
     *
     * @param $inputTpl
     * @return array
     */
    private function auxGetAllTags($inputTpl){
       $inputTpl = strtr($inputTpl, array('}}' => ','.chr(1), '{{' => chr(2)));
       return explode(',',$this->auxDeleteAllBetween(chr(1),chr(2),$inputTpl));
    }
    
    
    $template = '<style>
    td{border-bottom:1px solid #eee;}</style>
    <p>Dear {{jedi}},<br>New {{padawan}} is waiting for your approval: </p>
    <table border="0">
    <tbody><tr><td><strong>Register as</strong></td><td>{{register_as}}, user-{{level}}</td></tr>
    <tr><td><strong>Name</strong></td><td>{{first_name}} {{last_name}}</td></tr>...';
    
    print_r($this->auxGetAllTags($template));
    

    Hope it'll help somebody :)

    0 讨论(0)
提交回复
热议问题