#はじめに
サービスプロバイダーは、Laravel アプリケーションの起動処理の中心です。あなたのアプリケーションだけでなく、Laravel のコアサービスもすべてサービスプロバイダーを通じて起動されます。
「起動処理」とは何を指すのでしょうか?一般的には、サービスコンテナへのバインディング登録、イベントリスナー、ミドルウェア、ルートの登録などを含む「登録処理」を意味します。サービスプロバイダーはアプリケーションの設定を行う中心的な場所です。
Laravel に含まれる config/app.php ファイルを開くと、providers 配列が見つかります。ここにはアプリケーションで読み込まれるすべてのサービスプロバイダークラスがリストされています。デフォルトでは、Laravel のコアサービスプロバイダーがこの配列に含まれており、メール、キュー、キャッシュなどのコアコンポーネントを起動します。多くのプロバイダーは「遅延」プロバイダーで、すべてのリクエストで読み込まれるのではなく、実際に必要になったときだけ読み込まれます。
この概要では、独自のサービスプロバイダーの作成方法と、Laravel アプリケーションへの登録方法を学びます。
Laravel がリクエストをどのように処理し内部で動作しているか詳しく知りたい場合は、Laravel の リクエストライフサイクル のドキュメントを参照してください。
#サービスプロバイダーの作成
すべてのサービスプロバイダーは Illuminate\Support\ServiceProvider クラスを継承します。ほとんどのサービスプロバイダーは register メソッドと boot メソッドを持ちます。register メソッド内では、サービスコンテナ へのバインディング登録のみを行うべきです。イベントリスナーやルート、その他の機能を register メソッド内で登録しようとしてはいけません。
Artisan CLI の make:provider コマンドで新しいプロバイダーを生成できます。
php artisan make:provider RiakServiceProvider
#register メソッド
前述のとおり、register メソッド内ではサービスコンテナに対してのみバインドを行うべきです。register メソッド内でイベントリスナーやルート、その他の機能を登録しようとしてはいけません。そうしないと、まだロードされていないサービスプロバイダによって提供されるサービスを誤って使用してしまう可能性があります。
基本的なサービスプロバイダーを見てみましょう。サービスプロバイダーのメソッド内では常に $app プロパティを使ってサービスコンテナにアクセスできます。
<?php
namespace App\Providers;
use App\Services\Riak\Connection;
use Illuminate\Contracts\Foundation\Application;
use Illuminate\Support\ServiceProvider;
class RiakServiceProvider extends ServiceProvider
{
/**
* アプリケーションサービスを登録します。
*/
public function register(): void
{
$this->app->singleton(Connection::class, function (Application $app) {
return new Connection(config('riak'));
});
}
}
このサービスプロバイダーは register メソッドのみを定義し、その中で App\Services\Riak\Connection の実装をサービスコンテナに登録しています。Laravel のサービスコンテナにまだ慣れていない場合は、ドキュメントを参照してください。
#bindings と singletons プロパティ
多くの単純なバインディングを登録する場合は、個別に登録する代わりに 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
{
/**
* 登録すべきすべてのコンテナバインディング。
*
* @var array
*/
public $bindings = [
ServerProvider::class => DigitalOceanServerProvider::class,
];
/**
* 登録すべきすべてのコンテナシングルトン。
*
* @var array
*/
public $singletons = [
DowntimeNotifier::class => PingdomDowntimeNotifier::class,
ServerProvider::class => ServerToolsProvider::class,
];
}
#boot メソッド
サービスプロバイダー内で ビューコンポーザー を登録したい場合は、boot メソッド内で行います。このメソッドは他のすべてのサービスプロバイダーが登録された後に呼ばれるため、フレームワークによって登録されたすべてのサービスにアクセスできます。
<?php
namespace App\Providers;
use Illuminate\Support\Facades\View;
use Illuminate\Support\ServiceProvider;
class ComposerServiceProvider extends ServiceProvider
{
/**
* アプリケーションサービスを起動します。
*/
public function boot(): void
{
View::composer('view', function () {
// ...
});
}
}
#boot メソッドの依存性注入
サービスプロバイダーの boot メソッドには依存性をタイプヒントできます。サービスコンテナ が必要な依存性を自動的に注入します。
use Illuminate\Contracts\Routing\ResponseFactory;
/**
* アプリケーションサービスを起動します。
*/
public function boot(ResponseFactory $response): void
{
$response->macro('serialized', function (mixed $value) {
// ...
});
}
#プロバイダーの登録
すべてのサービスプロバイダーは config/app.php の設定ファイルで登録されます。このファイルの providers 配列にサービスプロバイダーのクラス名をリストします。デフォルトでは、Laravel のコアサービスプロバイダーが登録されており、メール、キュー、キャッシュなどのコアコンポーネントを起動します。
プロバイダーを登録するには、配列に追加します。
'providers' => ServiceProvider::defaultProviders()->merge([
// その他のサービスプロバイダー
App\Providers\ComposerServiceProvider::class,
])->toArray(),
#遅延プロバイダー
サービスプロバイダがサービスコンテナにバインディングをのみ登録している場合、登録されたバインディングのいずれかが実際に必要になるまでその登録を遅延させることができます。これにより、そのプロバイダが毎回のリクエストでファイルシステムから読み込まれなくなるため、アプリケーションのパフォーマンスが向上します。
Laravel は遅延サービスプロバイダーが提供するすべてのサービスと、そのプロバイラーのクラス名のリストをコンパイルして保存します。そして、これらのサービスのいずれかを解決しようとしたときにのみ、該当するサービスプロバイダーを読み込みます。
プロバイダーの遅延ロードを有効にするには、\Illuminate\Contracts\Support\DeferrableProvider インターフェイスを実装し、provides メソッドを定義します。provides メソッドはプロバイダーが登録するサービスコンテナのバインディングを返します。
<?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
{
/**
* アプリケーションサービスを登録します。
*/
public function register(): void
{
$this->app->singleton(Connection::class, function (Application $app) {
return new Connection($app['config']['riak']);
});
}
/**
* プロバイダーが提供するサービスを取得します。
*
* @return array<int, string>
*/
public function provides(): array
{
return [Connection::class];
}
}