Сервіс-провайдери · Laravel
Вступ
Сервіс-провайдери - центральне місце всього початкового завантаження Laravel-застосунку. Ваш власний застосунок, як і всі базові сервіси Laravel, завантажуються через сервіс-провайдери.
Але що ми маємо на увазі під «завантажуються» (bootstrapped)? Загалом ідеться про реєстрацію речей: привʼязок контейнера сервісів, слухачів подій, middleware і навіть маршрутів. Сервіс-провайдери - центральне місце для налаштування вашого застосунку.
Усередині Laravel використовує десятки сервіс-провайдерів, щоб завантажити свої базові сервіси: мейлер, чергу, кеш та інші. Багато з цих провайдерів є «відкладеними» (deferred), тобто вони завантажуються не на кожен запит, а лише тоді, коли сервіси, які вони надають, справді потрібні.
Усі сервіс-провайдери, визначені користувачем, реєструються у файлі bootstrap/providers.php. У документації нижче ви дізнаєтесь, як писати власні сервіс-провайдери та реєструвати їх у своєму Laravel-застосунку.
Примітка Якщо хочете дізнатися більше про те, як Laravel обробляє запити та працює всередині, перегляньте документацію про життєвий цикл запиту в Laravel.
Написання сервіс-провайдерів
Усі сервіс-провайдери успадковують клас Illuminate\Support\ServiceProvider. Більшість сервіс-провайдерів містить методи register і boot. У межах методу register слід лише привʼязувати речі до контейнера сервісів. Ніколи не намагайтеся реєструвати слухачів подій, маршрути чи будь-яку іншу функціональність у методі register.
Artisan CLI може згенерувати новий провайдер командою make:provider. Laravel автоматично зареєструє ваш новий провайдер у файлі bootstrap/providers.php вашого застосунку:
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 () {
// ...
});
}
}
Впровадження залежностей у метод boot
Ви можете вказати типи залежностей для методу boot вашого сервіс-провайдера. Контейнер сервісів автоматично впровадить будь-які потрібні вам залежності:
use Illuminate\Contracts\Routing\ResponseFactory;
/**
* Завантажує будь-які сервіси застосунку.
*/
public function boot(ResponseFactory $response): void
{
$response->macro('serialized', function (mixed $value) {
// ...
});
}
Реєстрація провайдерів
Усі сервіс-провайдери реєструються у файлі конфігурації bootstrap/providers.php. Цей файл повертає масив з іменами класів сервіс-провайдерів вашого застосунку:
<?php
return [
App\Providers\AppServiceProvider::class,
];
Коли ви викликаєте Artisan-команду make:provider, Laravel автоматично додає згенерований провайдер до файлу bootstrap/providers.php. Але якщо ви створили клас провайдера вручну, додайте його до масиву самостійно:
<?php
return [
App\Providers\AppServiceProvider::class,
App\Providers\ComposerServiceProvider::class, // [tl! add]
];
Відкладені провайдери
Якщо ваш провайдер реєструє лише привʼязки в контейнері сервісів, ви можете відкласти його реєстрацію до моменту, коли одна із зареєстрованих привʼязок справді знадобиться. Відкладене завантаження такого провайдера покращить швидкодію вашого застосунку, оскільки він не буде завантажуватися з файлової системи на кожен запит.
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];
}
}
Перекладаємо з офіційної документації, розділ за розділом, і не ховаємо недоперекладене. Помітили неточність у терміні чи реченні: напишіть, виправимо.