32. Поставщики услуг. 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
<?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']; } }