18

我想知道是否有一种简单的方法可以覆盖 Laravel 框架核心中的单例服务集?

例如,我正在尝试使用以下提供程序重写 app:name 命令服务“”:

use Hexavel\Console\AppNameCommand;
use Illuminate\Console\Events\ArtisanStarting;
use Illuminate\Contracts\Events\Dispatcher;
use Illuminate\Support\ServiceProvider;

class NameCommandProvider extends ServiceProvider
{
    /**
     * Register any other events for your application.
     *
     * @param  \Illuminate\Contracts\Events\Dispatcher  $events
     * @return void
     */
    public function boot(Dispatcher $events)
    {
        $events->listen(ArtisanStarting::class, function ($event) {
            $event->artisan->resolve('command.app.name');
        }, -1);
    }

    /**
     * Register the service provider.
     *
     * @return void
     */
    public function register()
    {
        $this->app->singleton('command.app.name', function ($app) {
            return new AppNameCommand($app['composer'], $app['files']);
        });
    }
}

由于进行了广泛的检查,我 100% 一切正常,无论我将我的服务提供商(高于或低于 ConsoleSupportServiceProvider)按什么顺序放置,它仍然会在我的自定义命令上加载原始 AppNameCommand。

我已经有一个解决方法,但是如果这可能的话,很高兴了解未来单例服务的行为?(如果这有什么不同,这是使用 Laravel 5.2。)

4

2 回答 2

30

实际上有一种更清洁的方法可以做到这一点。你基本上想扩展一个核心绑定,这可以通过使用以下extend方法来实现:

$this->app->extend('command.app.name', function ($command, $app) {
    return new AppNameCommand($app['composer'], $app['files']);
});

Jason Lewis在 Tutsplus 上有一篇关于 Laravel 的 IoC 的非常好的文章。一定要检查一下 ;)

于 2016-08-16T20:45:05.100 回答
5

我看了这个案子,似乎不是一件容易的事。如果您singleton在自定义提供者中使用它,它将最终被默认提供者(延迟的提供者)覆盖,所以它似乎不是这样。

在检查了这种简单的方法不起作用之后,您需要做的是分析 Laravel 注册此命令时发生的情况。

因此,在您的情况下,您首先搜索command.app.name-您会看到它在其中,Illuminate\Foundation\Providers\ArtisanServiceProvider并且registerAppNameCommand您可能希望覆盖某种方法。

所以现在你寻找ArtisanServiceProvider它的出现以查看它在哪里启动 - 你看到它Illuminate\Foundation\Providers\ConsoleSupportServiceProvider$providers财产中(你可能希望改变它)。

所以最后你应该寻找出现的ConsoleSupportServiceProvider并且你看到它在config/app.php.

所以在这种情况下你需要做的是:

  • 更改config/app.php- 更改Illuminate\Foundation\Providers\ConsoleSupportServiceProvider为您的自定义ConsoleSupportServiceProvider
  • 在您的自定义中,您应该从自定义扩展\Illuminate\Foundation\Providers\ConsoleSupportServiceProvider但从更改更改为$providersIlluminate\Foundation\Providers\ArtisanServiceProvider定义ArtisanServiceProvider
  • 最后创建自定义ArtisanServiceProvider,它将从\Illuminate\Foundation\Providers\ArtisanServiceProviderregisterAppNameCommand使用自定义类覆盖的位置扩展singleton

使用这种方式,您将实现您的目标(我已经验证了自定义类将用于运行命令php artisan app:name)。

或者,您可能希望在您的自定义删除ArtisanServiceProvider并使用您的自定义服务提供商,因为您显示了您注册单例的位置,但我没有尝试过这种方法。'AppName' => 'command.app.name',$devCommands

于 2015-12-23T07:26:41.870 回答