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

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

Существует два важных метода: boot и register, которые может реализовать ваш сервис провайдер, и в последнем разделе этой статьи мы подробно их обсудим.

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

Понимание сервисных контейнеров и сервис провайдеров

Что такое контейнер сервисов?

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

По словам официальной документации Laravel:

Сервисный контейнер Laravel — это мощный инструмент для управления зависимостями классов и выполнения инъекции зависимостей.

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

Давайте посмотрим на быстрый пример, чтобы понять это.

Class SomeClass
{
public function __construct(FooBar $foobarObject)
{
// use $foobarObject object
}
}

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

И если вам интересно, как Laravel знает, какие компоненты или сервисы включить в контейнер, ответ будет — сервис провайдер. Сервис провайдер сообщает Laravel о подключении различных компонентов в контейнер служб. Фактически, это называется привязкой к контейнерам службы, и вам нужно сделать это через сервис провайдер.

Таким образом, сервис провайдер регистрирует все привязки контейнера, и это делается с помощью метода register реализации сервис провайдера.

Сразу должен всплыть еще один вопрос: как Laravel знает о различных сервис провайдерах? Вы только что сказали что-нибудь? Я только что слышал, как кто-то сказал, что Laravel тоже должен это понять автоматически! Ох, вы просите слишком много: Laravel — это фреймворк, а не сверхчеловек, не так ли? Так что сервис провайдеры, это то, что вам нужно, чтобы сообщить Ларавелю напрямую.

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

‘providers’ => [

/*
* Laravel Framework Service Providers…
*/
IlluminateAuthAuthServiceProvider::class,
IlluminateBroadcastingBroadcastServiceProvider::class,
IlluminateBusBusServiceProvider::class,
IlluminateCacheCacheServiceProvider::class,
IlluminateFoundationProvidersConsoleSupportServiceProvider::class,
IlluminateCookieCookieServiceProvider::class,
IlluminateDatabaseDatabaseServiceProvider::class,
IlluminateEncryptionEncryptionServiceProvider::class,
IlluminateFilesystemFilesystemServiceProvider::class,
IlluminateFoundationProvidersFoundationServiceProvider::class,
IlluminateHashingHashServiceProvider::class,
IlluminateMailMailServiceProvider::class,
IlluminateNotificationsNotificationServiceProvider::class,
IlluminatePaginationPaginationServiceProvider::class,
IlluminatePipelinePipelineServiceProvider::class,
IlluminateQueueQueueServiceProvider::class,
IlluminateRedisRedisServiceProvider::class,
IlluminateAuthPasswordsPasswordResetServiceProvider::class,
IlluminateSessionSessionServiceProvider::class,
IlluminateTranslationTranslationServiceProvider::class,
IlluminateValidationValidationServiceProvider::class,
IlluminateViewViewServiceProvider::class,

/*
* Package Service Providers…
*/
LaravelTinkerTinkerServiceProvider::class,

/*
* Application Service Providers…
*/
AppProvidersAppServiceProvider::class,
AppProvidersAuthServiceProvider::class,
// AppProvidersBroadcastServiceProvider::class,
AppProvidersEventServiceProvider::class,
AppProvidersRouteServiceProvider::class,
],

Итак, это был контейнер в вашем распоряжении. В следующем разделе мы сосредоточимся на сервис провайдере, который является основной темой этой статьи!

Что такое сервис провайдер?

Если контейнер — это то, что позволяет вам определять привязки и устанавливать зависимости, сервис провайдер — это место, где все это происходит.

Давайте быстро взглянем на одного из основных сервис провайдеров, чтобы понять, что он делает. Откройте файл vender/laravel/framework/src/Illuminate/Cache/CacheServiceProvider.php.

public function register()
{
$this->app->singleton(‘cache’, function ($app) {
return new CacheManager($app);
});

$this->app->singleton(‘cache.store’, function ($app) {
return $app[‘cache’]->driver();
});

$this->app->singleton(‘memcached.connector’, function () {
return new MemcachedConnector;
});
}

