サービスプロバイダーとは

Laravelはサービス毎に初期処理を定義し、実行する仕組みを持っています。
その仕組や、実際に初期処理の実装を行うクラスのことをサービスプロバイダーと言います。

では、実際のコードを追いながら、理解を深めたいと思います。


サービスプロバイダーの登録

サービスプロバイダーの登録箇所は config/app.php になります。
Laravelに Composerを使って、パッケージをインストールした事のある方は、
そのインストール手順に従って、app.phpにサービスプロバイダーを登録したことがあるかと思います。

<?php // config/app.php

// …

return [
    'providers' => [
        /*
         * ① Laravel Framework Service Providers...
         */
        Illuminate\Foundation\Providers\ArtisanServiceProvider::class,
        Illuminate\Auth\AuthServiceProvider::class,
        Illuminate\Broadcasting\BroadcastServiceProvider::class,
        ...
        Illuminate\Encryption\EncryptionServiceProvider::class,  // ④
        ...
        Illuminate\View\ViewServiceProvider::class,

        /*
         * ② Application Service Providers...
         */
        App\Providers\AppServiceProvider::class,
        App\Providers\EventServiceProvider::class, // ⑤
        App\Providers\RouteServiceProvider::class,

        /*
         * ③ Composerで追加したパッケージのサービスプロバイダー...
         */
        Barryvdh\LaravelIdeHelper\IdeHelperServiceProvider::class,
        Barryvdh\Debugbar\ServiceProvider::class,
    ],

    // ...
];

① Laravelのコアサービスのサービスプロバイダーです。
② アプリケーション固有のサービスプロバイダーです。
③ 自分で、Composerを使って追加したパッケージのサービスプロバイダーです。

ここに登録されているサービスプロバイダーは、Laravelの起動処理で全て呼び出されます。ルーティングのアクション内でサービスを利用する前に、必要な初期処理を行うのがサービスプロバイダーです。

次に、④EncryptionServiceProviderと、⑤EventServiceProviderのコードを見てみます。


サービスプロバイダーと registerメソッドの例

④EncryptionServiceProvider.phpのコードを見てみます。
暗号化サービスの初期処理です。

<?php // vendor/laravel/framework/src/illuminate/Encryption/EncryptionServiceProvider.php

namespace Illuminate\Encryption;

use RuntimeException;
use Illuminate\Support\ServiceProvider;

class EncryptionServiceProvider extends ServiceProvider // (a)
{
    /**
     * Register the service provider.
     *
     * @return void
     */
    public function register() // (b)
    {
        $this->app->singleton('encrypter', function ($app) { // (c)
            $config = $app->make('config')->get('app');

            $key = $config['key'];

            $cipher = $config['cipher'];

            if (Encrypter::supported($key, $cipher)) {
                return new Encrypter($key, $cipher);
            } elseif (McryptEncrypter::supported($key, $cipher)) {
                return new McryptEncrypter($key, $cipher);
            } else {
                throw new RuntimeException('No supported encrypter found. The cipher and / or key length are invalid.');
            }
        });
    }
}

(a) 全てのサービスプロバイダーは、Illuminate\Support\ServiceProviderクラスを拡張します。

(b) register()では、サービスコンテナへの登録を実装します。
それ以外の処理を行ってはいけません。
register() メソッドの定義は必須ですが、サービスコンテナへの登録が必要なければ、
空のメソッドで構いません。

(c) Encrypterのインスタンスをシングルトンとしてサービスコンテナに登録しています。
Encrypterは暗号化を行うクラスで、Laravel内で何度も使用されます。
使用する度にインスタンス化するのは効率が悪いので、サービスコンテナにシングルトンとして登録し、再利用しています。


サービスプロバイダーと bootメソッドの例

⑤EventServiceProvider.phpのコードを見てみます。
イベントサービスの初期処理です。

<?php // app/Providers/EventServiceProvider.php

namespace App\Providers;

use Illuminate\Contracts\Events\Dispatcher as DispatcherContract;
use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;

class EventServiceProvider extends ServiceProvider
{
    /**
     * The event listener mappings for the application.
     *
     * @var array
     */
    protected $listen = [ // (c)
        'App\Events\SomeEvent' => [
            'App\Listeners\EventListener',
        ],
    ];

    /**
     * Register any other events for your application.
     *
     * @param  \Illuminate\Contracts\Events\Dispatcher  $events
     * @return void
     */
    public function boot(DispatcherContract $events) // (a)
    {
        parent::boot($events);

        $events->listen('SomeEvent', 'SomeEventHandler');  // (b)
    }

    /*
     * register() は親クラスで定義されています↓
     * Illuminate\Foundation\Support\Providers\EventServiceProvider
     */
}

(a) boot() では、そのサービス固有の初期処理を自由に実装できます。
サービス固有の初期処理が必要なければ、bootメソッドが無くても構いません。

boot()は、他の全てのサービスプロバイダーのregister()の実行を終えてから呼び出されます。つまり、サービスコンテナに登録されている物、全てにアクセスできます。

(b) boot()内でイベントリスナーの登録を行っています。
※イベントリスナーの登録は、(c)の $listen配列を設定することでも可能です。
親クラスの boot() の中で $listenを参照して、(b)と同様の処理をしています。

(a) boot()では、依存をタイプヒントにて指定可能です。
ここでは、サービスコンテナにDispatcherContract(インターフェース名)で
登録されているインスタンスが自動生成されて渡されて来ます。


まとめ

サービスプロバイダーについて理解できました。

  • サービスプロバイダーはサービスの初期処理を定義するクラス。
  • サービスプロバイダーは config/app.php 内で Laravelに登録する。
  • register() メソッド内でサービスコンテナへの登録を実装する。
  • boot() メソッド内でサービス固有の初期処理を実装する。

公式サイト
http://laravel.com/docs/5.1/providers

サービスプロバイダーの作成方法はこちら

コメントを残す