イントロダクション
サービスプロバイダはLaravelアプリケーション全体における起動処理初期の心臓部です。皆さんのアプリケーションと同じく、Laravelのコアサービス全部もサービスプロバイダを利用して初期起動処理を行っています。
ところで「初期起動処理」とは何を意味しているのでしょうか? サービスコンテナの結合やイベントリスナ、フィルター、それにルートなどを登録することを一般的に意味しています。サービスプロバイダはアプリケーション設定の中心部です。
Laravelに含まれているconfig/app.php
ファイルを開けば、providers
配列が見つかるでしょう。そこにある全サービスプロバイダクラスが、アプリケーションのためにロードされます。もちろんほとんどのプロバイダは、全てのリクエストで必ずロードされるとは限らず、そのプロバイダが提供するサービスが必要なときにのみロードされる「遅延」プロバイダです。
この概論ではサービスプロバイダの書き方と、Laravelアプリケーションに登録する方法を学びます。
サービスプロバイダの記述
全てのサービスプロバイダは、Illuminate\Support\ServiceProvider
クラスを拡張します。この抽象クラスは皆さんのプロバイダの中に、最低でもregister
メソッドだけは定義することを求めています。register
メソッドの中ではサービスコンテナへの登録だけを行わなくてはなりません。他のイベントリスナやルート、その他の機能の一部でも、register
メソッドの中で登録しようとしてはいけません。
make:provider
Artisanコマンドラインにより、簡単に新しいプロバイダが生成できます。
php artisan make:provider RiakServiceProvider
Registerメソッド
既に説明した通り、register
メソッドの中ではサービスコンテナに何かを結合することだけを行わなければなりません。イベントリスナやルート、その他のどんな作業もregister
メソッドの中では決して行ってはいけません。これを守らないと、サービスプロバイダがまだロードしていないサービスを意図せず使ってしまう羽目になるでしょう。
では、基本的なプロバイダを見てみましょう。
<?php
namespace App\Providers;
use Riak\Connection;
use Illuminate\Support\ServiceProvider;
class RiakServiceProvider extends ServiceProvider
{
/**
* コンテナへの結合登録
*
* @return void
*/
public function register()
{
$this->app->singleton(Connection::class, function ($app) {
return new Connection(config('riak'));
});
}
}
このサービスプロバイダではregister
メソッドだけが定義されています。そして、サービスコンテナにRiak\Connection
の実装を定義しています。サービスコンテナがどのように動作するのかまだ理解できていなければ、ドキュメントで調べてください。
Bootメソッド
ではイベントリスナをサービスプロバイダで登録する必要がある場合は、どうすればよいのでしょうか? boot
メソッドの中で行ってください。このメソッドは、他の全サービスプロバイダが登録し終えてから呼び出されます。つまりフレームワークにより登録された、他のサービス全てにアクセスできるのです。
<?php
namespace App\Providers;
use Illuminate\Contracts\Events\Dispatcher as DispatcherContract;
use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;
class EventServiceProvider extends ServiceProvider
{
// 他のサービスプロバイダプロパティ…
/**
* アプリケーションに対するその他のイベント登録
*
* @param \Illuminate\Contracts\Events\Dispatcher $events
* @return void
*/
public function boot(DispatcherContract $events)
{
parent::boot($events);
view()->composer('view', function () {
//
});
}
}
bootメソッドの依存注入
boot
メソッドでは依存をタイプヒントにより指定可能です。サービスコンテナは必要な依存を自動的に注入してくれます。
use Illuminate\Contracts\Routing\ResponseFactory;
public function boot(ResponseFactory $factory)
{
$factory->macro('caps', function ($value) {
//
});
}
プロバイダの登録
全てのサービスプロバイダは、config/app.php
設定ファイルで登録されています。このファイルには起動するサービスプロバイダの名前をリストしてあるproviders
配列が含まれています。この配列にはデフォルトとして、コアのサービスプロバイダが登録されています。これらのプロバイダは、メール送信、キュー、キャッシュなどのLaravelコアコンポーネントの初期起動を行っています。
プロバイダを登録するには、この配列に追加するだけです。
'providers' => [
// 他のサービスプロバイダ
App\Providers\AppServiceProvider::class,
],
遅延プロバイダ
もし皆さんのプロバイダが、サービスコンテナへコンテナ結合を登録するだけであるなら、その結合が実際に必要になるまで登録を遅らせる方が良いでしょう。こうしたプロバイダのローディングを遅らせるのは、リクエストがあるたびにファイルシステムからロードされなくなるため、アプリケーションのパフォーマンスを向上させます。
プロバイダを遅延ロードするには、defer
プロパティーにtrue
をセットし、provides
メソッドを定義します。provides
メソッドはそのプロバイダで登録するサービスコンテナ結合名を返します。
<?php
namespace App\Providers;
use Riak\Connection;
use Illuminate\Support\ServiceProvider;
class RiakServiceProvider extends ServiceProvider
{
/**
* プロバイダのローディングを遅延させるフラグ
*
* @var bool
*/
protected $defer = true;
/**
* サービスプロバーダーの登録
*
* @return void
*/
public function register()
{
$this->app->singleton(Connection::class, function ($app) {
return new Connection($app['config']['riak']);
});
}
/**
* このプロバイダにより提供されるサービス
*
* @return array
*/
public function provides()
{
return [Connection::class];
}
}
Laravelは遅延サービスプロバイダが提示した全サービスのリストをコンパイルし、サービスプロバイダのクラス名と共に保存します。その後、登録されているサービスのどれか一つを依存解決する必要が起きた時のみ、Laravelはそのサービスプロバイダをロードします。