Здесь важно отметить метод register, который позволяет вам определять привязки контейнера. Как вы можете видеть, существует три привязки для служб cache, cache.store и memcached.connector.

В основном, мы информируем Laravel о том, что всякий раз, когда есть необходимость разрешить получить сервис cache, он должен вернуть экземпляр CacheManager. Поэтому мы просто добавляем это соответствие в контейнер, к которому можно получить доступ через $this->app.

Это правильный способ добавления любого сервиса в контейнер Laravel. Это также позволяет вам понять, как Laravel проходит через метод register всех сервис провайдеров и заполняет контейнер! Как мы уже упоминали ранее, он использует список сервис провайдеров из файла config/app.php.

И это была история о сервис провайдере. В следующем разделе мы обсудим, как создать специализированного сервис провайдера, чтобы вы могли зарегистрировать свои пользовательские сервисы в контейнере Laravel.

Создание собственного сервис провайдера

В Laravel уже есть удобная утилита командной строки, artisan, которая позволяет вам создавать код шаблона, так что вам не нужно создавать его с нуля. Перейдите в командную строку и выполните следующую команду в корне приложения, чтобы создать пользовательский сервис провайдер.

$php artisan make:provider EnvatoCustomServiceProvider
Provider created successfully.

И эта команда должна создать файл EnvatoCustomServiceProvider.php в каталоге app/Providers. Откройте файл, чтобы узнать, что в нем держится.

<?php
namespace AppProviders;

use IlluminateSupportServiceProvider;

class EnvatoCustomServiceProvider extends ServiceProvider
{
/**
* Bootstrap the application services.
*
* @return void
*/
public function boot()
{
//
}

/**
* Register the application services.
*
* @return void
*/
public function register()
{
//
}
}

Как мы обсуждали ранее, существует два метода: register и booy, с которыми вы будете иметь дело большую часть времени, когда работаете с вашим пользовательским сервис провайдером.

Метод register — это место, где вы определяете все пользовательские привязки контейнера. С другой стороны, метод boot — это место, где вы можете использовать уже зарегистрированные через метод register службы. В последнем разделе этой статьи мы подробно обсудим эти два метода, поскольку мы рассмотрим некоторые практические примеры, чтобы понять использование обоих методов.

Зарегистрируйте свой пользовательский сервис провайдер

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

Чтобы зарегистрировать сервис провайдер, вам просто нужно добавить запись в массив сервис провайдеров в файле config/app.php.

‘providers’ => [

/*
* Laravel Framework Service Providers…
*/
IlluminateAuthAuthServiceProvider::class,
IlluminateBroadcastingBroadcastServiceProvider::class,
IlluminateBusBusServiceProvider::class,
IlluminateCacheCacheServiceProvider::class,
IlluminateFoundationProvidersConsoleSupportServiceProvider::class,
IlluminateCookieCookieServiceProvider::class,
IlluminateDatabaseDatabaseServiceProvider::class,
IlluminateEncryptionEncryptionServiceProvider::class,
IlluminateFilesystemFilesystemServiceProvider::class,
IlluminateFoundationProvidersFoundationServiceProvider::class,
IlluminateHashingHashServiceProvider::class,
IlluminateMailMailServiceProvider::class,
IlluminateNotificationsNotificationServiceProvider::class,
IlluminatePaginationPaginationServiceProvider::class,
IlluminatePipelinePipelineServiceProvider::class,
IlluminateQueueQueueServiceProvider::class,
IlluminateRedisRedisServiceProvider::class,
IlluminateAuthPasswordsPasswordResetServiceProvider::class,
IlluminateSessionSessionServiceProvider::class,
IlluminateTranslationTranslationServiceProvider::class,
IlluminateValidationValidationServiceProvider::class,
IlluminateViewViewServiceProvider::class,

/*
* Package Service Providers…
*/
LaravelTinkerTinkerServiceProvider::class,

/*
* Application Service Providers…
*/
AppProvidersAppServiceProvider::class,
AppProvidersAuthServiceProvider::class,
// AppProvidersBroadcastServiceProvider::class,
AppProvidersEventServiceProvider::class,
AppProvidersRouteServiceProvider::class,
AppProvidersEnvatoCustomServiceProvider::class,
],

