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
サービスプロバイダーの作成方法はこちら