webentwicklung-frage-antwort-db.com.de

Wie alle Variablen aus einer Twig-Vorlage abrufen?

Ist es möglich, alle Variablen in einer Twig-Vorlage mit PHP abzurufen? 

Beispiel someTemplate.twig.php:

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

Jetzt möchte ich so etwas machen: 

$template = $twig->loadTemplate('someTemplate');
$variables = $template->getVariables();

$ -Variablen sollten jetzt "Name" und "E-Mail" enthalten.

Der Grund, warum ich dies tun möchte, ist, dass ich an einem CMS-System arbeite, in dem meine Twig-Vorlagen und -Variablen von meinen Benutzern dynamisch festgelegt werden. 

Ich möchte die Standardwerte auf nicht festgelegte Variablen setzen und daher brauche ich eine Liste aller Variablen, die in der Vorlage vorhanden sind.

35
Stefan Neubig

UPDATE 2017

Es ist möglich, den {{ dump() }}-Filter zu verwenden. Danke für den Hinweis in den Kommentaren!


VERALTET

Es ist nicht möglich.

Sie können diese Variable in Zweigvorlagen suchen und ihnen einen |default('your_value')-Filter hinzufügen. Es wird geprüft, ob die Variable definiert ist und nicht leer ist. Wenn nein, wird sie durch Ihren Wert ersetzt.

17
Vitalii Zurian

Dies ist nützlich, um alle im aktuellen Kontext verfügbaren Schlüssel der obersten Ebene zu erhalten:

<ol>
    {% for key, value in _context  %}
      <li>{{ key }}</li>
    {% endfor %}
</ol>

Dank an https://www.drupal.org/node/1906780

60
duncan

Antwort bei 2015 hinzugefügt

In der Vergangenheit war das nicht möglich. Aber seit Version 1.5 dump () hat Funktion hinzugefügt. Sie können also alle Variablen aus dem aktuellen Kontext aufrufen, der dump () ohne Parameter aufruft:

<pre>
    {{ dump(user) }}
</pre>

Sie müssen jedoch die Erweiterung Twig_Extension_Debug explizit hinzufügen, wenn Sie Ihre Twig-Umgebung erstellen, da dump() standardmäßig nicht verfügbar ist:

$twig = new Twig_Environment($loader, array(
    'debug' => true,
    // ...
));
$twig->addExtension(new Twig_Extension_Debug());

Wenn Sie Symfony, Silex usw. verwendet haben, ist dump() standardmäßig verfügbar.

BEARBEITEN:

Sie können auch auf alle Variablen verweisen, die an eine Vorlage (außerhalb des Kontextes von dump()) übergeben werden, indem Sie die globale Variable _context verwenden. Das war es, wonach Sie gesucht haben. Es ist ein Array, das alle Variablennamen ihren Werten zuordnet.

Weitere Informationen finden Sie in der Twig-Dokumentation.

Für diese spezielle Frage ist es jedoch wahrscheinlich am besten, alle diese benutzerdefinierten Variablen unter derselben Umbrella-Variablen zusammenzufassen, sodass das Abrufen dieser Variablen keine Kopfschmerzen darstellt. Ich wäre ein Array namens custom_variables oder wie auch immer.

14
felipsmartins

Dies ist der beste und einfachste Weg, um alle Variablen auszugeben:

{{ dump () }}

Source: https://www.drupal.org/docs/8/theming/twig/discovering-and-inspecting-variables-in-twig-templates

12
ReaperSoon

Wenn Sie alle Twig-Elemente in einem Text benötigen, verwenden Sie einfach:

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

Ich hatte ein Problem, bei dem der WSIWYG-Editor HTML-Tags in Twig-Variablen eingefügt hat. Ich filte sie mit:

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

Verwenden Sie diesen Ausdruck, um alle {{}} und {%%} zu finden.

preg_match_all('/\{\%\s*([^\%\}]*)\s*\%\}|\{\{\s*([^\}\}]*)\s*\}\}/i', $text, $matches);
7
19Gerhard85

Ich mache das so

<script>console.log({{ _context | json_encode | raw }});</script>

Und dann überprüfe ich einfach meine Konsole mit DevTools

6
Luke Madhanga

Nachdem ich die Antwort von Duncan für einige Zeit verwendet hatte, fand ich schließlich den "richtigen" Weg, um alle Zweigvariablen einer Vorlage auszugeben

{% dump %}

Das ist alles. Alle Variablen, die in der Vorlage verfügbar sind, werden in den Speicherauszug des Profilers geladen und nicht in der Mitte Ihrer HTML-Datei, wie bei {{dump ()}}

