- Поставщики услуг. ServiceProvider
Введение
Поставщики услуг, или сервис-провайдеры (service providers), лежат в основе «первоначальной загрузки» всего Laravel. И ваше приложение, и все базовые сервисы Laravel загружаются через сервис-провайдеры.
Но что мы понимаем под «первоначальной загрузкой»? В основном это регистрация таких вещей как привязки сервис-контейнера, слушатели событий, посредники и даже маршруты. Сервис-провайдеры — центральное место для настройки вашего приложения.
Если вы откроете файл config/app.php, поставляемый с Laravel, то вы увидите массив providers. В нём перечислены все классы сервис-провайдеров, которые загружаются для вашего приложения. Конечно, многие из них являются «отложенными» (deferred), они не загружаются при каждом запросе, а только при необходимости.
В этом обзоре вы узнаете, как создавать свои собственные сервис-провайдеры и регистрировать их в своём приложении.
Создание сервис-провайдеров
Все сервис-провайдеры наследуют класс Illuminate\Support\ServiceProvider. В большинстве сервис-провайдеров есть методы register() и boot(). В методе register() вы должны только привязывать свои классы в сервис-контейнер. Никогда не пытайтесь зарегистрировать в этом методе слушателей событий, маршруты и какие-либо другие возможности.
С помощью Artisan CLI можно создать новый провайдер командой make:provider:
php artisan make:provider RiakServiceProvider
Метод register()
Как уже было сказано, внутри метода register() вы должны только привязывать свои классы в сервис-контейнер. Никогда не пытайтесь зарегистрировать в этом методе слушателей событий, маршруты и какие-либо другие возможности. Иначе может получиться, что вы обратитесь к сервису, предоставляемому сервис-провайдером, который ещё не был загружен.
Давайте взглянем на простой сервис-провайдер. Из любого метода вашего сервис-провайдера у вас всегда есть доступ к свойству $app, которое предоставляет доступ к сервис-контейнеру:
<?php
namespace App\Providers;
use Riak\Connection;
use Illuminate\Support\ServiceProvider;
class RiakServiceProvider extends ServiceProvider
{
/**
* Регистрация привязки в контейнере.
*
* @return void
*/
public function register()
{
$this->app->singleton(Connection::class, function ($app) {
//для версии 5.1 и ранее:
//$this->app->singleton('Riak\Contracts\Connection', function ($app) {
return new Connection(config('riak'));
});
}
}
Этот сервис-провайдер только определяет метод register() и использует его, чтобы определить реализацию Riak\Connection (для версии 5.1 и ранее — Riak\Contracts\Connection) в сервис-контейнере. Если вы не поняли, как работает сервис-контейнер, прочитайте его документацию.
+ 5.0
добавлено в 5.0 (08.02.2016)
Все сервис-провайдеры Laravel по-умолчанию размещены в namespace App\Providers. Там же разместится и наш класс. Но, естественно, вы всегда можете поменять его местоположение. Ваши сервис-провайдеры могут быть размещены где угодно, так чтобы Composer автоматически их загружал.
Метод boot()
А что, если нам нужно зарегистрировать построитель представления в нашем сервис-провайдере? Это нужно делать в методе boot. Этот метод вызывают после того, как все другие сервис-провайдеры были зарегистрированы. Это значит, что у вас есть доступ ко всем другим сервисам, которые были зарегистрированы фреймворком.
+ 5.3
добавлено в 5.3 (28.01.2017)
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
class ComposerServiceProvider extends ServiceProvider
{
/**
* Загрузка любых сервисов приложения.
*
* @return void
*/
public function boot()
{
view()->composer('view', function () {
//
});
}
}
+ 5.2
добавлено в 5.2 (08.12.2016)
<?php
namespace App\Providers;
use Illuminate\Contracts\Events\Dispatcher as DispatcherContract;
use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;
class EventServiceProvider extends ServiceProvider
{
// Свойства других сервис-провайдеров...
/**
* Регистрация всех остальных событий для вашего приложения.
*
* @param \Illuminate\Contracts\Events\Dispatcher $events
* @return void
*/
public function boot(DispatcherContract $events)
{
parent::boot($events);
view()->composer('view', function () {
//
});
}
}
+ 5.1 5.0
добавлено в 5.1 (19.06.2016) 5.0 (08.02.2016)
<?php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
class EventServiceProvider extends ServiceProvider
{
/**
* Загрузка сервисов после регистрации.
*
* @return void
*/
public function boot()
{
view()->composer('view', function () {
//
});
}
/**
* Привязка к контейнеру.
*
* @return void
*/
public function register()
{
//
}
}
Внедрение зависимостей метода boot()
Вы можете указать зависимости для метода boot() вашего сервис-провайдера. Сервис-контейнер автоматически внедрит те зависимости, которые вы зададите:
use Illuminate\Contracts\Routing\ResponseFactory;
public function boot(ResponseFactory $response)
{
$response->macro('caps', function ($value) {
//
});
}
Регистрация провайдеров
Все сервис-провайдеры регистрируются в файле config/app.php путем добавления имён их классов в массив providers. Изначально в нём указан набор базовых сервис-провайдеров Laravel. Эти провайдеры загружают базовые компоненты Laravel, такие как обработчик почты, очередь, кэш и другие.
Чтобы зарегистрировать свой сервис-провайдер, просто добавьте его в этот массив:
'providers' => [ // Другие сервис-провайдеры App\Providers\ComposerServiceProvider::class, ],
Отложенные провайдеры
Если ваш провайдер только регистрирует привязки в сервис-контейнере, то вы можете отложить регистрацию до момента, когда одна из этих привязок будет запрошена из сервис-контейнера. Это позволит не дёргать файловую систему при каждом запросе, что увеличит производительность вашего приложения.
Laravel собирает и хранит список всех сервисов, предоставляемых отложенными сервис-провайдерами, и их классов. Когда в процессе работы приложению понадобится один из этих сервисов, Laravel загрузит нужный сервис-провайдер.
Для того, чтобы сделать сервис-провайдер отложенным, установите свойство defer в true и определите метод provides(). Метод provides() должен вернуть привязки сервис-контейнера, зарегистрированные в вашем провайдере:
<?php
namespace App\Providers;
use Riak\Connection;
use Illuminate\Support\ServiceProvider;
class RiakServiceProvider extends ServiceProvider
{
/**
* Задаём, отложена ли загрузка провайдера.
*
* @var bool
*/
protected $defer = true;
/**
* Регистрация сервис-провайдера.
*
* @return void
*/
public function register()
{
$this->app->singleton(Connection::class, function ($app) {
//Для версии 5.1 и ранее:
//$this->app->singleton('Riak\Contracts\Connection', function ($app) {
return new Connection($app['config']['riak']);
});
}
/**
* Получить сервисы от провайдера.
*
* @return array
*/
public function provides()
{
return [Connection::class];
//Для версии 5.1 и ранее:
//return ['Riak\Contracts\Connection'];
}
}
