サイトアイコン IT & ライフハックブログ|学びと実践のためのアイデア集

Laravelパッケージ開発の始め方:「laravel package」で雛形作成から品質確認まで

PHPとLaravelのパッケージ構造を抽象的なモジュールで表現したイラスト

Laravel向けの共通機能を複数のアプリケーションで使いたいとき、コピーして増やすよりもパッケージとして管理したほうが、修正箇所と責任範囲をそろえやすくなります。

ただし、雛形を作るコマンドがあっても、何を公開APIにするか、どのLaravelバージョンを支えるか、設定やデータベース変更を利用側へどう渡すかは開発者が決める必要があります。

この記事では、Laravel Installerのlaravel packageコマンドを入口に、パッケージへ切り出す判断から公開前の品質確認までを実務の順番で整理します。

Laravel向けパッケージが適する場面

Composerパッケージは、PHPのコードと依存関係、読み込み規則などをひとまとまりにした配布単位です。

Laravel向けパッケージは、そのうちサービスコンテナ、設定、ルート、ビュー、マイグレーションなどLaravelの仕組みと連携するものを指します。

Laravel公式ドキュメントも、どのPHPフレームワークからでも使える独立パッケージと、Laravel固有の機能を提供するパッケージを分けています。

切り出しを検討しやすいのは、次の条件が重なる機能です。

反対に、一つのアプリケーションだけで使う処理や、固有のテーブル構造と画面遷移に強く依存する処理は、まずアプリケーション内のモジュールとして整理するほうが自然です。

業務Webアプリ全体のバージョン選定や運用設計は、既存記事のPHPとLaravelによる業務Webアプリの設計ガイドで確認できます。

「laravel package」で雛形を作る

Laravel Installer v5.31.0では、Laravel向けパッケージの雛形を作るpackageコマンドが追加されました。

Laravel 13の公式ドキュメントにも、公式のパッケージスケルトンを利用する開始方法として次のコマンドが掲載されています。

laravel package invoice-rules

対話形式の設定では、名前空間とサービスプロバイダーを決め、設定、ルート、ビュー、翻訳、マイグレーション、アセット、コマンド、ファサードなど、必要な機能だけを選べます。

自動化された初期設定では、必要な機能をオプションで指定できます。

laravel package invoice-rules \
  --config \
  --migrations \
  --commands

公式スケルトンには、サービスプロバイダーに加え、Pestによるテスト、Larastanによる静的解析、Pintによるコード整形、実際のLaravelアプリケーションに近い状態で検証するためのワークベンチが用意されています。

このコマンドが解決するのは初期構造の作成です。

利用側へ約束するインターフェースや互換性まで自動で決まるわけではありません。

コマンドを実行する前に決める境界

雛形へ機能を足す前に、パッケージの責任を一文で書ける状態にします。

たとえば「請求金額を計算する」だけでは、税率の取得、端数処理、通貨換算、請求書保存まで含むのかが決まりません。

「渡された明細と計算規則から合計額を返す」のように入力と出力まで限定すると、アプリケーション側に残す処理を判断できます。

決める項目 確認する問い 曖昧なまま進めた場合
責任範囲 何を受け取り、何を返すのか アプリ固有の処理が流入する
公開API 利用側が呼ぶクラスとメソッドはどれか 内部実装の変更が破壊的変更になる
対応環境 PHPとLaravelのどの組み合わせを支えるか インストールできても実行時に失敗する
状態の所有者 設定値とデータを誰が保持するか 設定公開やマイグレーションの責任が重なる
運用責任 ログ、キュー、定期処理を誰が監視するか 障害時の調査先が定まらない

再利用できそうだから切り出すのではなく、複数の利用側に対して同じ契約を保つ必要があるかで判断します。

生成後に確認する四つの層

Composerの依存条件

composer.jsonには、対応するPHPとilluminate/supportなどの依存パッケージを明示します。

ComposerはPHP本体、拡張機能、システムライブラリなどをプラットフォームパッケージとして扱い、依存解決時にバージョン条件を照合します。

Laravel 12と13を同じパッケージで支える例は次のように書けます。

{
  "require": {
    "php": "^8.3",
    "illuminate/support": "^12.0 || ^13.0"
  }
}

Laravel 13はPHP 8.3以上を必要とします。

Laravel 12をPHP 8.2でも支えるなら、PHPの条件を下げるだけでなく、パッケージ内でPHP 8.3固有の構文やAPIを使っていないことをテストで確認します。

対応範囲を広げるほど利用者は増えますが、継続的に検証する組み合わせも増えます。

実際に保守できる範囲へ絞るほうが、宣言だけの互換性を掲げるより安全です。

サービスプロバイダーの役割

サービスプロバイダーは、パッケージとLaravelアプリケーションを接続します。

registerではサービスコンテナへの登録や既定設定の統合を行い、bootではルート、ビュー、翻訳、マイグレーションなどの読み込みや公開を設定します。

public function register(): void
{
    $this->mergeConfigFrom(
        __DIR__.'/../config/invoice-rules.php',
        'invoice-rules'
    );
}

public function boot(): void
{
    $this->publishes([
        __DIR__.'/../config/invoice-rules.php' => config_path('invoice-rules.php'),
    ], 'invoice-rules-config');
}

公式ドキュメントによれば、mergeConfigFromが統合するのは配列の第1階層です。

多階層の設定を部分的に上書きできると誤解すると、利用側で未指定の値が欠ける可能性があります。

設定ファイル内のクロージャも、設定キャッシュで正しくシリアライズできないため避けます。

サービスコンテナと依存性注入の設計を先に確認したい場合は、Laravelのサービスコンテナと依存性注入の解説が参考になります。

設定とリソースの公開範囲

設定、ルート、ビュー、翻訳、マイグレーションをすべて生成して公開する必要はありません。

利用側が変更すべき設定だけを公開し、内部既定値で足りるものはパッケージ内に保ちます。

ルートを持つ場合は、名前とURLの衝突、認証や認可の前提、ミドルウェアの適用範囲を確認します。

マイグレーションを持つ場合は、既存テーブルとの名前衝突、ロールバック、複数バージョンを経由する更新手順まで検証します。

公開対象を増やすと利用者の自由度は上がりますが、上書きされたファイルをパッケージ側から更新しにくくなります。

利用側から見たテスト

クラス単体のテストだけでは、パッケージとして正しく組み込めることを保証できません。

サービスプロバイダーの自動検出、設定の上書き、ルート登録、マイグレーション、コマンド実行など、Laravelへ接続したときの振る舞いもテストします。

公式スケルトンのワークベンチは、この統合確認に使える小さなLaravelアプリケーションを提供します。

テストの粒度やデータベースの扱いは、Laravelのテスト戦略もあわせて参照してください。

複数バージョン対応を宣言する条件

複数のLaravelメジャーバージョンへ依存条件を広げるなら、継続的インテグレーションで各組み合わせを実行します。

依存関係が解決できることと、パッケージが正しく動くことは別の確認です。

最低依存バージョンと最新依存バージョンの両方を試すと、過度に新しいAPIへの依存と、将来の更新による不整合を見つけやすくなります。

利用者が必要とする対応範囲より、チームが保守できる範囲を優先します。

公開までの実務手順

  1. パッケージの責任、公開API、対応環境をREADMEの冒頭に書く
  2. laravel packageで雛形を作り、不要な設定やリソースを削る
  3. サービスプロバイダーへ必要最小限の登録と読み込みを書く
  4. 単体テストとワークベンチ上の統合テストを用意する
  5. 開発中のアプリケーションからローカルリポジトリとして導入し、利用手順を確認する
  6. 対応するPHPとLaravelの組み合わせを継続的インテグレーションで検証する
  7. 変更の互換性を判断し、セマンティックバージョニングに沿ってリリースする

ローカルでは動くのに新規導入で失敗する問題を避けるには、空のLaravelアプリケーションへREADMEどおりに導入する確認が有効です。

開発者の端末にだけある設定、未記載のPHP拡張、手作業で作成したテーブルがあれば、この段階で見つけられます。

公開前チェックリスト

よくある質問

社内だけで使う機能でもパッケージにする価値はありますか

複数のアプリケーションで同じ契約を保ち、独立して更新したいなら価値があります。

公開リポジトリに置く必要はなく、社内Gitや非公開のComposerリポジトリで配布できます。

一つのアプリケーションでしか使わない処理はどうしますか

最初はアプリケーション内の名前空間やモジュールとして分離します。

別のアプリケーションでも同じ公開APIが必要になった時点で、パッケージ化を検討すれば十分です。

設定ファイルは必ず公開すべきですか

利用側が変更する項目がある場合に限って公開します。

既定値だけで動くなら、mergeConfigFromで読み込み、公開手順を増やさない設計も選べます。

Laravelの複数メジャーバージョンを支えるべきですか

利用者の要件があり、各組み合わせを継続して検証できる場合に支えます。

テストできないバージョンまで依存条件だけ広げると、不具合の発見を利用者に任せることになります。

参考資料

モバイルバージョンを終了