如何导入多个宏?

问题描述 投票:0回答:2

我想从一个地方优雅地导入多个宏。

我创建了一个名为“macros.twig”的文件并将其包含到我的模板中:

{% include "_includes/macros" %}

在该文件中,我希望导入所有可用的宏,如下所示:

{% 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 %}

这种模块化方法应该可以更轻松地管理我想要在全局范围内使用的宏;不会弄乱我的主要布局的头部。

目前,当我以这种方式调用宏时,我收到“变量“订阅”不存在”错误。

一次性导入多个宏的首选方法是什么?

谢谢

php symfony macros twig
2个回答
3
投票
Twig 中的

macro
标签是一种可以用来避免代码重复的函数,适用于带有
{% import _self as macro %}
的单个模板,或者在使用相同视图变量的一组控制器的一些不同模板之间共享。

如果您需要在 twig 中全局使用某个函数,您最好创建一个

\Twig_SimpleFunction

参见 http://twig.sensiolabs.org/doc/advanced.html#functionshttp://symfony.com/doc/current/cookbook/templatating/twig_extension.html

根据评论进行编辑

无论如何,你可以有这样的东西来自动加载宏:

<?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
标签的范围与
_self
不同(即使它共享上下文):

{# /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 }}

您甚至可以在不使用导入的情况下从宏调用宏。

更新

我创建了一个要点


1
投票

这对我来说也有点困难,但我将一个很好的捆绑包与自动加载宏的事件监听器放在一起。

namespace App\Common\UIExtensionBundle\Listeners;

use Symfony\Component\HttpKernel\Event\GetResponseEvent;
use Symfony\Bundle\TwigBundle\TwigEngine;

class UIExtenderListener
{
    private $macroNamespace = 'ui';

    public function __construct(\Twig_Environment $oTwig, $aMacros)
    {
        $this->twig = $oTwig;

        //Macros
        $this->macros = $aMacros;
    }

    public function onKernelRequest(GetResponseEvent $oEvent)
    {
        $templates = [];
        foreach ($this->macros as $macro => $template)
        {
            $templates[$macro] = $this->twig->loadTemplate($template);
        }

        $this->twig->addGlobal($this->macroNamespace, $templates);

    }
}

捆绑包的 services.xml:

<?xml version="1.0" ?>

<container xmlns="http://symfony.com/schema/dic/services"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">

    <parameters>
        <parameter key="uiext.macros" type="collection">
            <parameter key="test">UIXBundle:ui:test.html.twig</parameter>
            <parameter key="list">UIXBundle:ui:list.html.twig</parameter>
            <parameter key="entity">UIXBundle:ui:entity.html.twig</parameter>
        </parameter>
    </parameters>

    <services>
        <service id="uiext.extender" class="App\Common\UIExtensionBundle\Listeners\UIExtenderListener" scope="container">
            <tag name="kernel.event_listener" event="kernel.request" method="onKernelRequest" priority="1000" />
            <argument type="service" id="twig"/>
            <argument>%uiext.macros%</argument>
        </service>
    </services>
</container>

这是

views\ui\list.html.twig
文件:

{% macro ol(arr) %}
    <ol>
        {% for item in arr %}
            <li>{{ item }}</li>
        {% endfor %}
    </ol>
{% endmacro %}

{% macro ul(arr) %}
    <ul>
        {% for item in arr %}
            <li>{{ item }}</li>
        {% endfor %}
    </ul>
{% endmacro %}

然后,从任何树枝模板中,只需添加

{{ ui.list.ul(listArr) }}

© www.soinside.com 2019 - 2024. All rights reserved.