从Symfony / Twig中覆盖的版本访问父模板


Access parent template from over-ridden version in Symfony / Twig

我有一个第三方包OriginalBundle,我想自定义其中的一些模板。

为了实现这一点,我使用Symfony文档中显示的覆盖方法设置了一个Symfony bundle MyCustomBundle

<?php
namespace My'CustomBundle;
use Symfony'Component'HttpKernel'Bundle'Bundle;
class MyCustomBundle extends Bundle
{
    public function getParent()
    {
        return 'OriginalBundle';
    }
}

然后我使用MyCustomBundle从OriginalBundle中创建一些Twig模板的覆盖版本。然而,我希望能够从我的版本访问原始模板(例如扩展它),只是覆盖一些块。

但是,如果我尝试这样做:

{# MyCustomBundle:Foo:bar.html.twig #}
{% extends 'OriginalBundle:Foo:bar.html.twig' %}
{% block xyz %}
    {# ... code in here ... #}
{% endblock %}

然后我得到一个白屏死机。我猜它会导致某种递归,因为Symfony正在路由extends回调到自定义文件?

原bundle的模板是这样的:

{# OriginalBundle:Foo:bar.html.twig #}
{% block abc %}
    {% block xyz %}
        {# ... code in here ... #}
    {% endblock %}
{% endblock %}

所以这个问题…

是否有任何方法可以访问原始模板文件时,同一模板的覆盖版本存在?

我基本上是在寻找parent::doSomething()的Twig/模板等效物。

如果没有这种对父文件的访问,我发现自己一字不差地复制了整个原始模板文件,然后更新了其中的一小部分,这感觉不对。

有一个解决方案。默认情况下,Symfony搜索第一个匹配资源并返回它。要改变这种行为,需要指定一些额外的语法。我用"!"来匹配第二个匹配

{% extends '!OriginalBundle:Foo:bar.html.twig' %}
{% block xyz %}
    {# ... code in here ... #}
{% endblock %}

重写文件可以在app/Resources/OriginalBundle/views/Foo/bar.html.twig

要激活这个系统,你需要覆盖原来的内核:

<?php
namespace Webility'Bundle'WebilityBundle'HttpKernel;
use Symfony'Component'HttpKernel'Kernel as BaseKernel;
abstract class Kernel extends BaseKernel
{
    public function getBundle($name, $first = true)
    {
        $get_next = false;
        if($name[0] == '!' && $first){
            $name = substr($name, 1);
            $first = false;
            $get_next = true;
        }
        $bundles = parent::getBundle($name, $first);
        if($get_next){
            return isset($bundles[1]) ? $bundles[1] : $bundles[0];
        } else {
            return $bundles;
        }
    }
    public function locateResource($name, $dir = null, $first = true)
    {
        $get_next = false;
        if($name[0] == '@' && $name[1] == '!' && $first){
            $name = '@'.substr($name, 2);
            $first = false;
            $get_next = true;
        }
        $files = parent::locateResource($name, $dir, $first);
        if($get_next){
            return isset($files[1]) ? $files[1] : $files[0];
        } else {
            return $files;
        }
    }
}

在app/AppKernel.php

中使用
class AppKernel extends 'Webility'Bundle'WebilityBundle'HttpKernel'Kernel

如果您想从链接到FooController的原始包中保留xyz块的视图,您必须输入

{{ parent() }}

否则,如果您重新定义块中没有任何内容,则会得到一个空页面。

你试过这样做吗?

{# MyCustomBundle:Foo:bar.html.twig #}
{% block xyz %}
    {# ... code in here ... #}
{% endblock %}

没有扩展部分?

如果你想保留你的'extends'到原始bundle,你必须使用方法a),所以创建app/Resources/original-bundle/views/layout.html。twig和/或app/Resources/original-bundle/views/Foo/bar.html。但是通过粘贴这些模板供应商文件的整个代码,因为你想重用它们(这些路径覆盖供应商的默认视图),然后你可以使用你的'extends'

如果你还想覆盖供应商的控制器,那么使用方法b):但即使在这种情况下,你也必须粘贴你想重用的代码(并且你必须在新bundle上做一个'extends')

因为我习惯于重写控制器,所以我使用方法b

对不起,这是不可能的…如果你打算重写控制器

,总是使用方法a)和b

我实际上是在寻找相同的东西。我的用例如下:

我有一个带有仪表板的网站。我想用bundle中的新数据扩展仪表板。每个bundle都有自己的数据,我想把它们放在仪表板中的一些块中。仪表板模板没有绑定到任何bundle,所以它应该是可访问的。

我想知道如何在不重载任何路由的情况下将块注入模板。

编辑:同样的东西为导航栏,例如-应该有一种方式来扩展块没有任何问题,所以它将很容易只是扩展主网站导航从捆绑包…

这个问题是由于Symfony将你的模板引用OriginalBundle解释为ChildBundle,这是由于bundle继承导致函数嵌套级别异常造成的。

你可以使用下面的符号来引用父组件的bundle模板文件:

{% extends "@Original/Foo/bar.html.twig" %}

替换:

{% extends "OriginalBundle:Foo:bar.html.twig" %}

Twig的FilesystemLoader将引用字符串分割为命名空间 (Original)和路径 (Foo/bar.html.twig)。Namespace是没有bundle后缀的bundle名。通过将默认的<bundle_path>/Resources/views/与提供的路径连接起来,可以解析每个名称空间的完整路径。