Est-il possible de récupérer toutes les variables d'un modèle Twig avec PHP?
Exemple someTemplate.twig.php:
Hello {{ name }},
your new email is {{ email }}
Maintenant, je veux faire quelque chose comme ça:
$template = $twig->loadTemplate('someTemplate');
$variables = $template->getVariables();
Les variables $ doivent maintenant contenir "nom" et "email".
La raison pour laquelle je veux faire cela est que je travaille sur un système CMS Où mes modèles et variables de brindille sont définis de manière dynamique par mes utilisateurs Ils remplissent également les variables via une API.
Je souhaite définir les valeurs par défaut sur des variables non définies et, par conséquent, j’ai besoin d’une liste de toutes les variables présentes dans le modèle…
MISE À JOUR 2017
C'est possible en utilisant le filtre {{ dump() }}
. Merci de l'avoir signalé dans les commentaires!
OBSOLÈTE
Ce n'est pas possible.
Vous pouvez rechercher ces variables dans les modèles de brindille et leur ajouter le filtre |default('your_value')
. Il vérifiera si la variable est définie et n'est pas vide, et si non, la remplacera par votre valeur.
Ceci est utile pour trouver toutes les clés de niveau supérieur disponibles dans le contexte actuel:
<ol>
{% for key, value in _context %}
<li>{{ key }}</li>
{% endfor %}
</ol>
Dans le passé, ce n'était pas possible. Mais depuis la version 1.5, la fonction dump () a été ajoutée. Vous pouvez donc obtenir toutes les variables du contexte actuel en appelant dump () sans aucun paramètre:
<pre>
{{ dump(user) }}
</pre>
Cependant, vous devez ajouter l'extension Twig_Extension_Debug explicitement lors de la création de votre environnement Twig car dump()
n'est pas disponible par défaut:
$twig = new Twig_Environment($loader, array(
'debug' => true,
// ...
));
$twig->addExtension(new Twig_Extension_Debug());
Si vous utilisez quelque chose comme Symfony, Silex, etc., dump()
est disponible par défaut.
On peut également référencer toutes les variables transmises à un modèle (en dehors du contexte de dump()
), en utilisant la variable globale _context
. C'est ce que vous cherchiez. C'est un tableau associant tous les noms de variables à leurs valeurs.
Vous pouvez trouver des informations supplémentaires dans la documentation Twig.
Pour cette question spécifique cependant, il serait probablement préférable de rassembler toutes ces variables personnalisées dont vous parlez, sous une même variable générique, afin que leur extraction ne soit pas un casse-tête. Je serais un tableau appelé custom_variables
ou autre chose.
Voici le moyen le plus simple et le plus simple de vider toutes les variables:
{{ dump () }}
Source: https://www.drupal.org/docs/8/theming/twig/discovering-and-inspecting-variables-in-twig-templates
Si vous avez besoin de tous les éléments Twig à l'intérieur d'un texte, utilisez simplement:
preg_match_all('/\{\%\s*(.*)\s*\%\}|\{\{(?!%)\s*((?:[^\s])*)\s*(?<!%)\}\}/i', $text, $matches);
J'ai eu un problème où l'éditeur WSIWYG a placé des balises HTML dans des variables Twig. Je les filtre avec:
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;
}
METTRE &AGRAVE; JOUR
Utilisez cette expression pour trouver tous les {{}} et {%%}
preg_match_all('/\{\%\s*([^\%\}]*)\s*\%\}|\{\{\s*([^\}\}]*)\s*\}\}/i', $text, $matches);
La façon dont je le fais est
<script>console.log({{ _context | json_encode | raw }});</script>
Et puis je vérifie ma console avec DevTools
Après avoir utilisé la réponse de duncan pendant un certain temps, j'ai finalement trouvé le "bon" moyen de vider toutes les variables de brindille d'un modèle.
{% dump %}
Toutes les variables disponibles dans le modèle seront vidées et dans la section dump du profileur, et non au milieu de votre code HTML comme avec {{dump ()}}
si vous mettez le contenu de dump () dans variable
{% set d = dump() %}
vous obtiendrez toutes les variables mais en "dump ready" html donc il serait difficile de l'analyser
J'espère que cela pourra aider
Je pense que la réponse de 19Gerhard85 est plutôt bonne, même si elle nécessite peut-être quelques ajustements car elle correspond à des chaînes vides pour moi. J'aime utiliser les fonctions existantes dans la mesure du possible et c'est une approche qui utilise principalement les fonctions de twig. Vous devez accéder à l'environnement de brindille de votre application.
/**
* @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);
}
Et la seule partie personnalisée de celle-ci est la fonction récursive pour collecter uniquement certains types de nœuds:
/**
* @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
}
}
}
Vous devez analyser le modèle et parcourir le AST qui le renvoie:
$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;
}
Après avoir passé une bonne nuit à essayer toutes les réponses ci-dessus, j’ai réalisé, pour une raison inattendue, que les expressions rationnelles ne fonctionnaient pas du tout avec mes modèles simples. Ils ont renvoyé des informations indésirables ou partielles. J'ai donc décidé de supprimer tout le contenu entre les balises au lieu de compter les balises ^ _ ^.
Je veux dire, si un modèle est 'AAA {{BB}} CC {{DD}} {{BB}} SS'
, j'ajoute simplement '}}'
au début du modèle et '{{
à la fin .... et tout le contenu entre }}
et {{
Je vais juste enlever la virgule, en ajoutant une virgule entre>> }}{{BB,}}{{DD,}}{{BB,}}{{
. Ensuite, effacez simplement }}
et {{
.
Il m'a fallu environ 15 minutes pour écrire et tester ... mais avec les expressions régulières, j'ai passé environ 5 heures sans succès.
/**
* 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));
J'espère que ça va aider quelqu'un :)
$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;
}
s'amuser :-)
Créez un Twig_Extension et ajoutez une fonction avec l'indicateur needs_context:
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 '';
}
}
Le contexte sera passé en tant que premier paramètre à votre fonction, contenant toutes les variables.
Sur votre modèle Twig, il vous suffit d'appeler cette fonction:
{{myTwigFunction()}}
Si vous avez besoin d'aide pour créer une extension Twig, veuillez vous reporter à cette documentation:
Cette Question a un doublon - là, j'ai trouvé un RegEX utile et plus puissant que le précédent. Celui-ci, j'ai amélioré pour correspondre plus précis:
\{\{(?!%)\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.