Twig 最佳实践 —— 函数与预处理模板
为了让 Drupal 8 的主题系统发挥最大性能,并在 Twig 模板中提供更多自定义可能性,请遵循以下建议:
本指南旨在帮助那些有 Drupal 7 开发经验的开发者,他们可能还习惯使用 theme() 或 drupal_render() 这样的函数,但这些函数在 Drupal 8+ 中已经不再推荐使用。文中的「之前」示例通常采用 Drupal 7 风格的代码。
在预处理函数中返回渲染数组
在预处理函数中始终返回渲染数组,而不是调用 theme() 或 drupal_render()。
Twig 会自动渲染所有输出,因此不需要在预处理函数中调用 drupal_render() 或 theme()。相反,应将渲染数组传递给模板,这比传递已经渲染好的 HTML 字符串提供了更多的灵活性。
从预处理函数中移除 theme():
// 之前 - 将渲染好的 HTML 字符串传递到模板。
$variables['table'] = theme('table', ['header' => $header, 'rows' => $rows]);
// 之后 - 将渲染数组传递到模板。
$variables['table'] = [
'#theme' => 'table',
'#header' => $header,
'#rows' => $rows,
];
从预处理函数中移除 drupal_render() 只需删除调用:
// 之前,不必要的 drupal_render() 调用。 $variables['teaser'] = drupal_render($node_teaser); // 之后,移除了 drupal_render()。 $variables['teaser'] = $node_teaser;
一个常见情况是 drupal_render() 被用在表格数据中:
// 之前,不必要的 drupal_render() 调用。 $row[] = drupal_render($display['title']); // 之后,移除了 drupal_render()。 $row[]['data'] = $display['title'];
在模板中使用过滤器和工具函数
虽然渲染数组为数据提供了可寻址、可修改的结构,但并非所有变量都需要渲染数组。为了尽可能长时间地保持数据的原始性,主题开发者应该在 Twig 模板中调用 过滤器(如 t),以及工具函数(如 url())。在 Twig 模板而不是预处理函数中调用这些函数,可以减少函数调用次数,因为传入模板的变量可能根本不会被打印出来。
之前:
在预处理函数中:
$variables['no_content_text'] = t('You have not created any content types yet. Go to the <a href="@create-content">content type creation page</a> to add a new content type.', array('@create-content' => url('admin/structure/types/add')));
在模板中:
<p>{{ no_content_text }}</p>
之后:
在模板中:
<p>{{ 'You have not created any content types yet. Go to the <a href="@create-content">content type creation page</a> to add a new content type.'|t({'@create-content': url('admin/structure/types/add')}) }}</p>
显示 / 隐藏以及移除 drupal_render_children 和 element_children
如果在原始模板中使用了 hide(),并且使用 drupal_render_children 渲染「剩余」的数据,那么我们需要在预处理过程中将这些部分拆分为单独的变量。
之前(PHPTemplate 文件):
<?php hide($form['advanced']); hide($form['actions']); ?> <div class="layout-node-form clearfix"> <div class="layout-region layout-region-node-main"> <?php print drupal_render_children($form); ?> </div> <div class="layout-region layout-region-node-secondary"> <?php print render($form['advanced']); ?> </div> <div class="layout-region layout-region-node-footer"> <?php print render($form['actions']); ?> </div> </div>
请使用 Twig 的「without」过滤器来隐藏特定元素。你可以像平常一样单独打印需要的部分。
之后:(Twig 模板)
<div class="layout-node-form clearfix">
<div class="layout-region layout-region-node-main">
{{ form|without('advanced', 'actions') }}
</div>
<div class="layout-region layout-region-node-secondary">
{{ form.advanced }}
</div>
<div class="layout-region layout-region-node-footer">
{{ form.actions }}
</div>
</div>
替代方法(不再推荐):
将所有部分在预处理中拆分成单独的变量并传递到模板中。在渲染其余内容之前,可能需要将表单中的部分元素赋值给变量。然后在模板中精确地打印这些变量。
之前:(预处理)
function template_preprocess_node_edit_form(&$variables) {
$form = $variables['form'];
// @todo Update this once drupal.org/node/1920886 is resolved.
$variables['advanced'] = $form['advanced'];
$variables['actions'] = $form['actions'];
unset($form['advanced'], $form['actions']);
$variables['form'] = drupal_render_children($form);
}
之后:(Twig 模板)
<div class="layout-node-form clearfix">
<div class="layout-region layout-region-node-main">
{{ form }}
</div>
<div class="layout-region layout-region-node-secondary">
{{ advanced }}
</div>
<div class="layout-region layout-region-node-footer">
{{ actions }}
</div>
</div>