Symfony/Twig: 如何停止渲染模板的其余部分

9

我一直在网上搜索这个问题,但没有找到任何相关的信息。

我正在创建一个简单的twig模板,它将在多个位置使用,但需要一些变量。

我想能够像这样做:

{% if some_variable is not defined %}
    <h1>Some variable was not defined.<h1>
    -- stop rendering the rest of the template --
{% endif %}

{{ some_variable }} is defined here.

我提出这个问题的原因很简单。我不想让整个模板在一个或多个if语句中缩进,因为这会很容易使整个文件混乱。
我知道解决方法是创建多个模板,但对于一个简单的条件来说,创建多个文件似乎有些过分了。
如果没有内置的解决方法,我可以创建一个扩展来实现这一点,如果有人能告诉我如何做到这一点。
谢谢!P.S. 不要用{% else %}作答,那正是我想要避免的东西...

你可以创建自己的扩展并实现 PHP 的 die 函数。 - Matteo
那会停止整个应用程序的执行。抱歉,但这绝对不是我想要的 ;) - Harold
2个回答

3
您所要求的并不是原生支持的。为了实现这样的事情,您需要经历很多麻烦。
Twig模板会被编译成PHP,并由Twig自身的基本模板进行扩展。当查看基本模板时,您将看到最终将调用doDisplay函数。该函数的内容示例如下:
    protected function doDisplay(array $context, array $blocks = array())
    {
        // line 1
        echo "\t<div id=\"null_wrapper\">
\t\t<div class=\"invoice_price\">\t\t\t
\t\t\t<div>
\t\t\t\t";
        // line 4
        echo twig_escape_filter($this->env, $this->getAttribute((isset($context["forms"]) ? $context["forms"] : $this->getContext($context, "forms")), "getTextfield", array(0 => "#label_Quantity#", 1 => "txt_new_quantity", 2 => ((array_key_exists("txt_quantity", $context)) ? (_twig_default_filter((isset($context["txt_quantity"]) ? $context["txt_quantity"] : $this->getContext($context, "txt_quantity")), 1)) : (1)), 3 => ((array_key_exists("errors", $context)) ? (_twig_default_filter((isset($context["errors"]) ? $context["errors"] : $this->getContext($context, "errors")), "")) : ("")), 4 => "", 5 => "smallinput"), "method"), "html", null, true);
        echo "
\t\t\t</div>
\t\t\t<div class=\"clear\"></div>
\t\t\t<div>
\t\t\t\t";
        // line 8
        echo twig_escape_filter($this->env, $this->getAttribute((isset($context["forms"]) ? $context["forms"] : $this->getContext($context, "forms")), "getTextfield", array(0 => "#label_Unit_price#", 1 => "txt_new_price_excl", 2 => ((array_key_exists("txt_new_price_excl", $context)) ? (_twig_default_filter((isset($context["txt_new_price_excl"]) ? $context["txt_new_price_excl"] : $this->getContext($context, "txt_new_price_excl")), "")) : ("")), 3 => ((array_key_exists("errors", $context)) ? (_twig_default_filter((isset($context["errors"]) ? $context["errors"] : $this->getContext($context, "errors")), "")) : ("")), 4 => "", 5 => "smallinput"), "method"), "html", null, true);
        echo "<span>";
        echo twig_escape_filter($this->env, getSiteConfigValue("CURRENCY"), "html", null, true);
        echo "</span>
\t\t\t</div>
\t\t\t<div class=\"clear\"></div>
\t\t\t<div>
\t\t\t\t";

如您所见,输出内容会立即发送到浏览器(并被基本模板中的ob_start捕获),因此,即使您退出模板,也有可能导致HTML出现错误。

TL:DR 实现这样的事情的唯一方法是覆盖 twig 编译器,该编译器将 twig 模板编译为 PHP。也许您可以编写自己的节点,因为这也会呈现/编译。


感谢您的快速回复,DarkBee。我想我会接受这个解决方法。不过很遗憾,这听起来确实更加麻烦。 - Harold

3

我可能没有完全理解原意,但是我发现通过扩展Twig模板函数可以很容易地实现这一点,我称之为cancel

public function cancel($msg = '') {
        throw new Twig\Error\Error("Process cancelled with msg: $msg");
}

正如您所看到的,它只是抛出一个异常。在模板之外,这个异常被捕获并处理。

在模板中,我写下了这个:

{{ cancel('My reason for cancelling') }}

根据我的测试,就我所知道的,模板处理就到这里了。

要添加扩展,请按照正常程序进行操作。


抛出异常后,模板的其余部分是否仍然呈现? - DarkBee
正如答案中所说,不会有任何模板处理。 - pgr
1
那我就不明白这怎么回答问题了。这意味着你最终可能会得到损坏的HTML,正如我在我的答案中指出的那样。 - DarkBee
那个被涵盖在“I might be missing something of the original intent”中了 :-) 是的,你可能最终会得到破碎的HTML,但Twig在许多方面都有用途,在我的情况下,模板正在执行完全不同的操作(类似于执行低代码程序),我并不太关心输出被中断。我想那些给我点赞的人也找到了它的用途。我想他们和我一样,只是看了问题的标题而已,而不是实际问题的细节...但你问这个问题很好,这些评论有助于澄清。 - pgr

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接