wenn Sie den Inhalt von dump () in variable setzen

{% set d = dump() %}

sie erhalten alle Variablen, aber in "dump ready" html, sodass es schwierig sein könnte, sie zu analysieren

Hoffentlich hilft das

4
Mawcel

Ich denke, die Antwort von 19Gerhard85 ist ziemlich gut, auch wenn sie ein paar Optimierungen benötigt, weil sie für mich mit einigen leeren Saiten übereinstimmt. Ich mag es, wenn möglich, vorhandene Funktionen zu verwenden, und dies ist ein Ansatz, bei dem hauptsächlich die Funktionen von twig verwendet werden. Sie benötigen Zugriff auf die Zweigumgebung Ihrer Anwendung.

/**
 * @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);
}

Der einzige benutzerdefinierte Teil davon ist die rekursive Funktion, um nur bestimmte Arten von Knoten zu erfassen:

/**
 * @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
        }
    }
}
3
mickadoo

Sie müssen die Vorlage analysieren und die zurückgegebenen AST durchlaufen:

$loaded = $twig->getLoader()->getSource($template);
var_dump(extractVars($twig->parse($twig->tokenize($loaded)));

function extractVars($node)
{
    if (!$node instanceof Traversable) return array();

    $vars = array();
    foreach ($node as $cur)
    {
        if (get_class($cur) != 'Twig_Node_Expression_Name')
        {
            $vars = array_merge($vars, extractVars($cur));
        }
        else
        {
            $vars[] = $cur->getAttribute('name');
        }
    }

    return $vars;
}
1
devicenull

Nachdem ich eine ganze Nacht verbracht hatte und alle obigen Antworten ausprobiert hatte, wurde mir aus unerwarteten Gründen klar, dass Regexx mit meinen einfachen Vorlagen überhaupt nicht funktionierten. Sie gaben Junk- oder Teilinformationen zurück. Also habe ich beschlossen, den gesamten Inhalt zwischen den Tags zu löschen, anstatt die Tags zu zählen ^ _ ^.

Ich meine, wenn eine Vorlage 'AAA {{BB}} CC {{DD}} {{BB}} SS' ist, füge ich einfach '}}' am Anfang der Vorlage und '{{ am Ende hinzu .... und den gesamten Inhalt zwischen }} und {{ werde ich einfach streichen und ein Komma dazwischen einfügen => }}{{BB,}}{{DD,}}{{BB,}}{{ . Dann - löschen Sie einfach }} und {{.

Ich habe ungefähr 15 Minuten gebraucht, um zu schreiben und zu testen ... aber mit Regex-Ausdrücken habe ich ungefähr 5 Stunden ohne Erfolg verbracht. 

/**
 * 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));

Ich hoffe es hilft jemandem :)

1
Alexey Abraham
$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;
}

habe Spaß :-)

1
Lars

Erstellen Sie eine Twig_Extension und fügen Sie eine Funktion mit dem Flag needs_context hinzu:

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

Der Kontext wird als erster Parameter an Ihre Funktion übergeben und enthält alle Variablen.

In Ihrer Twig-Vorlage müssen Sie nur diese Funktion aufrufen:

{{myTwigFunction()}}

Wenn Sie Unterstützung beim Erstellen einer Twig-Erweiterung benötigen, lesen Sie diese Dokumentation:

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

Ich habe eine Twig2Schema-Klasse erstellt, um aus einer Twig AST Variablen abzuleiten. Um die Variablen in einem Dokument zu erhalten, müssen Sie die Twig = rekursiv durchlaufen AST und haben Regeln, wenn Sie auf bestimmte Arten von Sprachknoten stoßen.

Diese Klasse extrahiert Variablennamen aus Nodes, wenn sie nicht immer definiert sind, und erfasst auch Variablen aus dem in ForLoopNodes und IfStatements verwendeten Wert.

Um es zu verwenden, können Sie entweder infer für die gesamte Vorlage oder eine Teilmenge des Baums mit inferFromAst aufrufen.

<?php

class Twig2Schema
{
    /**
     * @param \Twig\Environment $twig - A twig environment containing loaded templates
     * @param $twigTemplateName - The name of the template to infer variables from
     * @param $config - A configuration object for this function
     * @return array
     */
    public function infer(\Twig\Environment $twig, $twigTemplateName)
    {
        $source = $twig->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;
    }
}
0
Cameron Wilby

Diese Frage hat ein Duplikat - da fand ich eine nützliche und mächtigere RegEX als oben. Dieses habe ich verbessert, um genauer zu sein:

\{\{(?!%)\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
Martin Winter