我有一个第三方包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
对不起,这是不可能的…如果你打算重写控制器
我实际上是在寻找相同的东西。我的用例如下:
我有一个带有仪表板的网站。我想用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/
与提供的路径连接起来,可以解析每个名称空间的完整路径。