Service providers là một thành phần cốt lõi, trung tâm của việc khởi tạo mọi ứng dụng trong Laravel.

Các bạn có thể tìm thấy một số default providers trong config/app.php

và trong vendor/laravel/framework/src/Illuminate/Support/DefaultProviders.php

Các bạn có thể thấy tên các classes được truyền vào mảng, hệ thống sẽ tự hiểu cần phải bind chúng vào Container (thay vì phải sử dung các function như bind, singleton, instance,… Nếu chưa rõ phần này thì xem lại bài 5 nhé).

1. Cách viết một provider

Tất cả các provider phải extend từ class \Illuminate\Support\ServiceProvider. Để cho tiện thì các bạn có thể chạy lệnh sau để tạo một provider

php artisan make:provider RiakServiceProvider

Hầu hết thì bên trong một provider sẽ có 2 methods là: register và boot.

<?php

namespace App\Providers;

use Illuminate\Support\ServiceProvider;

class AppServiceProvider extends ServiceProvider
{
    /**
     * Register any application services.
     */
    public function register(): void
    {
        //
    }

    /**
     * Bootstrap any application services.
     */
    public function boot(): void
    {
        //
    }
}

Bên trong method register, các bạn chỉ nên thực hiện nhiệm vụ bind vào Serivce Container (Ngoài ra thì đừng thực hiện việc gì khác trong này).

<?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'));
        });
    }
}

Để cho đơn giản hơn, khi muốn simple bind hoặc singleton thì các bạn chỉ cần khải báo vào 2 biến: $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,
    ];
}

Về method boot. Cơ bản thì method này được gọi sau khi toàn bộ providers được registered (điều này có nghĩa là bạn có thể truy xuất tới toàn bộ các service providers khác bên trong boot method). Bên trong method này, các bạn có thể register một “view composer” (giờ hiểu tạm thời thế đã, sau này chúng ta sẽ tìm hiểu view composer cụ thể là gì)

<?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 () {
            // ...
        });
    }
}

2. Đăng ký một provider (Register provider)

Đối với version 10.x thì các bạn thêm vào mảng $providers trong file config/app.php

'providers' => ServiceProvider::defaultProviders()->merge([
    // Other Service Providers
 
    App\Providers\ComposerServiceProvider::class,
])->toArray(),

Đối với bản 11.x, khi các bạn chạy lệnh “make:provider” thì hệ thống sẽ tự động register cho các bạn bằng cách thêm code vào file bootstrap/providers.php

<?php
 
// This file is automatically generated by Laravel...
 
return [
    App\Providers\AppServiceProvider::class,
    App\Providers\ComposerServiceProvider::class, 
];

3. Deferred Providers

Nếu như provider của các bạn đơn thuần chỉ là register binding vào trong Container, để tránh việc việc “đăng ký” (registration) này được thực hiện khi “chưa cần thiết”, các bạn có thể “hoãn lại” việc registration này cho tới khi cần thiết. Điều này sẽ làm tăng hiệu suất của hệ thông

Để làm điều này thì đơn giản là implement class \Illuminate\Contracts\Support\DeferrableProvider, khi báo method provides. Method này làm nhiệm vụ return về Service Container được registered bởi provider

<?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];
    }
}

Oke, Tạm thời như vậy. Về lý thuyết thì để binding thì chúng ta sẽ cần thông qua Providers. Mặc định các Providers sẽ được Laravel load khi khởi chạy hệ thống, tuy nhiên chúng ta sẽ có thể defer (nếu muốn) cho tới khi thực sự cần load provider nào đó.
Có thể kiến thức này hơi lằng nhằng lúc này, nhưng sau này khi chúng ta đi vào một ví dụ cụ thể, các bạn sẽ rõ hơn về những lý thuyết này.

Chúc các bạn chân cứng đá mềm trong quá trình học tập 🙂

By HNK

Leave a Reply

Your email address will not be published. Required fields are marked *