我有一个较大的base.twig文件,我想把它分成三个包括:header.twig,content.twig和footer.twig。我无法从我的子模板中获取块来覆盖包含在我的父模板中的块,并且想知道它是否可能,如果没有,那么Twig-ish解决方案可能是什么样子。
我设置了一个简单的例子来说明这个问题。我正在检索Wordpress页面并使用Timber处理Twig模板。被调用的PHP模板是page-test.php:
<?
$context = Timber::get_context();
Timber::render('test_child.twig', $context);
?>
呈现的Twig模板是test_child.twig:
{% extends 'test_base.twig' %}
{% block content_main %}
<h1>Random HTML</h1>
{% endblock content_main %}
父模板test_base.twig是:
<!DOCTYPE html>
<head>
<title>Twig test</title>
</head>
<body>
{% include 'test_content.twig' %}
</body>
</html>
最后,包含的模板test_content.twig是这样的:
<div class="main">
{% block content_main %}
{% endblock content_main %}
</div>
结果输出如下:
<!DOCTYPE html>
<head>
<title>Twig test</title>
</head>
<body>
<div class="main">
</div>
</body>
</html>
如您所见,<div>
没有内容。我期望它包含来自test_child.twig的<h1>Random HTML</h1>
片段。
为什么test_child.twig中的块不会覆盖test_content.twig中包含的同名块到test_base.twig?如果这种方法根本不起作用,那么最好的Twig-ish方法是什么?
答案 0 :(得分:2)
int n[1];
t2 = &n; // ok
确实无法做到这一点,因为包含的文件与调用它们的模板没有任何关联。要解释一下自己看看这个片段
twig
此代码段将由{{ include('foo.twig') }}
编译器解析为PHP
,其编译的代码为
twig
现在我们可以通过查看$this->loadTemplate("foo.twig", "main.twig", 6)->display($context);
的来源进一步调查此问题。如果您看一下我们将看到的特定函数,因为您正在向函数传递Twig_Template::loadTemplate
,函数string
将在类loadTemplate
中调用
在最后一个函数中,我们可以清楚地看到Twig_Environment
函数没有传递任何信息,也没有传递您向所包含模板呈现的模板实例。传递的唯一内容(Twig_Environment::loadTemplate
)是变量by value
,它将您从控制器发送的所有变量保存到正在渲染的模板中。
我猜测其编码的主要原因之一是因为包含的文件在任何情况下都应该是可重用的,并且不应该像(不存在的)块一样具有依赖性以使它们被渲染
TwigTemplate.php
$context
Environment.php
protected function loadTemplate($template, $templateName = null, $line = null, $index = null) {
try {
if (is_array($template)) return $this->env->resolveTemplate($template);
if ($template instanceof self) return $template;
if ($template instanceof Twig_TemplateWrapper) return $template;
return $this->env->loadTemplate($template, $index);
} catch (Twig_Error $e) {
if (!$e->getSourceContext()) $e->setSourceContext($templateName ? new Twig_Source('', $templateName) : $this->getSourceContext());
if ($e->getTemplateLine()) throw $e;
if (!$line) {
$e->guess();
} else {
$e->setTemplateLine($line);
}
throw $e;
}
}
由于我不确定你为什么会这样设置,这将是一个更public function loadTemplate($name, $index = null) {
$cls = $mainCls = $this->getTemplateClass($name);
if (null !== $index) {
$cls .= '_'.$index;
}
if (isset($this->loadedTemplates[$cls])) {
return $this->loadedTemplates[$cls];
}
if (!class_exists($cls, false)) {
$key = $this->cache->generateKey($name, $mainCls);
if (!$this->isAutoReload() || $this->isTemplateFresh($name, $this->cache->getTimestamp($key))) {
$this->cache->load($key);
}
if (!class_exists($cls, false)) {
$source = $this->getLoader()->getSourceContext($name);
$content = $this->compileSource($source);
$this->cache->write($key, $content);
$this->cache->load($key);
if (!class_exists($mainCls, false)) {
/* Last line of defense if either $this->bcWriteCacheFile was used,
* $this->cache is implemented as a no-op or we have a race condition
* where the cache was cleared between the above calls to write to and load from
* the cache.
*/
eval('?>'.$content);
}
if (!class_exists($cls, false)) {
throw new Twig_Error_Runtime(sprintf('Failed to load Twig template "%s", index "%s": cache is corrupted.', $name, $index), -1, $source);
}
}
}
式的设置。请注意,您必须首先在基类中定义块,因为在扩展类中“定义”块,尝试显示父级的块,而不是创建新的块。
test_main.twig
twig
test_child.twig
<!DOCTYPE html>
<head>
<title>Twig test</title>
</head>
<body>
{% block content_main %}
{% include 'block.twig' %}
{% endblock %}
</body>
</html>
test_content.twig
{% extends "test_main.twig" %}
{% block content_main %}
{% include "test_content.twig" %}
{% endblock %}
答案 1 :(得分:0)
不幸的是,这不适用于包含。
当我尝试将一些SEO值从我的产品控制器传递到包含元标记的基本模板时,我也遇到了这个问题。
您还必须为内部模板使用“extends”,并指向您的控制器以使用内部模板而不是中间/布局模板。
然后,您可以在内部模板上定义一个单独的块,它可以直接覆盖基本模板的块。
你可以在这个小提琴中看到一个工作示例(注意内部模板是主要模板) https://twigfiddle.com/1ve5kt