1. Архитектурные концепции
  2. Сервис-провайдеры

Присоединяйся к нашему Telegram сообществу @webblend!

Здесь ты найдешь сниппеты по Laravel и полезные советы по веб-разработке.

Введение

Сервис-провайдеры - центральное место для всех инициализаций Laravel-приложений. Ваше собственное приложение, а также все основные службы Laravel, инициализируются через сервис-провайдеры.

Но что мы имеем в виду под "инициализацией"? В общем, мы имеем в виду регистрацию вещей, включая регистрацию привязок контейнера служб, слушателей событий, промежуточного ПО и даже маршрутов. Сервис-провайдеры - центральное место для конфигурации вашего приложения.

Если вы откроете файл config/app.php, включенный в Laravel, вы увидите массив providers. В этом массиве перечислены все классы сервис-провайдеров, которые будут загружены для вашего приложения. По умолчанию в этом массиве перечислены основные сервис-провайдеры Laravel. Эти провайдеры откладывают загрузку, что означает, что они не будут загружены при каждом запросе, а только когда будут фактически нужны их службы.

В этом обзоре вы узнаете, как написать свои собственные сервис-провайдеры и зарегистрировать их в вашем приложении Laravel.

Примечание Если вы хотите узнать больше о том, как Laravel обрабатывает запросы и внутренне функционирует, ознакомьтесь с нашей документацией о жизненном цикле запроса.

Написание сервис-провайдеров

Все сервис-провайдеры расширяют класс Illuminate\Support\ServiceProvider. Большинство сервис-провайдеров содержат методы register и boot. Внутри метода register вы должны только регистрировать вещи в контейнере служб. Никогда не пытайтесь регистрировать слушателей событий, маршруты или любую другую функциональность внутри метода register.

Artisan CLI может сгенерировать новый провайдер с помощью команды make:provider:

php artisan make:provider RiakServiceProvider

Метод Register

Как упоминалось ранее, внутри метода register вы должны только регистрировать вещи в контейнере служб. Никогда не пытайтесь регистрировать слушателей событий, маршруты или любую другую функциональность внутри метода register. В противном случае вы можете случайно использовать службу, предоставляемую сервис-провайдером, который еще не загрузился.

Давайте рассмотрим базовый сервис-провайдер. Внутри любого метода вашего сервис-провайдера у вас всегда есть доступ к свойству $app, которое предоставляет доступ к контейнеру служб:

<?php
 
namespace App\Providers;
 
use App\Services\Riak\Connection;
use Illuminate\Contracts\Foundation\Application;
use Illuminate\Support\ServiceProvider;
 
class RiakServiceProvider extends ServiceProvider
{
/**
* Регистрация любых служб приложения.
*/
public function register(): void
{
$this->app->singleton(Connection::class, function (Application $app) {
return new Connection(config('riak'));
});
}
}

Этот сервис-провайдер определяет только метод register и использует его для определения реализации App\Services\Riak\Connection в контейнере служб. Если вы еще не знакомы с контейнером служб Laravel, ознакомьтесь с его документацией.

Свойства bindings и singletons

Если ваш сервис-провайдер регистрирует много простых привязок, вы можете использовать свойства bindings и singletons вместо ручной регистрации каждой привязки контейнера. Когда фреймворк загружает сервис-провайдер, он автоматически проверит эти свойства и зарегистрирует их привязки:

<?php
 
namespace App\Providers;
 
use App\Contracts\DowntimeNotifier;
use App\Contracts\ServerProvider;
use App\Services\DigitalOceanServerProvider;
use App\Services\PingdomDowntimeNotifier;
use App\Services\ServerToolsProvider;
use Illuminate\Support\ServiceProvider;
 
class AppServiceProvider extends ServiceProvider
{
/**
* Все привязки контейнера, которые должны быть зарегистрированы.
*
* @var array
*/
public $bindings = [
ServerProvider::class => DigitalOceanServerProvider::class,
];
 
/**
* Все синглтоны контейнера, которые должны быть зарегистрированы.
*
* @var array
*/
public $singletons = [
DowntimeNotifier::class => PingdomDowntimeNotifier::class,
ServerProvider::class => ServerToolsProvider::class,
];
}

Метод Boot

Итак, что делать, если нам нужно зарегистрировать композер представлений внутри нашего сервис-провайдера? Это следует сделать в методе boot. Этот метод вызывается после регистрации всех остальных сервис-провайдеров, что означает, что у вас есть доступ ко всем остальным службам, зарегистрированным фреймворком:

<?php
 
namespace App\Providers;
 
use Illuminate\Support\Facades\View;
use Illuminate\Support\ServiceProvider;
 
class ComposerServiceProvider extends ServiceProvider
{
/**
* Запуск служб приложения.
*/
public function boot(): void
{
View::composer('view', function () {
// ...
});
}
}

Метод Dependency Injection Boot

Вы можете указывать зависимости для метода boot своего сервис-провайдера. Контейнер служб автоматически внедрит любые зависимости, которые вам нужны:

use Illuminate\Contracts\Routing\ResponseFactory;
 
/**
* Запуск служб приложения.
*/
public function boot(ResponseFactory $response): void
{
$response->macro('serialized', function (mixed $value) {
// ...
});
}

Регистрация провайдеров

Все сервис-провайдеры регистрируются в файле конфигурации config/app.php. Этот файл содержит массив providers, где вы можете перечислить классы ваших сервис-провайдеров. По умолчанию в этот массив уже включены основные сервис-провайдеры Laravel. Они инициализируют основные компоненты Laravel, такие как почтовик, очередь, кэш и другие.

Чтобы зарегистрировать свой провайдер, добавьте его в массив:

'providers' => ServiceProvider::defaultProviders()->merge([
// Другие службы.
 
App\Providers\ComposerServiceProvider::class,
])->toArray(),

Отложенные провайдеры

Если ваш провайдер только регистрирует привязки в контейнере служб, вы можете отложить его регистрацию до тех пор, пока не потребуется одна из зарегистрированных привязок. Отложение загрузки такого провайдера улучшит производительность вашего приложения, поскольку он не загружается с файловой системы при каждом запросе.

Laravel компилирует и сохраняет список всех служб, предоставляемых отложенными сервис-провайдерами, а также имя их класса. Тогда, только когда вы пытаетесь получить одну из этих служб, Laravel загружает сервис-провайдер.

Для отложенной загрузки провайдера реализуйте интерфейс \Illuminate\Contracts\Support\DeferrableProvider и определите метод provides. Метод provides должен возвращать привязки контейнера служб, зарегистрированные провайдером:

<?php
 
namespace App\Providers;
 
use App\Services\Riak\Connection;
use Illuminate\Contracts\Foundation\Application;
use Illuminate\Contracts\Support\DeferrableProvider;
use Illuminate\Support\ServiceProvider;
 
class RiakServiceProvider extends ServiceProvider implements DeferrableProvider
{
/**
* Регистрация любых служб приложения.
*/
public function register(): void
{
$this->app->singleton(Connection::class, function (Application $app) {
return new Connection($app['config']['riak']);
});
}
 
/**
* Получите службы, предоставленные этим провайдером.
*
* @return array<int, string>
*/
public function provides(): array
{
return [Connection::class];
}
}