Увійти Реєстрація
Блог Серії
Кар'єра
Вакансії Компанії
Навчання
Документація Співбесіди Тестування Відео
Екосистема
Пакети Ресурси Проєкти
Інше
Події Про нас

Сервіс-провайдери

Вступ

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

Але що ми маємо на увазі під «завантаженням»? Загалом - реєстрацію речей: прив'язок сервіс-контейнера, слухачів подій, middleware і навіть маршрутів. Сервіс-провайдери є центральним місцем налаштування вашого застосунку.

Внутрішньо Laravel використовує десятки сервіс-провайдерів, щоб завантажити свої базові сервіси - поштовий модуль, черги, кеш тощо. Багато з цих провайдерів «відкладені», тобто вони завантажуються не на кожному запиті, а лише тоді, коли сервіси, які вони надають, справді потрібні.

Усі визначені вами сервіс-провайдери реєструються у файлі bootstrap/providers.php. Далі в документації ви дізнаєтеся, як писати власні сервіс-провайдери та реєструвати їх у своєму застосунку Laravel.

Якщо ви хочете дізнатися більше про те, як Laravel обробляє запити й працює всередині, перегляньте нашу документацію про життєвий цикл запиту.

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

Усі сервіс-провайдери успадковують клас Illuminate\Support\ServiceProvider. Більшість сервіс-провайдерів містять методи register і boot. У методі register слід лише прив'язувати речі до сервіс-контейнера. Ніколи не намагайтеся реєструвати в методі register слухачів подій, маршрути чи будь-яку іншу функціональність.

Artisan CLI може згенерувати новий провайдер командою make:provider. Laravel автоматично зареєструє ваш новий провайдер у файлі bootstrap/providers.php вашого застосунку:

php artisan make:provider RiakServiceProvider

Метод 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
{
    /**
     * Register any application services.
     */
    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
{
    /**
     * All of the container bindings that should be registered.
     *
     * @var array
     */
    public $bindings = [
        ServerProvider::class => DigitalOceanServerProvider::class,
    ];

    /**
     * All of the container singletons that should be registered.
     *
     * @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
{
    /**
     * Bootstrap any application services.
     */
    public function boot(): void
    {
        View::composer('view', function () {
            // ...
        });
    }
}

Впровадження залежностей у методі boot

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

use Illuminate\Contracts\Routing\ResponseFactory;

/**
 * Bootstrap any application services.
 */
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
{
    /**
     * Register any application services.
     */
    public function register(): void
    {
        $this->app->singleton(Connection::class, function (Application $app) {
            return new Connection($app['config']['riak']);
        });
    }

    /**
     * Get the services provided by the provider.
     *
     * @return array<int, string>
     */
    public function provides(): array
    {
        return [Connection::class];
    }
}