Статьи

Как зарегистрироваться и использовать сервис-провайдеров Laravel

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

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

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

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

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

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

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

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

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

1
2
3
4
5
6
7
Class SomeClass
{
    public function __construct(FooBar $foobarObject)
    {
        // use $foobarObject object
    }
}

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

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

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

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

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

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
‘providers’ => [
  
        /*
         * Laravel Framework Service Providers…
         */
        Illuminate\Auth\AuthServiceProvider::class,
        Illuminate\Broadcasting\BroadcastServiceProvider::class,
        Illuminate\Bus\BusServiceProvider::class,
        Illuminate\Cache\CacheServiceProvider::class,
        Illuminate\Foundation\Providers\ConsoleSupportServiceProvider::class,
        Illuminate\Cookie\CookieServiceProvider::class,
        Illuminate\Database\DatabaseServiceProvider::class,
        Illuminate\Encryption\EncryptionServiceProvider::class,
        Illuminate\Filesystem\FilesystemServiceProvider::class,
        Illuminate\Foundation\Providers\FoundationServiceProvider::class,
        Illuminate\Hashing\HashServiceProvider::class,
        Illuminate\Mail\MailServiceProvider::class,
        Illuminate\Notifications\NotificationServiceProvider::class,
        Illuminate\Pagination\PaginationServiceProvider::class,
        Illuminate\Pipeline\PipelineServiceProvider::class,
        Illuminate\Queue\QueueServiceProvider::class,
        Illuminate\Redis\RedisServiceProvider::class,
        Illuminate\Auth\Passwords\PasswordResetServiceProvider::class,
        Illuminate\Session\SessionServiceProvider::class,
        Illuminate\Translation\TranslationServiceProvider::class,
        Illuminate\Validation\ValidationServiceProvider::class,
        Illuminate\View\ViewServiceProvider::class,
  
        /*
         * Package Service Providers…
         */
        Laravel\Tinker\TinkerServiceProvider::class,
  
        /*
         * Application Service Providers…
         */
        App\Providers\AppServiceProvider::class,
        App\Providers\AuthServiceProvider::class,
        // App\Providers\BroadcastServiceProvider::class,
        App\Providers\EventServiceProvider::class,
        App\Providers\RouteServiceProvider::class,
],

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

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

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

01
02
03
04
05
06
07
08
09
10
11
12
13
14
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 проходит через метод регистрации всех поставщиков услуг и заполняет контейнер услуг! И, как мы упоминали ранее, он выбирает список поставщиков услуг из файла config/app.php .

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

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

1
2
$php artisan make:provider EnvatoCustomServiceProvider
Provider created successfully.

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

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<?php
namespace App\Providers;
  
use Illuminate\Support\ServiceProvider;
  
class EnvatoCustomServiceProvider extends ServiceProvider
{
    /**
     * Bootstrap the application services.
     *
     * @return void
     */
    public function boot()
    {
        //
    }
  
    /**
     * Register the application services.
     *
     * @return void
     */
    public function register()
    {
        //
    }
}

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

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

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

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

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
‘providers’ => [
  
        /*
         * Laravel Framework Service Providers…
         */
        Illuminate\Auth\AuthServiceProvider::class,
        Illuminate\Broadcasting\BroadcastServiceProvider::class,
        Illuminate\Bus\BusServiceProvider::class,
        Illuminate\Cache\CacheServiceProvider::class,
        Illuminate\Foundation\Providers\ConsoleSupportServiceProvider::class,
        Illuminate\Cookie\CookieServiceProvider::class,
        Illuminate\Database\DatabaseServiceProvider::class,
        Illuminate\Encryption\EncryptionServiceProvider::class,
        Illuminate\Filesystem\FilesystemServiceProvider::class,
        Illuminate\Foundation\Providers\FoundationServiceProvider::class,
        Illuminate\Hashing\HashServiceProvider::class,
        Illuminate\Mail\MailServiceProvider::class,
        Illuminate\Notifications\NotificationServiceProvider::class,
        Illuminate\Pagination\PaginationServiceProvider::class,
        Illuminate\Pipeline\PipelineServiceProvider::class,
        Illuminate\Queue\QueueServiceProvider::class,
        Illuminate\Redis\RedisServiceProvider::class,
        Illuminate\Auth\Passwords\PasswordResetServiceProvider::class,
        Illuminate\Session\SessionServiceProvider::class,
        Illuminate\Translation\TranslationServiceProvider::class,
        Illuminate\Validation\ValidationServiceProvider::class,
        Illuminate\View\ViewServiceProvider::class,
  
        /*
         * Package Service Providers…
         */
        Laravel\Tinker\TinkerServiceProvider::class,
  
        /*
         * Application Service Providers…
         */
        App\Providers\AppServiceProvider::class,
        App\Providers\AuthServiceProvider::class,
        // App\Providers\BroadcastServiceProvider::class,
        App\Providers\EventServiceProvider::class,
        App\Providers\RouteServiceProvider::class,
        App\Providers\EnvatoCustomServiceProvider::class,
],

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

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

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
<?php
namespace App\Providers;
  
