在Laravel服务提供商中,更换服务的最佳方式是什么


What is the best way to replace a service in a Laravel Service Provider?

我想将Laravel框架提供的服务替换为我自己的服务,该服务扩展了相同的Laravel服务。在这种特定情况下,我想交换BladeCompiler服务。

Laravel提供的默认ViewServiceProvider的作用如下:

use Illuminate'View'Engines'BladeCompiler;
use Illuminate'View'Engines'CompilerEngine;
...
public function registerBladeEngine($resolver)
{
    $app = $this->app;
    $resolver->register('blade', function() use ($app)
    {
        $cache = $app['path.storage'].'/views';
        $compiler = new BladeCompiler($app['files'], $cache);
        return new CompilerEngine($compiler, $app['files']);
    });
}

我唯一需要做的就是扩展提供程序,重写方法并替换编译器类。在这种情况下,My'View'Engines'BladeCompiler

但要做到这一点,我必须将所有函数复制并粘贴到我的服务提供商,只需替换use语句。这是一种糟糕的方法,因为对Laravel这一部分的任何修改都会破坏我的应用程序。

我真正想做的是创建另一个扩展默认刀片编译器类的类,为其添加更多功能

有人有更好的主意吗?

编辑:

我打开了一个描述该问题的问题,Taylor将对4.1进行更改,使扩展服务更加容易(至少是刀片编译器)。

我相信你有两个选择:

  1. 用您自己的覆盖服务提供商
  2. 利用BladeCompiler的extend()方法

选项1:服务提供商副本&粘贴

您要做的关键事情是用扩展版本覆盖Blade编译器。由于整个继承问题,您必须以与默认服务提供商完全相同的方式来定义它;尤其是这段代码:

$resolver->register('blade', function() use ($app)
{
    $cache = $app['path.storage'].'/views';
    // This is where your extended class would go.
    $compiler = new BladeCompiler($app['files'], $cache);
    return new CompilerEngine($compiler, $app['files']);
});

您可以通过以下方式访问服务提供商中的View类"EngineResolver":

$this->app['view']->getEngineResolver()

所有这些加在一起,您只剩下以下内容(替换类名并在适当的情况下修改use):

<?php
use Illuminate'Support'ServiceProvider;
use Illuminate'View'Engines'CompilerEngine;
class ExtendBladeServiceProvider extends ServiceProvider {
    public function register()
    {
        $resolver = $this->app['view']->getEngineResolver();
        $resolver->register('blade', function() use ($app)
        {
            $cache = $app['path.storage'].'/views';
            $compiler = new MyBladeCompiler($app['files'], $cache);
            return new CompilerEngine($compiler, $app['files']);
        });
    }
}

因此,是的,您基本上是在复制现有服务提供商的代码。但据我所知,你不得不这么做。我不知道你为什么担心Laravel会改变你的应用程序;你实际上依赖于Laravel组件,所以任何变化都可能破坏一切。使用无法控制的组件会带来风险。

选项2:BladeCompiler的extend()方法

这几乎可以在应用程序中任何有意义的地方进行。您不会在传统意义上扩展BladeCompiler类,但您可以实现自己的一组编译函数来运行。

extend()将提供的闭包添加到在编译期间迭代的数组中。它本质上与扩展类方法相同,不需要重新实例化CompileEngine之类的东西。

注册这些扩展的一种选择是使用服务提供商的boot()方法(您也可以使用register(),只需确保按正确的顺序进行):

public function boot()
{
    $blade = $this->app['view']->getEngineResolver()->resolve('blade')->getCompiler();
    $blade->extend(function($value) use ($blade)
    {
        $matcher = $blade->createMatcher('myfeature');
        return preg_replace($matcher, '<?php echo MyFeature::make$2; ?>', $value);
    });
}

您可以查看TwigBridge包的服务提供商。该包所做的是注册另一个视图处理程序(在本例中为.tritch文件)。既然你可能想为你的扩展刀片文件(.bladex?)有一个不同的扩展名,你可以做一些类似的事情

[警告:未经测试的代码]

$app['view']->addExtension('bladex','bladex',function() use($app) 
{
   $cache = $app['path.storage'].'/views';
   $compiler = new BladeXCompiler($app['files'], $cache);
   return new CompilerEngine($compiler, $app['files']);
}