问题描述
我想从一个地方优雅地导入多个宏.
我创建了一个名为"macros.twig"的文件,并将其包含在我的模板中:
I created a file called "macros.twig" and have included it into my template:
{% include "_includes/macros" %}
在该文件中,我希望导入所有可用的宏,如下所示:
Within that file, I hoped to import all my available macros like so:
{% import "_includes/macros/snippets" as snippets %}
{% import "_includes/macros/timestamp" as timestamp %}
{% import "_includes/macros/telephone" as telephone %}
{% import "_includes/macros/subscribe" as subscribe %}
{% import "_includes/macros/image" as image %}
{% import "_includes/macros/admin" as admin %}
这种排序的模块化方法是为了简化我要全局使用的宏的管理.而不会使我的主要布局混乱.
This sort-of modular approach was suppose to make it easier to manage the macros I want to use globally; without cluttering the head of my main layout.
当前,当我以这种方式调用宏时,出现变量订阅"不存在" 错误.
Currently, when I call a macro this way, I get a "Variable "subscribe" does not exist" error.
一次导入多个宏的首选方法是什么?
What's the preferred method of importing multiple macros at one time?
谢谢
推荐答案
macro
标签是一种可以避免代码重复的功能,适用于带有{% import _self as macro %}
的单个模板或可以共享使用相同的视图变量的一组控制器的一些不同模板之间的交互.
macro
tag in Twig is a kind of function you can use to avoid code repetition and is meant for a single template with {% import _self as macro %}
or to be shared between some different templates for a group of controllers using the same view variables.
如果需要在树枝中全局使用功能,则最好创建一个\Twig_SimpleFunction
.
If you need to use a function globally in twig you better create a \Twig_SimpleFunction
.
请参见 http://twig.sensiolabs.org/doc/advanced.html#functions 和 http://symfony.com/doc/current/cookbook/templating/twig_extension.html
无论如何,您可以使用类似的方法来自动加载宏:
Anyway you could have something like this to autoload macro :
<?php
// src/AppBundle/Twig/MacroAutoloadExtension.php
namespace AppBundle\Twig;
class MacroAutoloadExtension extends \Twig_Extension
{
public function getFunctions()
{
return array(
// "*"" is used to get "template_macro" as $macro as third argument
new \Twig_SimpleFunction('macro_*', array($this, 'getMacro'), array(
'needs_environment' => true, // $env first argument will render the macro
'needs_context' => true, // $context second argument an array of view vars
'is_safe' => array('html'), // function returns escaped html
'is_variadic' => true, // and takes any number of arguments
))
);
}
public function getMacro(\Twig_Environment $env, array $context, $macro, array $vars = array())
{
list($name, $func) = explode('_', $macro);
$notInContext = 0; // helps generate unique context key
$varToContextKey = function ($var) use (&$context, $name, $func, &$notInContext) {
if (false !== $idx = array_search($var, $context, true)) {
return $idx;
}
// else the var does not belong to context
$key = '_'.$name.'_'.$func.'_'.++$notInContext;
$context[$key] = $var;
return $key;
};
$args = implode(', ', array_map($varToContextKey, $vars));
$twig = <<<EOT
{% import '_includes/macros/$name.twig' as $name %}
{{ $name.$func($args) }}
EOT;
try {
$html = $env->createTemplate($twig)->render($context);
} catch (\Twig_Error $e) {
$e->setTemplateFile(sprintf('_includes/macro/%s.twig', $name));
throw $e;
}
return $html;
}
public function getName()
{
return 'macro_autoload_extension';
}
}
注册扩展名:
# app/config/sevices.yml
services:
...
app.macro_autoload_extension:
class: AppBundle\Twig\MacroAutoloadExtension
public: false
tags:
- { name: twig.extension }
写一些宏:
{# app/Resources/views/_includes/macros/list.twig #}
{% macro ol(array) %}
{% if array is iterable %}
<ol>
{% for item in array %}
<li>
{% if item is iterable %}
{% for sub_item in item %}{{ macro_list_ul(sub_item) }}{% endfor %}
{% else %}
{{ item }}
{% endif %}
</li>
{% endfor %}
</ol>
{% else %}
<ol><li>{{ array }}</li></ol>
{% endif %}
{% endmacro %}
{% macro ul(array) %}
{% if array is iterable %}
<ul>
{% for key, item in array %}
{{ key }}:
{% if item is iterable %}
{% for sub_item in item %}{{ macro_list_ul(sub_item) }}{% endfor %}
{% else %}{{ item }}{% endif %}
{% endfor %}
</ul>
{% else %}
<ul><li>{{ array }}</li></ul>
{% endif %}
{% endmacro %}
然后您就可以在视图中的任何地方使用它:
{{ macro_list_ol(['un', 'deux', 'trois']) }}
或:
{% set hash = { 'one': 1, 'two': 'deux', 'posts': posts } %}
{{ macro_list_ul(hash) }}
奖金
通常,当使用_self
或其他模板从模板(一个文件)中导入宏时,如果需要set标记中的宏,则该宏不可用,因为set
标记的作用域不同于_self
(即使它共享上下文):
Bonus
Usually when you import macro in a template (one file) with _self
or from another template, if you need a macro in a set tag, the macro is not available since set
tag has a different scope than _self
(even if it shares context) :
{# /app/Resources/views/includes/macro/outer.html.twig #}
{% macro function(args) %}
...
{% endmacro %}
加
{# /app/Resources/views/Bundle/Controller/action.html.twig #}
{% macro inner_macro(arg1, arg2) %}
{# render something #}
{# cannot access context of this view, only args #}
{% endmacro %}
{% import _self as inner %}
{% import '/includes/macro/outer_macro.html.twig' as outer %} {# cannot access context either %}
...
{% set some_var %}
{# can access context but neither outer or inner #}
{{ inner.inner_macro('yes', 64) }} {# will not work #}
{# you need to do import _self as inner again %}
{# this is fix by both my answer and the one by @KalZekdor #}
{{ macro_outer_function(var_from_context) }} {# will work #}
{% endset %}
{{ some_var }}
您甚至可以在不使用导入的情况下从宏调用宏.
You can even call macro from macro without using import.
我创建了要点
这篇关于如何导入多个宏?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!