use Illuminate\Support\ServiceProvider;
use App\Library\Services\DemoOne;
  
class EnvatoCustomServiceProvider extends ServiceProvider
{
    public function boot()
    {
    }
  
    public function register()
    {
        $this->app->bind(‘App\Library\Services\DemoOne’, function ($app) {
          return new DemoOne();
        });
    }
}

Здесь следует отметить две важные вещи:

  • Мы импортировали App\Library\Services\DemoOne чтобы мы могли его использовать. Класс DemoOne еще не создан, но мы сделаем это через минуту.
  • В методе register мы использовали метод bind контейнера службы, чтобы добавить привязку контейнера службы. Таким образом, всякий раз, когда необходимо App\Library\Services\DemoOne зависимость App\Library\Services\DemoOne , она вызывает функцию закрытия, а также создает и возвращает объект App\Library\Services\DemoOne .

Так что вам просто нужно создать файл app/Library/Services/DemoOne.php чтобы это работало.

01
02
03
04
05
06
07
08
09
10
<?php
namespace App\Library\Services;
  
class DemoOne
{
    public function doSomethingUseful()
    {
      return ‘Output from DemoOne’;
    }
}

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

01
02
03
04
05
06
07
08
09
10
11
12
13
<?php
namespace App\Http\Controllers;
  
use App\Http\Controllers\Controller;
use App\Library\Services\DemoOne;
  
class TestController extends Controller
{
    public function index(DemoOne $customServiceInstance)
    {
        echo $customServiceInstance->doSomethingUseful();
    }
}

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

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

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

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

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

1
2
3
4
5
6
7
8
<?php
// app/Library/Services/Contracts/CustomServiceInterface.php
namespace App\Library\Services\Contracts;
  
Interface CustomServiceInterface
{
    public function doSomethingUseful();
}

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

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

01
02
03
04
05
06
07
08
09
10
11
12
13
<?php
// app/Library/Services/DemoOne.php
namespace App\Library\Services;
  
use App\Library\Services\Contracts\CustomServiceInterface;
  
class DemoOne implements CustomServiceInterface
{
    public function doSomethingUseful()
    {
      return ‘Output from DemoOne’;
    }
}

Аналогично, DemoTwo в app/Library/Services/DemoTwo.php .

01
02
03
04
05
06
07
08
09
10
11
12
13
<?php
// app/Library/Services/DemoTwo.php
namespace App\Library\Services;
  
use App\Library\Services\Contracts\CustomServiceInterface;
  
class DemoTwo implements CustomServiceInterface
{
    public function doSomethingUseful()
    {
      return ‘Output from DemoTwo’;
    }
}

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

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
<?php
namespace App\Providers;
  
use Illuminate\Support\ServiceProvider;
use App\Library\Services\DemoOne;
  
class EnvatoCustomServiceProvider extends ServiceProvider
{
    public function boot()
    {
    }
  
    public function register()
    {
        $this->app->bind(‘App\Library\Services\Contracts\CustomServiceInterface’, function ($app) {
          return new DemoOne();
        });
    }
}

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

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

01
02
03
04
05
06
07
08
09
10
11
12
13
<?php
namespace App\Http\Controllers;
  
use App\Http\Controllers\Controller;
use App\Library\Services\Contracts\CustomServiceInterface;
  
class TestController extends Controller
{
    public function index(CustomServiceInterface $customServiceInstance)
    {
        echo $customServiceInstance->doSomethingUseful();
    }
}

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

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

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

1
use App\Library\Services\DemoOne;

И заменить его на:

1
use App\Library\Services\DemoTwo;

Точно так же найдите это:

1
return new DemoOne();

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

1
return new DemoTwo();

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

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

Давайте посмотрим на пару примеров, которые требуют реализации метода загрузки.

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

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

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

1
2
3
4
5
6
public function boot()
{
    View::composer(
        ‘demo’, ‘App\Http\ViewComposers\DemoComposer’
    );
}

Конечно, вы хотите импортировать фасад Illuminate\Support\Facades\View у своего поставщика услуг.

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

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

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

1
2
3
4
5
6
public function boot()
{
    parent::boot();
  
    Route::model(‘user’, App\User::class);
}

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

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

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

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

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

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