Вот и все! Вы зарегистрировали свой сервис провайдер с помощью схемы Laravel! Но созданный нами сервис провайдер — это почти пустой шаблон и он не используется на данный момент. В следующем разделе мы рассмотрим несколько практических примеров, чтобы узнать, что вы можете сделать с помощью методов register и boot.

Пройдемся по методам regsiter и boot

Для начала мы рассмотрим метод register, чтобы понять, как вы можете его использовать. Откройте созданный ранее файл сервис провайдера app/Providers/EnvatoCustomServiceProvider.php и замените существующий код следующим.

<?php
namespace AppProviders;

use IlluminateSupportServiceProvider;
use AppLibraryServicesDemoOne;

class EnvatoCustomServiceProvider extends ServiceProvider
{
public function boot()
{
}

public function register()
{
$this->app->bind(‘AppLibraryServicesDemoOne’, function ($app) {
return new DemoOne();
});
}
}

Здесь есть два важных момента:

  • Мы импортировали AppLibraryServicesDemoOne, чтобы мы могли его использовать. Класс DemoOne еще не создан, но мы сделаем это через мгновение.
  • В методе register мы использовали метод bind контейнера служб для добавления привязки нашего сервиса к контейнеру. Таким образом, всякий раз, когда должна быть разрешена зависимость AppLibraryServicesDemoOne, она вызывает замыкание, которое создает экземпляр и возвращает объект AppLibraryServicesDemoOne.

Для этого вам просто нужно создать файл app/Library/Services/DemoOne.php.

<?php
namespace AppLibraryServices;

class DemoOne
{
public function doSomethingUseful()
{
return ‘Output from DemoOne’;
}
}

И вот код где-то в вашем контроллере, где будет введена зависимость.

<?php
namespace AppHttpControllers;

use AppHttpControllersController;
use AppLibraryServicesDemoOne;

class TestController extends Controller
{
public function index(DemoOne $customServiceInstance)
{
echo $customServiceInstance->doSomethingUseful();
}
}

Это очень простой пример привязки класса. Фактически, в приведенном выше примере нет необходимости создавать сервис провайдер и внедрять метод register, как это было сделано, поскольку Laravel может автоматически разрешать его с помощью отражения.

Очень важное замечание из документации Laravel:

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

С другой стороны, это было бы очень полезно, если бы вы связали интерфейс с определенной реализацией. Давайте рассмотрим пример, чтобы понять это.

Давайте создадим очень простой интерфейс в app/Library/Services/Contracts/CustomServiceInterface.php.

<?php
// app/Library/Services/Contracts/CustomServiceInterface.php
namespace AppLibraryServicesContracts;

Interface CustomServiceInterface
{
public function doSomethingUseful();
}

Затем давайте создадим две реализации этого интерфейса. В принципе, нам просто нужно создать два класса, которые реализуют интерфейс CustomServiceInterface.

Создайте класс DemoOne в app/Library/Services/DemoOne.php.

<?php
// app/Library/Services/DemoOne.php
namespace AppLibraryServices;

use AppLibraryServicesContractsCustomServiceInterface;

class DemoOne implements CustomServiceInterface
{
public function doSomethingUseful()
{
return ‘Output from DemoOne’;
}
}

Аналогично, DemoTwo будет в App/Library/Services/DemoTwo.php.

<?php
// app/Library/Services/DemoTwo.php
namespace AppLibraryServices;

use AppLibraryServicesContractsCustomServiceInterface;

class DemoTwo implements CustomServiceInterface
{
public function doSomethingUseful()
{
return ‘Output from DemoTwo’;
}
}

