从另一个包覆盖symfony扩展的"正确"方法是什么

use*_*149 12 php symfony twig

我需要覆盖文件/vendor/symfony/symfony/src/Symfony/Bundle/TwigBundle/Extension/AssetsExtension.php

它使用twig函数'asset'从bundle中加载twig getAssetUrl

/**
 * Returns a list of functions to add to the existing list.
 *
 * @return array An array of functions
 */
public function getFunctions()
{
    return array(
        new \Twig_SimpleFunction('asset', array($this, 'getAssetUrl')),
        new \Twig_SimpleFunction('assets_version', array($this, 'getAssetsVersion')),
    );
}
Run Code Online (Sandbox Code Playgroud)

我想覆盖asset()twig函数而不触及核心文件,否则将被下一个symfony更新覆盖

kba*_*kba 8

请考虑您的代码位于AppBundle名称空间中.首先在app/config.yml或src/AppBundle/Resources/config/something.yml中创建服务配置(您必须在bundle扩展中加载此配置文件).不要忘记把它放在服务密钥下面.

twig.extension.assets:
    class:     AppBundle\Twig\AssetsExtension
    arguments: ["@service_container", "@?router.request_context"]
    public: false
    tags:
        - { name: twig.extension }
Run Code Online (Sandbox Code Playgroud)

现在让我们创建扩展src/AppBundle/Twig/AssetsExtension.php.这个类继承自原始扩展,我将只覆盖一个方法(在模板asset()中).

<?php

namespace AppBundle\Twig;

class AssetsExtension extends \Symfony\Bundle\TwigBundle\Extension\AssetsExtension
{
    public function getAssetUrl($path, $packageName = null, $absolute = false, $version = null)
    {
        return parent::getAssetUrl('/something/' . $path, $packageName, $absolute, $version);
    }
}
Run Code Online (Sandbox Code Playgroud)

现在,重新加载后,您的所有资产都应该是不正确的,默认情况下以/ something /为前缀.如果出现问题,您可以尝试删除Symfony缓存.我在Symfony 2.5.5上测试了这个场景.

另一种如何使用内置服务的方法是编译器传递.在编译器传递中,您可以修改整个Symfony服务容器(删除,替换,修改服务).Symfony就是DIC.我希望这是足够好的解决方案.


小智 8

我提供了另一个解决方案,因为自symfony 3.0以来,服务的类名不再可覆盖.您必须选择编译器传递解决方案.

假设你想在twig中覆盖url()函数,你应该为它创建一个编译器传递并更改定义:

<?php
// AppBundle/AppBundle.php

namespace AppBundle;

use AppBundle\DependencyInjection\Compiler\TwigRoutingExtensionPass;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\HttpKernel\Bundle\Bundle;

class AppBundle extends Bundle
{
    public function build(ContainerBuilder $container)
    {
        parent::build($container);

        $container->addCompilerPass(new TwigRoutingExtensionPass());
    }
}
Run Code Online (Sandbox Code Playgroud)

然后创建TwigRoutingExtensionPass文件:

<?php
// AppBundle/DependencyInjectoin/Compiler/TwigRoutingExtensionPass.php    

namespace AppBundle\DependencyInjection\Compiler;

use AppBundle\Twig\Extension\RoutingExtension;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;

class TwigRoutingExtensionPass implements CompilerPassInterface
{
    public function process(ContainerBuilder $container)
    {
        if (false === $container->hasDefinition('twig.extension.routing')) {
            return;
        }

        $definition = $container->getDefinition('twig.extension.routing');
        $definition->setClass(RoutingExtension::class);
    }
}
Run Code Online (Sandbox Code Playgroud)

然后创建您的RoutingExtension文件.

如果要为新扩展注入一些服务:

<?php

    $definition->addArgument('some_service');
    // OR
    $definition->addMethodCall('setSomeService' [$container->get('some_service')]);
Run Code Online (Sandbox Code Playgroud)