[英]Joining tables in Symfony Doctrine and accessing all the variables from Twig template
[英]How to retrieve all Variables from a Twig Template?
是否可以使用 PHP 檢索 Twig 模板中的所有變量?
示例 someTemplate.twig.php:
Hello {{ name }},
your new email is {{ email }}
現在我想做這樣的事情:
$template = $twig->loadTemplate('someTemplate');
$variables = $template->getVariables();
$variables 現在應該包含“name”和“email”。
我想這樣做的原因是我在一個 CMS 系統上工作,我的樹枝模板和變量由我的用戶動態設置,他們還通過 API 填充變量。
我想將默認值設置為未設置的變量,因此我需要模板中存在的所有變量的列表......
我發現獲得當前上下文中所有可用的頂級鍵非常有用:
<ol>
{% for key, value in _context %}
<li>{{ key }}</li>
{% endfor %}
</ol>
更新2019
盡管{{ dump() }}
確實有效,但是在某些情況下,如果PHP生成的信息過多(例如由於遞歸),可能會導致PHP出現“內存耗盡”錯誤。 在這種情況下,請嘗試{{ dump(_context|keys) }}
通過名稱獲取已定義變量的列表,而不轉儲其內容。
更新2017
使用{{ dump() }}
過濾器是可能的。 感謝您在評論中指出!
過時的
這不可能。
您可以在樹枝模板中查找這些變量,然后向它們添加|default('your_value')
過濾器。 它將檢查變量是否已定義並且不為空,如果不存在,則將其替換為您的值。
過去是不可能的。 但自1.5版以來,已添加dump()函數。 因此,您可以從沒有調用任何參數的當前上下文中獲取所有變量,方法是:dump():
<pre>
{{ dump(user) }}
</pre>
但是,在創建Twig環境時,必須顯式添加Twig_Extension_Debug擴展,因為默認情況下dump()
不可用:
$twig = new Twig_Environment($loader, array(
'debug' => true,
// ...
));
$twig->addExtension(new Twig_Extension_Debug());
如果您使用的是Symfony,Silex等,則默認情況下dump()
可用。
也可以使用全局變量_context
引用傳遞給模板的所有變量(在dump()
上下文之外dump()
。 這就是您想要的。 它是一個將所有變量名稱與其值關聯的數組。
但是,對於這個特定問題,最好將所有您要說的這些自定義變量收集在一個總括變量下,這樣檢索它們就不會太麻煩了。 我將是一個名為custom_variables
的數組。
這是轉儲所有變量的最佳方法和最簡單的方法:
{{ dump () }}
來源: https : //www.drupal.org/docs/8/theming/twig/discovering-and-inspecting-variables-in-twig-templates
如果需要在文本中包含所有Twig元素,請使用:
preg_match_all('/\{\%\s*(.*)\s*\%\}|\{\{(?!%)\s*((?:[^\s])*)\s*(?<!%)\}\}/i', $text, $matches);
我遇到一個問題,其中WSIWYG編輯器將HTML標記放置在Twig變量內。 我用它們過濾:
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;
}
更新
使用此表達式查找所有{{}}和{%%}
preg_match_all('/\{\%\s*([^\%\}]*)\s*\%\}|\{\{\s*([^\}\}]*)\s*\}\}/i', $text, $matches);
我的方式是
<script>console.log({{ _context | json_encode | raw }});</script>
然后我只是使用DevTools檢查控制台
在使用duncan的答案一段時間后,我終於找到了轉儲模板中所有樹枝變量的“正確”方法:
{% dump %}
而已。 模板中所有可用的變量都將被轉儲到事件探查器的轉儲部分中,而不是像{{ dump() }}
一樣出現在html的中間。
如果將dump()
的內容放入變量中:
{% set d = dump() %}
您將獲得所有變量,但是在“ dump ready” html中,因此很難解析它。
希望能有所幫助。
我認為19Gerhard85的答案相當不錯,盡管可能需要進行一些調整,因為它為我匹配了一些空字符串。 我喜歡在可能的情況下使用現有功能,而這是大多數使用twig功能的方法。 您需要訪問應用程序的樹枝環境。
/**
* @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);
}
並且它的唯一自定義部分是僅收集某些類型的節點的遞歸函數:
/**
* @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
}
}
}
$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;
}
玩得開心 :-)
您必須解析模板,並逐步執行返回的AST:
$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, call_user_func(__FUNCTION__, $cur));
}
else if ($cur->getAttribute('always_defined') == false)
{
// List only predefined variables expected by template,
// filtering out `v` and leaving `arr` from `{% for v in arr%}`
$vars[] = $cur->getAttribute('name');
}
}
return $vars;
}
在花了整整一個晚上,嘗試以上所有答案后,我意識到,由於某些意外原因,正則表達式根本無法用於我的簡單模板。 他們返回了垃圾信息或部分信息。 因此,我決定刪除所有標簽之間的內容,而不是對標簽^ _ ^進行計數。
我的意思是,如果模板是'AAA {{BB}} CC {{DD}} {{BB}} SS'
,我只需在模板的開頭添加'}}'
,在末尾添加'{{
。 ..和}}
和{{
之間的所有內容,我將刪除,在=> }}{{BB,}}{{DD,}}{{BB,}}{{
之間添加逗號。 然后-只需擦除}}
和{{
。
我花了大約15分鍾來編寫和測試.....但是使用正則表達式我已經花費了大約5個小時,但沒有成功。
/**
* 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));
希望對別人有幫助:)
創建一個Twig_Extension並添加一個帶有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 '';
}
}
上下文將作為包含所有變量的第一個參數傳遞給您的函數。
在Twig模板上,您只需要調用該函數:
{{myTwigFunction()}}
如果您需要有關創建Twig擴展程序的幫助,請參閱以下文檔:
這個問題有一個重復的部分 –在這里,我發現了一個比上面有用且更強大的RegEX。 我對此進行了改進,以使其更加精確:
\{\{(?!%)\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.
我構建了一個Twig2Schema類,以從Twig AST推斷變量。 要獲取文檔中的變量,您需要遞歸地“遍歷” Twig AST,並在遇到某些類型的語言節點時制定適當的規則。
此類從節點中提取變量名稱(如果未始終定義它們),並且還從ForLoopNodes和IfStatements中使用的值中獲取變量。
要使用它,您可以為整個模板調用infer
,也可以使用inferFromAst
樹的子集。
<?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;
}
}
如果您查看 twig 編譯過程,您可以看到有一個名為 ignore_strict_check 的參數,如果它是 true compile 將用 null 替換丟失的變量,但如果 false compile 會拋出運行時錯誤,請查看文件 twig/src/Node/Expression/NameExpression.php 行63 在 symfony 中你可以通過 twig 包配置來設置這個參數 strict_variables: false
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.