Теперь вместо привязки класса мы свяжем интерфейс. Снова откройте EnvatoCustomServiceProvider.php и измените код, как показано ниже.

<?php
namespace AppProviders;

use IlluminateSupportServiceProvider;
use AppLibraryServicesDemoOne;

class EnvatoCustomServiceProvider extends ServiceProvider
{
public function boot()
{
}

public function register()
{
$this->app->bind(‘AppLibraryServicesContractsCustomServiceInterface’, function ($app) {
return new DemoOne();
});
}
}

В этом случае мы привязали интерфейс AppLibraryServicesContractsCustomServiceInterface к реализации DemoOne. Следовательно, всякий раз, когда необходимо разрешить зависимость AppLibraryServicesContractsCustomServiceInterface, будет создан экземпляр и возвращен объект AppLibraryServicesDemoOne. Теперь это имеет смысл, не так ли?

Давайте быстро пересмотрим код контроллера.

<?php
namespace AppHttpControllers;

use AppHttpControllersController;
use AppLibraryServicesContractsCustomServiceInterface;

class TestController extends Controller
{
public function index(CustomServiceInterface $customServiceInstance)
{
echo $customServiceInstance->doSomethingUseful();
}
}

Как вы, возможно, догадались, $customServiceInstance должен быть экземпляром AppLibraryServicesDemoOne! Красота такого подхода заключается в том, что вы можете легко заменить реализацию DemoOne на другой класс.

Предположим, вы хотите использовать реализацию DemoTwo вместо DemoOne. В этом случае вам просто нужно внести следующие изменения в сервис-провайдер EnvatoCustomServiceProvider.php.

Найдите следующую строку:

use AppLibraryServicesDemoOne;

И замените ее на:

use AppLibraryServicesDemoTwo;

Аналогичным образом найдите это:

return new DemoOne();

Это должно быть заменено на:

return new DemoTwo();

Тот же подход можно использовать, если вы хотите заменить любую основную реализацию своей собственной. И это не только метод bind, который вы могли бы использовать для привязки сервиса к контейнеру; Контейнер Laravel предоставляет различные способы привязки. Пожалуйста, ознакомьтесь с официальной документацией Laravel для полной справки.

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

Давайте рассмотрим несколько примеров, требующих реализации метода boot.

Вы хотите добавить свой собственный инструмент проверки поля формы в Laravel.

public function boot()
{
Validator::extend(‘my_custom_validator’, function ($attribute, $value, $parameters, $validator) {
// validation logic goes here…
});
}

Если вы хотите зарегистрировать компоновщик отображений, то это идеальное место для этого! Фактически, можно сказать, что метод boot часто используется для добавления компоновщиков отображений!

public function boot()
{
View::composer(
‘demo’, ‘AppHttpViewComposersDemoComposer’
);
}

Конечно, вам нужно в первую очередь импортировать фасад IlluminateSupportFacadesView в своем сервис провайдере.

На этой же территории вы можете делиться данными и по нескольким представлениям!

public function boot()
{
View::share(‘key’, ‘value’);
}

Он также может использоваться для определения явных привязок к модели.

public function boot()
{
parent::boot();

Route::model(‘user’, AppUser::class);
}

Это было несколько примеров, чтобы продемонстрировать использование метода boot. Чем больше вы погружаетесь в Laravel, тем больше причин вы найдете для его реализации!

И вот мы дошли до конца этой статьи. Надеюсь, вам понравились темы, которые в ней обсуждались.

Заключение

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

После этого мы разработали свой собственный сервис провайдер, а во второй половине статьи мы рассмотрели несколько практических примеров.

Для тех из вас, кто только начинает работать с Laravel или хочет расширить свои знания, сайт или приложение с расширениями, у нас есть множество вещей, которые вы можете изучать на Envato Market.

Если у вас есть какие-либо вопросы или комментарии, то обязательно оставляйте их в обратной связи ниже!

Источник: code.tutsplus.com