在Symfony 4/5中如何覆盖另一个Bundle的模板?

10
因为 Symfony 3.4 开始已不推荐使用 bundle inheritance,在 4.0 版本中将会被移除,因此我正在寻找新的解决方案。我有以下几个bundle:

  • Application
  • FooBundle
  • BarBundle

我没有问题可以在 Application 中覆盖模板。但我需要在 FooBundle 中覆盖 BarBundle 中的模板。这在 bundle inheritance 中非常容易实现,但现在我迷失了。

我尝试过 twig 命名空间,但是没有成功,也许我的配置方式不正确。我的目标是在 BarBundle 中有基础模板,我可以在 FooBundle 或 Application 中进行覆盖。(这是因为 BarBundle 是第三方 bundle,而 FooBundle 是我的 bundle,用于多个项目)。

是否还有不使用 bundle inheritance 的解决方案?如何实现?

谢谢。


1
你尝试过这个吗:https://symfony.com/doc/current/templating/overriding.html。虽然我自己已经有一段时间没有做过了,但它似乎足够简单。另一种方法是添加[命名空间twig路径](https://symfony.com/doc/current/templating/namespaced_paths.html)。 - Cerad
@Cerad:对我来说,那些东西看起来像是你自己应用程序的配置,但我认为OP正在寻找一个封装在他的捆绑包中的解决方案。 - Nico Haase
@NicoHaase 第二个链接展示了如何使用FooBundle添加Twig命名空间以覆盖BarBundle模板。然后,您可以在应用程序中添加一个来覆盖FooBundle的内容。在放弃Twig之前,我曾经做过这种无聊的事情。 - Cerad
3个回答

9
我将展示在我的情况下(Symfony 5.1)如何实现。要覆盖 JMoseCommandSchedulerBudnleTwigBundle 的视图,可以按照以下步骤进行: 1. 创建自己的目录并添加第三方包模板(我将它们放在 Resources/views/bundles 目录下): enter image description here 2. 为每个要覆盖模板的包创建文件夹: enter image description here 3. 创建自定义模板(例如,创建自定义 Twig 错误页面): enter image description here 4. 实现PrependExtensionInterface接口,并将自定义路径添加到Twig扩展配置中:
class AppngCmsExtension extends Extension implements PrependExtensionInterface {
    public function load(array $configs, ContainerBuilder $container)
    {
        $loader = new YamlFileLoader($container, new FileLocator(__DIR__ . '/../Resources/config'));
        $loader->load('services.yaml');
    }

    public function prepend(ContainerBuilder $container)
    {
        // I recommend using FileLocator here 
        $thirdPartyBundlesViewFileLocator = (new FileLocator(__DIR__ . '/../Resources/views/bundles'));

        $container->loadFromExtension('twig', [
            'paths' => [
                $thirdPartyBundlesViewFileLocator->locate('JMoseCommandSchedulerBundle') => 'JMoseCommandScheduler',
                $thirdPartyBundlesViewFileLocator->locate('TwigBundle') => 'Twig',
            ],
        ]);
    }
}

7

最近我需要同样的功能,通过@NicoHasse的评论帮助下,我成功地创建了一个工作示例。

在你的捆绑扩展类中,你需要实现PrependExtensionInterface,然后你可以修改twig路径。然后你需要知道你需要覆盖的原始命名空间(php bin/console debug:twig)。

你可以使用twig调试命令确认它是否工作,在那个命名空间的第一个位置上应该看到你的路径。

class YourExtensionClass extends Extension implements PrependExtensionInterface
{
    public function prepend(ContainerBuilder $container)
    {
        $container->loadFromExtension('twig', [
            'paths' => [
                '%kernel.project_dir%/vendor/xx/yy/zzz' => 'OriginalVNamespace',
            ]
        ]);

6
这是一个更易懂的例子。
让我们从一些假设开始。
您的bundle名称:AcmeBundle 您想要覆盖的bundle:FOSUserBundle 运行命令php bin/console debug:twig,并找到您想要覆盖的bundle的命名空间。在这种情况下,它是@FOSUser。
您的bundle扩展应该如下所示。
<?php // src/AcmeBundle/DependencyInjection/AcmeExtension.php

namespace AcmeBundle\DependencyInjection;

// ...

use Symfony\Component\DependencyInjection\Extension\PrependExtensionInterface;

class AcmeExtension extends Extension implements PrependExtensionInterface
{
    // ...

    public function prepend(ContainerBuilder $container)
    {
        $container->loadFromExtension('twig', array(
            'paths' => array(
                '%kernel.project_dir%/src/AcmeBundle/Resources/FOSUserBundle/views' => 'FOSUser', // You use the namespace you found earlier here. Discard the `@` symbol.
            ),
        ));
    }
}

现在你可以创建src/AcmeBundle/Resources/FOSUserBundle/views/Security/login.html.twig来覆盖FOSUserBundle的登录模板。
这只是FOSUserBundle的一个例子。您可以根据要覆盖的内容更改包名称。

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