【问题标题】:What is the best way to replace a service in a Laravel Service Provider?在 Laravel 服务提供者中替换服务的最佳方法是什么?
【发布时间】:2013-11-20 17:11:53
【问题描述】:

我想将 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 的那部分进行任何修改都会破坏我的应用程序。

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

有人有更好的主意吗?

编辑:

I opened an issue 描述了该问题,Taylor 将对 4.1 进行更改,使扩展服务更加容易(至少是刀片编译器)。

【问题讨论】:

  • 有趣的想法。正如你所注意到的,Blade 在 Laravel 中太深了,所以替换它可能会在内部破坏很多东西。如果你只想替换默认的模板引擎,在 laravel 论坛上有一些讨论forums.laravel.io/viewtopic.php?id=5346 无论如何,我认为你应该编写自己的包
  • 你能解释一下你的最终目标吗(使用你自己的模板引擎?)?为什么只需要更改use 语句?谢谢
  • 我想继续使用 Blade,但我想为其添加功能。我打开了编译器文件,简直是小菜一碟。所以,我想实现一些新功能。简而言之,我将创建一个扩展Illuminate\View\Engines\BladeCompilerMy\View\Engines\BladeCompiler。由于我只需要实例化我自己的类,因此我只需要复制提供者的方法并更改 use 语句。
  • 我的建议是向 laravel 本身发送一个补丁,将 BladeCompiler 对象提取到 blade.compiler 服务中。然后,您自己的提供者可以直接覆盖 blade.compiler,而无需触及 blade 服务。

标签: php laravel


【解决方案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);
    });
}

【讨论】:

    【解决方案2】:

    您可能会查看服务提供商的(很棒的)TwigBridge 包。该包所做的是注册另一个视图处理程序(在本例中为 .twig 文件)。由于您可能希望为扩展刀片文件(.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']);
    }
    

    【讨论】:

    • 我真的不想要另一个视图处理程序,我只想为 Blade 添加更多功能。事实上,我在我的应用程序中做了很多扩展,因此,一个解决方案使我能够使用尽可能少的代码来设置我的新类而不是默认类。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-05-08
    • 2019-03-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-01-11
    • 2019-05-29
    相关资源
    最近更新 更多