Переопределить синглтон в контейнере Laravel

Мне интересно, есть ли простой способ переопределить набор одноэлементных сервисов в ядре платформы Laravel?

например Я пытаюсь переписать приложение: name command service » со следующим поставщиком:

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, если это что-то меняет.)

9

Решение

На самом деле есть более чистый способ сделать это. В основном вы хотите расширить привязку ядра, чего можно добиться с помощью extend метод:

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

Джейсон Льюис есть действительно хорошая статья о IoC Laravel на Tutsplus. Не забудьте проверить это;)

14

Другие решения

Я посмотрел на этот случай, и, кажется, он не из легких. Если вы используете 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 но изменить в $providers от Illuminate\Foundation\Providers\ArtisanServiceProvider в ваш обычай ArtisanServiceProvider
  • наконец-то создать кастом ArtisanServiceProvider который простирается от \Illuminate\Foundation\Providers\ArtisanServiceProvider где вы переопределите registerAppNameCommand используя пользовательский класс в singleton

Используя этот способ, вы достигнете своей цели (я убедился, что пользовательский класс будет использоваться при выполнении команды php artisan app:name).

В качестве альтернативы вы можете захотеть ArtisanServiceProvider Удалить 'AppName' => 'command.app.name', от $devCommands и используйте своего поставщика услуг, как вы показали, где вы регистрируете свой синглтон, но я не пробовал этот подход.

5

По вопросам рекламы [email protected]