#はじめに
パッケージはLaravelに機能を追加する主要な方法です。パッケージは、Carbonのような日付操作の便利なツールから、SpatieのLaravel Media LibraryのようにEloquentモデルにファイルを関連付けるパッケージまで様々です。
パッケージには種類があります。スタンドアロンのパッケージは、どのPHPフレームワークでも動作します。CarbonやPHPUnitはスタンドアロンの例です。これらのパッケージは、composer.jsonに追加することでLaravelでも利用できます。
一方で、Laravel専用に設計されたパッケージもあります。これらはLaravelアプリケーションを拡張するために、ルート、コントローラー、ビュー、設定などを含みます。このガイドは主にLaravel専用パッケージの開発について扱います。
#ファサードについての注意
Laravelアプリケーションを書く際は、契約(contracts)かファサードのどちらを使ってもテストのしやすさはほぼ同じです。しかしパッケージを書く場合、Laravelのテストヘルパー全てにアクセスできないことが多いです。パッケージを通常のLaravelアプリ内にインストールしたかのようにテストを書きたい場合は、Orchestral Testbenchパッケージを使えます。
#パッケージディスカバリー
Laravelアプリケーションのconfig/app.php設定ファイルのprovidersオプションは、Laravelが読み込むサービスプロバイダーのリストを定義します。パッケージをインストールした際に、通常はサービスプロバイダーをこのリストに含めたいです。ユーザーに手動で追加させる代わりに、パッケージのcomposer.jsonのextraセクションでプロバイダーを定義できます。サービスプロバイダーに加え、登録したいファサードもリストに含められます:
"extra": {
"laravel": {
"providers": [
"Barryvdh\\Debugbar\\ServiceProvider"
],
"aliases": {
"Debugbar": "Barryvdh\\Debugbar\\Facade"
}
}
},
パッケージがディスカバリー用に設定されると、Laravelはインストール時に自動的にサービスプロバイダーとファサードを登録し、パッケージ利用者に便利なインストール体験を提供します。
#パッケージディスカバリーの無効化
パッケージの利用者が特定のパッケージのディスカバリーを無効にしたい場合、アプリケーションのcomposer.jsonのextraセクションにパッケージ名を記載できます:
"extra": {
"laravel": {
"dont-discover": [
"barryvdh/laravel-debugbar"
]
}
},
アプリケーションのdont-discoverディレクティブに*を使うと、すべてのパッケージのディスカバリーを無効にできます:
"extra": {
"laravel": {
"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');
設定ファイル内にクロージャを定義しないでください。config:cache Artisanコマンド実行時に正しくシリアライズできません。
#デフォルトのパッケージ設定
パッケージの設定ファイルをアプリケーションの公開済み設定とマージすることもできます。これにより利用者は公開済み設定ファイルで上書きしたいオプションだけを定義できます。設定値をマージするには、サービスプロバイダーのregisterメソッド内でmergeConfigFromメソッドを使います。
mergeConfigFromメソッドは、第一引数にパッケージの設定ファイルのパス、第二引数にアプリケーションの設定名を受け取ります:
/**
* アプリケーションのサービスを登録します。
*/
public function register(): void
{
$this->mergeConfigFrom(
__DIR__.'/../config/courier.php', 'courier'
);
}
このメソッドは設定配列の第一階層のみマージします。多次元配列の一部だけを利用者が定義した場合、未定義のオプションはマージされません。
#ルート
パッケージにルートが含まれる場合、loadRoutesFromメソッドで読み込めます。このメソッドはアプリケーションのルートがキャッシュされているか自動判別し、キャッシュ済みならルートファイルを読み込みません:
/**
* パッケージのサービスを起動します。
*/
public function boot(): void
{
$this->loadRoutesFrom(__DIR__.'/../routes/web.php');
}
#マイグレーション
パッケージにデータベースマイグレーションが含まれている場合、loadMigrationsFrom メソッドを使って Laravel にそれらの読み込み方法を知らせることができます。loadMigrationsFrom はパッケージのマイグレーションへのパスを唯一の引数として受け取ります:
/**
* パッケージのサービスを起動します。
*/
public function boot(): void
{
$this->loadMigrationsFrom(__DIR__.'/../database/migrations');
}
パッケージのマイグレーションが登録されると、php artisan migrateコマンド実行時に自動で実行されます。アプリケーションのdatabase/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');
パッケージのJSON翻訳ファイルはloadJsonTranslationsFromメソッドで登録できます。このメソッドは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 パッケージを例に取ると、まず開発者が resources/views/vendor/courier ディレクトリにカスタム版のビューを置いていないか Laravel が確認します。ビューがカスタマイズされていない場合は、loadViewsFrom の呼び出しで指定したパッケージのビュー用ディレクトリを検索します。これにより、パッケージ利用者があなたのパッケージのビューを簡単にカスタマイズ/オーバーライドできるようになります。
#ビューの公開
ビューをアプリケーションのresources/views/vendorディレクトリに公開可能にしたい場合、サービスプロバイダーのpublishesメソッドを使います。publishesはパッケージビューのパスと公開先の配列を受け取ります:
/**
* Bootstrap the package services.
*/
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コンポーネントを使うパッケージや、非標準ディレクトリにコンポーネントを置く場合は、コンポーネントクラスとHTMLタグのエイリアスを手動で登録し、Laravelに場所を教える必要があります。通常はパッケージのサービスプロバイダーのbootメソッドで登録します:
use Illuminate\Support\Facades\Blade;
use VendorPackage\View\Components\AlertComponent;
/**
* パッケージのサービスを起動します。
*/
public function boot(): void
{
Blade::component('package-alert', AlertComponent::class);
}
登録後はタグエイリアスでコンポーネントをレンダリングできます:
<x-package-alert/>
#パッケージコンポーネントのオートロード
またはcomponentNamespaceメソッドを使い、規約に従ってコンポーネントクラスをオートロードできます。例えばNightshadeパッケージにCalendarやColorPickerコンポーネントがNightshade\Views\Components名前空間にある場合:
use Illuminate\Support\Facades\Blade;
/**
* パッケージのサービスを起動します。
*/
public function boot(): void
{
Blade::componentNamespace('Nightshade\\Views\\Components', 'nightshade');
}
これによりpackage-name::構文でベンダー名前空間付きのパッケージコンポーネントを使えます:
<x-nightshade::calendar />
<x-nightshade::color-picker />
Bladeはコンポーネント名をパスカルケースに変換してクラスを自動検出します。サブディレクトリもドット表記で対応します。
#匿名コンポーネント
パッケージに匿名コンポーネントがある場合、パッケージの「ビュー」ディレクトリ内のcomponentsディレクトリに配置する必要があります(loadViewsFromメソッドで指定した場所)。その後、パッケージのビュー名前空間をプレフィックスにしてレンダリングできます:
<x-courier::alert />
#「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フラグを使えます。
php artisan vendor:publish --tag=public --force
#ファイルグループの公開
パッケージのアセットやリソースをグループごとに分けて公開したい場合があります。例えば設定ファイルだけ公開し、アセットは公開しないようにできます。これはサービスプロバイダーのpublishesメソッドでタグ付けすることで実現します。例としてcourierパッケージのcourier-configとcourier-migrationsという2つの公開グループをbootメソッドで定義します:
/**
* パッケージのサービスを起動します。
*/
public function boot(): void
{
$this->publishes([
__DIR__.'/../config/package.php' => config_path('package.php')
], 'courier-config');
$this->publishes([
__DIR__.'/../database/migrations/' => database_path('migrations')
], 'courier-migrations');
}
これで利用者はvendor:publishコマンド実行時にタグを指定して、これらのグループを個別に公開できます:
php artisan vendor:publish --tag=courier-config