パッケージ開発
導入
パッケージは、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`セクションにパッケージ名をリストできます。
"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パッケージにあり、独自の package の依存関係に追加する必要があります。サービスプロバイダーの構造と目的の詳細については、ドキュメントを参照してください。
リソース
設定
通常、パッケージの設定ファイルをアプリケーションの`config`ディレクトリに公開する必要があります。これにより、パッケージのユーザーはデフォルトの設定オプションを簡単にオーバーライドできます。設定ファイルを公開できるようにするには、サービスプロバイダーの`boot`メソッドから`publishes`メソッドを呼び出します。
/** * Bootstrap any package services. */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`メソッドは、最初のパラメーターとしてパッケージの設定ファイルへのパス、2番目のパラメーターとしてアプリケーションの設定ファイルのコピー名を受け取ります。
/** * Register any application services. */public function register(): void{ $this->mergeConfigFrom( __DIR__.'/../config/courier.php', 'courier' );}
このメソッドは、設定配列の最初のレベルのみをマージします。ユーザーが多次元設定配列を部分的に定義した場合、不足しているオプションはマージされません。
ルート
パッケージにルートが含まれている場合は、`loadRoutesFrom`メソッドを使用してロードできます。このメソッドは、アプリケーションのルートがキャッシュされているかどうかを自動的に判断し、ルートが既にキャッシュされている場合はルートファイルを読み込みません。
/** * Bootstrap any package services. */public function boot(): void{ $this->loadRoutesFrom(__DIR__.'/../routes/web.php');}
マイグレーション
パッケージにデータベースマイグレーションが含まれている場合は、`publishesMigrations`メソッドを使用して、指定されたディレクトリまたはファイルにマイグレーションが含まれていることをLaravelに通知できます。Laravelがマイグレーションを公開すると、ファイル名内のタイムスタンプが現在の日時を反映するように自動的に更新されます。
/** * Bootstrap any package services. */public function boot(): void{ $this->publishesMigrations([ __DIR__.'/../database/migrations' => database_path('migrations'), ]);}
言語ファイル
パッケージに言語ファイルが含まれている場合は、`loadTranslationsFrom`メソッドを使用して、それらをロードする方法をLaravelに通知できます。たとえば、パッケージ名が`courier`の場合、サービスプロバイダーの`boot`メソッドに以下を追加する必要があります。
/** * Bootstrap any package services. */public function boot(): void{ $this->loadTranslationsFrom(__DIR__.'/../lang', 'courier');}
パッケージの翻訳行は、`package::file.line`構文規則を使用して参照されます。そのため、`messages`ファイルから`courier`パッケージの`welcome`行を次のようにロードできます。
echo trans('courier::messages.welcome');
`loadJsonTranslationsFrom`メソッドを使用して、パッケージのJSON翻訳ファイルを登録できます。このメソッドは、パッケージのJSON翻訳ファイルを含むディレクトリへのパスを受け取ります。
/** * Bootstrap any package services. */public function boot(): void{ $this->loadJsonTranslationsFrom(__DIR__.'/../lang');}
言語ファイルの公開
パッケージの言語ファイルをアプリケーションの`lang/vendor`ディレクトリに公開したい場合は、サービスプロバイダーの`publishes`メソッドを使用できます。`publishes`メソッドは、パッケージパスとその目的の公開場所の配列を受け取ります。たとえば、`courier`パッケージの言語ファイルを公開するには、次のようにします。
/** * Bootstrap any package services. */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
メソッドに以下を追加します。
/** * Bootstrap any package services. */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
メソッドは、パッケージビューパスの配列とその目的の公開場所を受け取ります。
/** * 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; /** * Bootstrap your package's services. */public function boot(): void{ Blade::component('package-alert', AlertComponent::class);}
コンポーネントが登録されると、そのタグエイリアスを使用してレンダリングできます。
<x-package-alert/>
パッケージコンポーネントの自動読み込み
あるいは、componentNamespace
メソッドを使用して、慣例に従ってコンポーネントクラスを自動的に読み込むことができます。たとえば、Nightshade
パッケージには、Nightshade\Views\Components
名前空間に存在するCalendar
とColorPicker
コンポーネントがある場合があります。
use Illuminate\Support\Facades\Blade; /** * Bootstrap your package's services. */public function boot(): void{ Blade::componentNamespace('Nightshade\\Views\\Components', 'nightshade');}
これにより、package-name::
構文を使用して、ベンダーの名前空間でパッケージコンポーネントを使用できるようになります。
<x-nightshade::calendar /><x-nightshade::color-picker />
Bladeは、コンポーネント名をパスカルケースに変換することで、このコンポーネントにリンクされているクラスを自動的に検出します。 サブディレクトリも「ドット」表記でサポートされています。
匿名コンポーネント
パッケージに匿名コンポーネントが含まれている場合、それらはパッケージの「views」ディレクトリ(loadViewsFrom
メソッドで指定)のcomponents
ディレクトリに配置する必要があります。その後、パッケージのビュー名前空間をコンポーネント名の前に付けることで、それらをレンダリングできます。
<x-courier::alert />
「About」Artisanコマンド
Laravelの組み込みabout
Artisanコマンドは、アプリケーションの環境と構成の概要を提供します。パッケージは、AboutCommand
クラスを介して、このコマンドの出力に追加情報をプッシュできます。通常、この情報はパッケージサービスプロバイダーのboot
メソッドから追加できます。
use Illuminate\Foundation\Console\AboutCommand; /** * Bootstrap any application services. */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; /** * Bootstrap any package services. */public function boot(): void{ if ($this->app->runningInConsole()) { $this->commands([ InstallCommand::class, NetworkCommand::class, ]); }}
コマンドの最適化
Laravelのoptimize
コマンドは、アプリケーションの構成、イベント、ルート、ビューをキャッシュします。optimizes
メソッドを使用して、optimize
コマンドとoptimize:clear
コマンドが実行されたときに呼び出す必要があるパッケージ独自のArtisanコマンドを登録できます。
/** * Bootstrap any package services. */public function boot(): void{ if ($this->app->runningInConsole()) { $this->optimizes( optimize: 'package:optimize', clear: 'package:clear-optimizations', ); }}
公開アセット
パッケージには、JavaScript、CSS、画像などのアセットが含まれている場合があります。これらのアセットをアプリケーションのpublic
ディレクトリに公開するには、サービスプロバイダーのpublishes
メソッドを使用します。この例では、関連するアセットのグループを簡単に公開するために使用できるpublic
アセットグループタグも追加します。
/** * Bootstrap any package services. */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
パッケージの2つの公開グループ(courier-config
とcourier-migrations
)をパッケージのサービスプロバイダーのboot
メソッドで定義するためにタグを使用してみましょう。
/** * Bootstrap any package services. */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
コマンドを実行するときにタグを参照することで、これらのグループを個別に公開できます。
php artisan vendor:publish --tag=courier-config