所以我有这个Twig扩展,它允许添加命名小部件,这些小部件可以从数据库中获取内容并回显它们,或回显标签内的回退内容:
{% widget 'my_text' %}
Hello world
{% endwidget %}
我已经设置了一个Twig扩展来执行此操作。它由一个节点访问者组成,它在没有缓存时收集我的节点,并将他们的密钥添加到一个数组中,然后用于进行数据库调用:
class WidgetNodeVisitor implements \Twig_NodeVisitorInterface
{
private $aliases = array();
public function enterNode(Twig_NodeInterface $node, Twig_Environment $env)
{
if ($node instanceof WidgetNode) {
$env->getExtension('widget')->addAlias($node->getNode('alias')->getAttribute('value'));
}
return $node;
}
/...
令牌解析器相当基本,大部分类似于{% trans %}{% endtrans %}
解析器,因此不需要提供其代码(并且它运行良好)。
节点类本身如下所示:
class WidgetNode extends \Twig_Node
{
public function __construct(\Twig_NodeInterface $alias, \Twig_NodeInterface $body, $lineno = 0, $tag = null)
{
parent::__construct(array('alias' => $alias, 'body' => $body), array(), $lineno, $tag);
}
public function getName()
{
return $this->attributes['name'];
}
public function compile(\Twig_Compiler $compiler)
{
$compiler->addDebugInfo($this);
$alias = $this->nodes['alias']->attributes['value'];
$fallback = \addslashes($this->nodes['body']->attributes['data']);
// This method fetches the data from the DB or cache
$compiler->raw("echo \$this->env->getExtension('widget')->getWidget('$alias', '$fallback');\n");
}
}
我的问题是,每个编译后的WidgetNode
都会在getWidget()
中生成一个数据库调用。如果我的模板中有很多这样的节点,那么数据库负载会太高。所以,我认为我可以收集整个模板所需的小部件别名,然后让我的扩展程序使用alias IN (...)
SQL查询获取所有需要的小部件,但为此,我需要一种方法以某种方式修改缓存的模板__construct
或doDisplay
方法,以便调用我的扩展程序来获取所需的所有小部件:
class __TwigTemplate_6f3bb8f1b5ab540431a1ab3ff48c625b58765e4f0d0d284fe05a9353ea714de8 extends Twig_Template
{
public function __construct(Twig_Environment $env)
{
parent::__construct($env);
// We've visited the nodes prior to compilation, so the actual string aliases should be known
$env->getExtension('widget')->prefetch(array('widget1', 'widget2', ...));
}
但是如何让Twig修改基本模板模板?我尝试用一个包装器交换任何\Twig_Node_Module
,这个包装器会以不同的方式呈现缓存的模板构造函数,但似乎我的更改不起作用。我尝试在NodeVisitor
进行交换。
此外,我已经注意到'traits'
节点可能会影响Twig对模板缓存的渲染,尽管没有文档或任何内容。
有关如何在扩展程序中修改缓存模板标题的任何建议吗?
UPD。作为Christophe Coevoet的suggested,包裹\Twig_Node_Module
是正确的方法:
但是,通过将Twig_Node_Module包装在节点中的自己的节点中 访问者,你可以在doDisplay中添加一些逻辑 覆盖compileDisplayHeader或compileDisplayBody。
Cristophe还建议将Kris Wallsmith's blog post on Twig node visitors作为此类修复的起点。