パッケージ開発¶
はじめに¶
パッケージは、Laravelに機能を追加するための主要な方法です。パッケージは、Carbonのような日付を扱う素晴らしい方法から、SpatieのLaravel Media LibraryのようにEloquentモデルにファイルを関連付けることができるパッケージまで、さまざまなものがあります。
パッケージにはさまざまな種類があります。一部のパッケージはスタンドアロンであり、どのPHPフレームワークでも動作します。CarbonやPestはスタンドアロンパッケージの例です。これらのパッケージは、composer.jsonファイルで要求することでLaravelで使用できます。
一方、他のパッケージはLaravelでの使用を特に意図しています。これらのパッケージには、Laravelアプリケーションを強化するために意図されたルート、コントローラ、ビュー、設定が含まれる場合があります。このガイドでは、主にLaravel固有のパッケージの開発について説明します。
ファサードについての注意¶
Laravelアプリケーションを書く際、コントラクトを使用するかファサードを使用するかは、通常、テスト可能性の観点からほぼ同等であるため、問題になりません。しかし、パッケージを書く場合、パッケージは通常、Laravelのすべてのテストヘルパーにアクセスできません。パッケージが典型的なLaravelアプリケーション内にインストールされているかのようにパッケージのテストを書きたい場合は、Orchestral Testbenchパッケージを使用できます。
パッケージの発見¶
Laravelアプリケーションのbootstrap/providers.phpファイルには、Laravelによってロードされるべきサービスプロバイダのリストが含まれています。しかし、ユーザーが手動でサービスプロバイダをリストに追加する必要がないように、パッケージのcomposer.jsonファイルのextraセクションでプロバイダを定義することができます。これにより、Laravelによって自動的にロードされます。サービスプロバイダに加えて、登録したいファサードをリストすることもできます:
"extra": {
"laravel": {
"providers": [
"Barryvdh\\Debugbar\\ServiceProvider"
],
"aliases": {
"Debugbar": "Barryvdh\\Debugbar\\Facade"
}
}
},
パッケージが発見のために設定されると、Laravelはインストール時に自動的にそのサービスプロバイダとファサードを登録し、パッケージのユーザーに便利なインストール体験を提供します。
パッケージの発見をオプトアウトする¶
パッケージの利用者として、パッケージの発見を無効にしたい場合は、アプリケーションのcomposer.jsonファイルのextraセクションにパッケージ名をリストすることができます:
アプリケーションのdont-discoverディレクティブ内で*文字を使用して、すべてのパッケージの発見を無効にすることもできます:
サービスプロバイダ¶
サービスプロバイダは、パッケージとLaravelの接続点です。サービスプロバイダは、Laravelのサービスコンテナにバインドし、パッケージのリソース(ビュー、設定、言語ファイルなど)をロードする場所をLaravelに通知する役割を担います。
サービスプロバイダはIlluminate\Support\ServiceProviderクラスを拡張し、registerとbootの2つのメソッドを含みます。ベースのServiceProviderクラスはilluminate/support Composerパッケージにあり、独自のパッケージの依存関係に追加する必要があります。サービスプロバイダの構造と目的について詳しくは、そのドキュメントを参照してください。
リソース¶
設定¶
通常、パッケージの設定ファイルをアプリケーションのconfigディレクトリに公開する必要があります。これにより、パッケージのユーザーはデフォルトの設定オプションを簡単にオーバーライドできます。設定ファイルを公開できるようにするには、サービスプロバイダのbootメソッドからpublishesメソッドを呼び出します:
/**
* パッケージサービスのあらゆる初期化処理を行う。
*/
public function boot(): void
{
$this->publishes([
__DIR__.'/../config/courier.php' => config_path('courier.php'),
]);
}
これで、パッケージのユーザーがLaravelのvendor:publishコマンドを実行すると、ファイルが指定された公開場所にコピーされます。設定が公開されると、その値は他の設定ファイルと同様にアクセスできます:
$value = config('courier.option');
Warning
設定ファイルにクロージャを定義してはいけません。ユーザーがconfig:cache Artisanコマンドを実行すると、正しくシリアライズできません。
デフォルトのパッケージ設定¶
独自のパッケージ設定ファイルをアプリケーションの公開されたコピーとマージすることもできます。これにより、ユーザーは設定ファイルの公開されたコピーで実際にオーバーライドしたいオプションのみを定義できます。設定ファイルの値をマージするには、サービスプロバイダのregisterメソッド内でmergeConfigFromメソッドを使用します。
mergeConfigFromメソッドは、パッケージの設定ファイルへのパスを最初の引数として受け取り、アプリケーションの設定ファイルの名前を2番目の引数として受け取ります:
/**
* アプリケーションサービスの登録。
*/
public function register(): void
{
$this->mergeConfigFrom(
__DIR__.'/../config/courier.php', 'courier'
);
}
Warning
このメソッドは設定配列の最初のレベルのみをマージします。ユーザーが多次元設定配列を部分的に定義した場合、不足しているオプションはマージされません。
ルート¶
パッケージにルートが含まれている場合、loadRoutesFromメソッドを使用してそれらをロードできます。このメソッドは、アプリケーションのルートがキャッシュされているかどうかを自動的に判断し、ルートが既にキャッシュされている場合はルートファイルをロードしません:
/**
* パッケージサービスのあらゆる初期化処理を行う。
*/
public function boot(): void
{
$this->loadRoutesFrom(__DIR__.'/../routes/web.php');
}
マイグレーション¶
パッケージにデータベースマイグレーションが含まれている場合、publishesMigrationsメソッドを使用して、指定されたディレクトリまたはファイルにマイグレーションが含まれていることをLaravelに通知できます。Laravelがマイグレーションを公開すると、ファイル名内のタイムスタンプが現在の日付と時刻に自動的に更新されます:
/**
* パッケージサービスのあらゆる初期化処理を行う。
*/
public function boot(): void
{
$this->publishesMigrations([
__DIR__.'/../database/migrations' => database_path('migrations'),
]);
}
言語ファイル¶
パッケージに言語ファイルが含まれている場合、loadTranslationsFromメソッドを使用してLaravelにそれらをロードする方法を通知できます。たとえば、パッケージがcourierという名前の場合、サービスプロバイダのbootメソッドに次のように追加する必要があります:
/**
* パッケージサービスのあらゆる初期化処理を行う。
*/
public function boot(): void
{
$this->loadTranslationsFrom(__DIR__.'/../lang', 'courier');
}
パッケージの翻訳行は、package::file.line構文規則を使用して参照されます。したがって、courierパッケージのmessagesファイルからwelcome行を次のようにロードできます:
echo trans('courier::messages.welcome');
loadJsonTranslationsFromメソッドを使用して、パッケージのJSON翻訳ファイルを登録することもできます。このメソッドは、パッケージのJSON翻訳ファイルを含むディレクトリへのパスを受け取ります:
/**
* パッケージサービスのあらゆる初期化処理を行う。
*/
public function boot(): void
{
$this->loadJsonTranslationsFrom(__DIR__.'/../lang');
}
言語ファイルの公開¶
パッケージの言語ファイルをアプリケーションのlang/vendorディレクトリに公開したい場合は、サービスプロバイダのpublishesメソッドを使用できます。publishesメソッドは、パッケージパスとその希望する公開場所の配列を受け取ります。たとえば、courierパッケージの言語ファイルを公開するには、次のようにします:
/**
* パッケージサービスのあらゆる初期化処理を行う。
*/
public function boot(): void
{
$this->loadTranslationsFrom(__DIR__.'/../lang', 'courier');
$this->publishes([
__DIR__.'/../lang' => $this->app->langPath('vendor/courier'),
]);
}
これで、パッケージのユーザーがLaravelのvendor:publish Artisanコマンドを実行すると、パッケージの言語ファイルが指定された公開場所に公開されます。
ビュー¶
Laravelにパッケージのビューを登録するには、Laravelにビューがどこにあるかを教える必要があります。サービスプロバイダのloadViewsFromメソッドを使用してこれを行うことができます。loadViewsFromメソッドは、ビューテンプレートへのパスとパッケージの名前の2つの引数を受け取ります。例えば、パッケージの名前がcourierの場合、サービスプロバイダのbootメソッドに以下を追加します:
/**
* パッケージサービスのブートストラップ
*/
public function boot(): void
{
$this->loadViewsFrom(__DIR__.'/../resources/views', 'courier');
}
パッケージのビューは、package::view構文規則を使用して参照されます。したがって、サービスプロバイダでビューパスが登録されると、courierパッケージからdashboardビューを次のようにロードできます:
Route::get('/dashboard', function () {
return view('courier::dashboard');
});
パッケージビューのオーバーライド¶
loadViewsFromメソッドを使用すると、Laravelは実際にビューの2つの場所を登録します: アプリケーションのresources/views/vendorディレクトリと、指定したディレクトリです。したがって、courierパッケージを例にすると、Laravelはまず開発者によってresources/views/vendor/courierディレクトリにカスタムバージョンのビューが配置されているかどうかを確認します。そして、ビューがカスタマイズされていない場合、LaravelはloadViewsFromの呼び出しで指定したパッケージビューディレクトリを検索します。これにより、パッケージユーザーがパッケージのビューを簡単にカスタマイズ/オーバーライドできます。
ビューの公開¶
ビューをアプリケーションのresources/views/vendorディレクトリに公開できるようにしたい場合は、サービスプロバイダのpublishesメソッドを使用できます。publishesメソッドは、パッケージビューパスとその希望する公開場所の配列を受け取ります:
/**
* パッケージサービスのブートストラップ
*/
public function boot(): void
{
$this->loadViewsFrom(__DIR__.'/../resources/views', 'courier');
$this->publishes([
__DIR__.'/../resources/views' => resource_path('views/vendor/courier'),
]);
}
これで、パッケージのユーザーがLaravelのvendor:publish Artisanコマンドを実行すると、パッケージのビューが指定された公開場所にコピーされます。
ビューコンポーネント¶
Bladeコンポーネントを利用するパッケージを構築している場合、またはコンポーネントを非標準的なディレクトリに配置している場合、Laravelがコンポーネントを見つける場所を知るために、コンポーネントクラスとそのHTMLタグエイリアスを手動で登録する必要があります。通常、パッケージのサービスプロバイダのbootメソッドでコンポーネントを登録する必要があります:
use Illuminate\Support\Facades\Blade;
use VendorPackage\View\Components\AlertComponent;
/**
* パッケージサービスのブートストラップ
*/
public function boot(): void
{
Blade::component('package-alert', AlertComponent::class);
}
コンポーネントが登録されると、そのタグエイリアスを使用してレンダリングできます:
パッケージコンポーネントの自動読み込み¶
または、componentNamespaceメソッドを使用して、規約に従ってコンポーネントクラスを自動読み込みすることもできます。例えば、NightshadeパッケージにはCalendarとColorPickerコンポーネントがあり、これらはNightshade\Views\Components名前空間内にあります:
use Illuminate\Support\Facades\Blade;
/**
* パッケージサービスのブートストラップ
*/
public function boot(): void
{
Blade::componentNamespace('Nightshade\\Views\\Components', 'nightshade');
}
これにより、package-name::構文を使用してベンダー名前空間でパッケージコンポーネントを使用できます:
Bladeは、コンポーネント名をパスカルケースにして、このコンポーネントにリンクされたクラスを自動的に検出します。サブディレクトリも「ドット」記法でサポートされています。
匿名コンポーネント¶
パッケージに匿名コンポーネントが含まれている場合、それらはパッケージの「ビュー」ディレクトリのcomponentsディレクトリ内に配置する必要があります(loadViewsFromメソッドで指定されたとおり)。その後、パッケージのビュー名前空間をプレフィックスとして付けてレンダリングできます:
"About" Artisanコマンド¶
Laravelの組み込みabout Artisanコマンドは、アプリケーションの環境と設定の概要を提供します。パッケージはAboutCommandクラスを介してこのコマンドの出力に追加情報をプッシュできます。通常、この情報はパッケージサービスプロバイダのbootメソッドから追加されます:
use Illuminate\Foundation\Console\AboutCommand;
/**
* アプリケーションサービスのブートストラップ
*/
public function boot(): void
{
AboutCommand::add('My Package', fn () => ['Version' => '1.0.0']);
}
コマンド¶
パッケージのArtisanコマンドをLaravelに登録するには、commandsメソッドを使用できます。このメソッドはコマンドクラス名の配列を期待します。コマンドが登録されると、Artisan CLIを使用して実行できます:
use Courier\Console\Commands\InstallCommand;
use Courier\Console\Commands\NetworkCommand;
/**
* パッケージサービスのブートストラップ
*/
public function boot(): void
{
if ($this->app->runningInConsole()) {
$this->commands([
InstallCommand::class,
NetworkCommand::class,
]);
}
}
公開アセット¶
パッケージには、JavaScript、CSS、画像などのアセットが含まれている場合があります。これらのアセットをアプリケーションのpublicディレクトリに公開するには、サービスプロバイダのpublishesメソッドを使用します。この例では、関連するアセットのグループを簡単に公開できるように、publicアセットグループタグも追加します:
/**
* パッケージサービスのブートストラップ
*/
public function boot(): void
{
$this->publishes([
__DIR__.'/../public' => public_path('vendor/courier'),
], 'public');
}
これで、パッケージのユーザーがvendor:publishコマンドを実行すると、アセットが指定された公開場所にコピーされます。パッケージが更新されるたびにアセットを上書きする必要があるため、--forceフラグを使用できます:
ファイルグループの公開¶
パッケージのアセットとリソースのグループを個別に公開したい場合があります。例えば、パッケージの設定ファイルを公開させたいが、パッケージのアセットを公開させたくない場合があります。これを行うには、パッケージのサービスプロバイダからpublishesメソッドを呼び出す際に「タグ」を付けます。例えば、courierパッケージのサービスプロバイダのbootメソッドで、2つの公開グループ(courier-configとcourier-migrations)を定義します:
/**
* パッケージサービスのブートストラップ
*/
public function boot(): void
{
$this->publishes([
__DIR__.'/../config/package.php' => config_path('package.php')
], 'courier-config');
$this->publishesMigrations([
__DIR__.'/../database/migrations/' => database_path('migrations')
], 'courier-migrations');
}
これで、ユーザーはvendor:publishコマンドを実行する際にタグを参照することで、これらのグループを個別に公開できます: