0

Tự tạo Service Provider

1. Lí do nên tự viết Service Provider

Xin chào các bạn, mình đã trở lại đây. Trong bài viết này mình sẽ hướng dẫn mọi người tự tạo ra các provider để làm giảm nhẹ sức nặng của AppServiceProvider. Đối với 1 ứng dụng Laravel lớn khi mà bạn phải bootstrap quá nhiều thứ vàoAppServiceProvider. Điều này thực sự sẽ là thảm họa khi ai đó phải maintain cái project của bạn. Bạn cảm giác như file AppServiceProvider.php dài vô tận. Và bạn nghĩ mình phải tạo ra các service riêng.

Trong khuôn khổ bài viết này mình sẽ đặt ra tình huống ứng dựng có sử dụng Repository Design Partern để binding một Interface với một Implementation đối với mỗi Model để làm tầng trung gian giữa Controller với Model. Các bạn có thể xem chi tiết hơn về Repository Với Laravel ở bài viết này của mình. Viết Repository Sạch Hơn Trong Laravel Lúc này AppServiceProvider chúng ta phải đăng kí như sau


<?php

namespace App\Providers;


use App\Libraries\Countries\CountriesManager;

class AppServiceProvider extends ServiceProvider
{
    /**
     * Bootstrap any application services.
     *
     * @return void
     */
    public function boot()
    {
        $this->app->bind(UserRepositoryInterface::class, UserRepository::class);
    }
}

Nhưng sau đó ứng dụng của mình lại sử dụng Model event (Lại khoe cây nhà lá vườn trồng được) Khi đó function boot() ta lại phải thêm code để xử lí event model


<?php

namespace App\Providers;


use App\Libraries\Countries\CountriesManager;

class AppServiceProvider extends ServiceProvider
{
    /**
     * Bootstrap any application services.
     *
     * @return void
     */
    public function boot()
    {
        $this->app->bind(UserRepositoryInterface::class, UserRepository::class);
         Group::observe(GroupObserver::class);
    }
}

Rồi sau đó ứng dựng lại sử dụng Service để dùng chung một số hàm, chúng ta lại phải binding một Interface với một Implementation đối với từng service. Vậy là AppServiceProvider của chúng ta sẽ khá cồng kềnh. Vậy là chúng ta nghĩ đến việc tách ra thành từng service riêng : RepositoryServiceProvider, ModelEventServiceProvider . . .

2. Triển khai viết Service Provider

Ở đây mình sẽ triển khai viết Service Provider cho Repository. Bước đầu tiên là tạo 1 class có tên RepositoryServiceProvider.php nằm cùng cấp với thằng AppServiceProvider.php. Bên trong mình cũng khai báo sẵn 2 phương thức boot()register().

<?php

namespace App\Providers;

class RepositoryServiceProvider extends ServiceProvider
{
    /**
     * Indicates if loading of the provider is deferred.
     *
     * @var bool
     */
    protected $defer = true;
    
    /**
     * Bootstrap any application services.
     *
     * @return void
     */
    public function boot()
    {
        //
    }

    /**
     * Register Interface::Class with container.
     *
     * @return void
     */
    public function register()
    {
        $this->registerPermissionRepository();
    }

    /**
     * register PermissionRepository
     *
     * @return void
     */
    public function registerPermissionRepository()
    {
        $this->app->bind(PermissionRepositoryInterface::class, PermissionRepository::class);
    }
}

Thực ra nó ở đây mình chỉ clone từ thằng AppServiceProvider ra thôi mục đích để làm phân tán để giảm nhẹ sức nặng khi viết chung vào 1 class. Bức tiếp theo là phải đăng kí RepositoryServiceProvider vừa tạo trong config/app.php

    'providers' => [

        /*
         * Laravel Framework Service Providers...
         */
        ...
        App\Providers\RepositoryServiceProvider::class,

Do cấu hình được cache nên những thay đổi trong config/app.php không được tải lại nên nó thiếu RepositoryServiceProvider.php của mình. Nên để chắc chắc nó đãn được binding vào app() chúng ra phải chạy 2 lệnh sau

php artisan config:clear
php artisan cache:clear

Vậy là chúng ta đã tạo thành công 1 ServiceProvider.

Ở đây mình muốn giải thích thêm một chút về thuộc tính protected $defer trong RepositoryServiceProvider. Đầu tiên ứng dụng sẽ check xem biến $defer là true hay false. Nếu là false thì thực hiện ngay việc binding thông qua việc chạy hàm register. Nếu $defer là true thì không chạy hàm register, thay vào đó sẽ lưu lại thông tin về việc service provider đó sẽ trả về service gì thông qua kết quả của hàm provides. Việc load các service một cách defer như vậy sẽ giúp cái thiện performance cho application của bạn, khi mà những service chỉ được load khi mà nó là cần thiết.

3. Tổng kết

Vậy là mình đã giới thiệu các bạn tại sao nên tách riêng ra thành các provider và thực hiện việc tự tạo RepositoryServiceProvider. Việc tự tạo cách ServiceProvider giúp code của bạn sáng sủa hơn, đồng làm làm giảm gánh nặng cho AppServiceProvider. Đồng thời mọi người nhìn vào code của bạn cũng nhìn bạn với con mắt master hơn 😄

4. Tham khảo

  1. Service Provider via Viblo
  2. Service Provider via Document

All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí