> ## Documentation Index
> Fetch the complete documentation index at: https://kawax.biz/llms.txt
> Use this file to discover all available pages before exploring further.

# パッケージのキャッシュとoptimizeへの統合

> Laravel 13のoptimizes()を使い、パッケージ独自のキャッシュ生成・削除をデプロイに統合します。登録キー、除外指定、実行順序、失敗時の終了コードを実装から解説します。

パッケージが独自のメタデータを事前生成する場合、利用者のデプロイ手順に専用コマンドを追加してもらうだけでは、更新時の実行漏れが起こりやすくなります。`ServiceProvider::optimizes()` を使うと、生成と削除のコマンドをLaravelの `optimize` と `optimize:clear` に組み込めます。

このページでは[パッケージ開発の基礎](/jp/advanced/package-development)を前提に、Laravel Framework `v13.35.0` の実装を確認します。キャッシュファイルの形式ではなく、登録と運用の契約を扱います。

## コマンドの登録とタスクの登録を分ける

`commands()` はArtisanから呼べるコマンドクラスを登録します。`optimizes()` は、すでに実行可能なコマンド名を最適化タスクとして登録する別の処理です。後者だけを呼んでも、コマンドクラスは登録されません。

次の例は、パッケージに `CacheMetadataCommand` と `ClearMetadataCommand` が実装済みで、それぞれの `$signature` が `courier:cache` と `courier:clear-cache` であることを前提にしています。

```php theme={null}
<?php

namespace Acme\Courier;

use Acme\Courier\Console\Commands\CacheMetadataCommand;
use Acme\Courier\Console\Commands\ClearMetadataCommand;
use Illuminate\Support\ServiceProvider;

class CourierServiceProvider extends ServiceProvider
{
    public function boot(): void
    {
        if ($this->app->runningInConsole()) {
            $this->commands([
                CacheMetadataCommand::class,
                ClearMetadataCommand::class,
            ]);

            $this->optimizes(
                optimize: 'courier:cache',
                clear: 'courier:clear-cache',
                key: 'acme-courier',
            );
        }
    }
}
```

`optimizes()` の引数はすべてnullableで、生成だけ、削除だけの登録も可能です。ただし、生成したキャッシュをどの手順で無効化するかは、必ず利用者に案内してください。

## 登録キーも利用者向けの契約になる

`ServiceProvider` は、生成コマンドを静的配列の `$optimizeCommands` に、削除コマンドを `$optimizeClearCommands` に保存します。どちらも `key` が配列キーになります。

`key` を省略すると、プロバイダーのクラス名から名前が生成されます。たとえば `CourierServiceProvider` なら `courier` です。クラス名だけを使うため、別の名前空間にある同名プロバイダーでも衝突し得ます。

同じキーに再登録すると、その側のコマンドが後の値で上書きされます。複数のタスクを登録したい場合は、別々のキーを指定してください。また、`config` や `routes` などLaravel標準タスクのキーは避けます。標準タスクとパッケージタスクをまとめる際にも、同じ文字列キーは上書きされるためです。

<Tip>
  `acme-courier` のようにパッケージを識別できるキーを明示し、リリース間で維持してください。キーはタスクの表示名になり、利用者が `--except` で指定する値にもなります。
</Tip>

## 標準タスクの後で実行される

確認した実装では、両コマンドは標準タスクの配列にパッケージの登録配列を展開してから、順番に呼び出します。衝突しないキーを使った場合、パッケージタスクは標準タスクの後に追加されます。

| コマンド | 標準タスクの実行順序 | その後の処理 |
| - | - | - |
| `optimize` | `config:cache` → `event:cache` → `route:cache` → `view:cache` | 登録された生成コマンド |
| `optimize:clear` | `config:clear` → `cache:clear` → `clear-compiled` → `event:clear` → `route:clear` → `view:clear` | 登録された削除コマンド |

```mermaid theme={null}
flowchart TD
    A["プロバイダーのboot()"] --> B["commands()でArtisanコマンドを登録"]
    A --> C["optimizes()でキーとコマンド名を登録"]
    B --> D["php artisan optimize"]
    C --> D
    D --> E["標準の設定・イベント・ルート・ビューをキャッシュ"]
    E --> F["courier:cacheを実行"]
    C --> G["php artisan optimize:clear"]
    G --> H["標準キャッシュを削除"]
    H --> I["courier:clear-cacheを実行"]
```

この順序を前提に、生成コマンドは他の標準キャッシュを作り直すのではなく、パッケージが所有するデータだけを生成します。複数パッケージ間の依存順序を制御するAPIとして `optimizes()` を使わず、厳密な順序が必要なら専用コマンドを明示的に並べます。

<Warning>
  `optimize:clear` には `cache:clear` も含まれ、デフォルトのキャッシュストアのデータも削除します。パッケージ専用キャッシュだけを消したい場合は `courier:clear-cache` を直接実行してください。パッケージの削除コマンド自身も、共有ストア全体をflushせず、所有するキーやファイルだけを削除する設計にします。
</Warning>

## キーまたはコマンド名で除外する

両コマンドの `--except` は、カンマ区切りの値を受け取ります。各値の前後の空白を取り除き、タスクのキーまたはコマンド名に一致したものを除外します。

```bash theme={null}
php artisan optimize --except=acme-courier
php artisan optimize --except=courier:cache
php artisan optimize:clear --except=acme-courier,cache
```

最初の2つは同じ生成タスクを除外します。3つ目はパッケージの削除タスクと、標準の `cache:clear` を除外します。`cache` はタスクのキーで、パッケージ専用の名前ではありません。

除外指定はその実行だけに作用します。プロバイダーの登録を無効化したり、以前に作ったパッケージキャッシュを自動削除したりする設定ではありません。

## タスクのFAILと親コマンドの終了コードを区別する

`OptimizeCommand` と `OptimizeClearCommand` は各タスクを `callSilently()` で呼び、終了コードが `0` かどうかをタスク表示に渡します。通常の子コマンドの出力は表示されないため、原因の調査には専用コマンドを直接実行します。

Laravel `v13.35.0` の両 `handle()` は、子コマンドが非ゼロを返してもその値を親の戻り値として返しません。画面に `FAIL` と表示されてもループは続き、例外がなければ親コマンドの終了コードは `0` になります。一方、投げられた例外はタスク表示コンポーネントで再送出されるため、同じ継続動作ではありません。

<Warning>
  `php artisan optimize` が終了コード `0` だったことだけで、パッケージキャッシュの生成成功を判断しないでください。この挙動は確認したバージョンの実装に基づくため、対応Laravelバージョンを更新するときにも確認します。
</Warning>

パッケージの生成がデプロイの必須条件なら、子コマンドの終了コードを直接確認できる手順にします。たとえば、以下はパッケージタスクを一括実行から除外し、標準タスクの後に1回だけ直接実行する例です。

```bash theme={null}
php artisan optimize --except=acme-courier && php artisan courier:cache
```

この例は `courier:cache` の失敗を終了コードに反映しますが、標準タスクの非ゼロ終了を集約するものではありません。標準タスクも厳密に検知する必要があるデプロイでは、必要なコマンドを個別に実行して終了コードを確認してください。

## 更新に耐えるキャッシュの設計と確認

登録だけでなく、コマンドと読み取り側の責務も決めておきます。

* 生成は繰り返し実行しても同じ入力から同じ状態になり、途中失敗で不完全なデータを有効にしない。
* 削除はキャッシュが存在しない場合も正常に完了し、利用者の公開済み設定や永続データを削除しない。
* 生成に失敗したコマンドはエラーを報告して非ゼロを返す。読み取り側も壊れたキャッシュを無条件に正常扱いしない。
* キャッシュ形式を変更したら、利用者に再生成の必要性を案内し、長時間動くプロセスの再起動も検討する。

パッケージのテストに加え、利用アプリケーションでは以下を確認します。登録配列は静的なため、同一プロセスのテスト間では登録状態の持ち越しにも注意します。

| 確認する操作 | 完了条件 |
| - | - |
| 専用の生成・削除コマンドを直接実行 | 正常時は `0`、生成失敗時は非ゼロ。削除を2回実行しても成功する |
| `optimize` / `optimize:clear` を実行 | パッケージタスクが1回ずつ呼ばれ、生成・削除後の状態が正しい |
| キーとコマンド名で `--except` を指定 | 対象タスクだけが実行されない |
| 生成コマンドを非ゼロ終了させる | `FAIL` 表示と、確認対象バージョンの親コマンドの終了コードを区別できる |
| パッケージ更新後に再生成 | 新しいコードと設定で生成され、古い形式を読み続けない |

## 関連ページ

<Columns cols={2}>
  <Card title="パッケージ設定のマージとキャッシュ" icon="sliders" href="/jp/advanced/package-config-merging">
    公開済み設定の補完と、設定キャッシュ再構築の関係を確認します。
  </Card>

  <Card title="パッケージのテスト" icon="flask" href="/jp/advanced/package-testing">
    プロバイダーとArtisanコマンドをテスト環境に登録します。
  </Card>
</Columns>

## 参照した一次情報

* [Laravel公式ドキュメント: Optimize commands](https://github.com/laravel/docs/blob/13.x/packages.md#optimize-commands)
* [ServiceProvider: optimizes()と登録キー](https://github.com/laravel/framework/blob/v13.35.0/src/Illuminate/Support/ServiceProvider.php)
* [OptimizeCommand: タスクと除外処理](https://github.com/laravel/framework/blob/v13.35.0/src/Illuminate/Foundation/Console/OptimizeCommand.php)
* [OptimizeClearCommand: 削除タスクと実行順序](https://github.com/laravel/framework/blob/v13.35.0/src/Illuminate/Foundation/Console/OptimizeClearCommand.php)
* [Command: handle()の戻り値と終了コード](https://github.com/laravel/framework/blob/v13.35.0/src/Illuminate/Console/Command.php)
* [Task: 結果表示と例外の再送出](https://github.com/laravel/framework/blob/v13.35.0/src/Illuminate/Console/View/Components/Task.php)


## Related topics

- [Laravelパッケージ開発](/jp/advanced/package-development.md)
- [応用トピック](/jp/advanced/index.md)
- [パッケージのルート登録とキャッシュ](/jp/advanced/package-routes.md)
- [パッケージ設定のマージとキャッシュ](/jp/advanced/package-config-merging.md)
- [キャッシュ](/jp/cache.md)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.