# バッチ設計書 23-assets:install

## 概要

本ドキュメントは、Symfonyフレームワークの`assets:install`コンソールコマンドのバッチ設計書である。このコマンドは、各バンドルが持つWebアセット（CSS、JavaScript、画像など）をアプリケーションのpublicディレクトリにインストール（コピーまたはシンボリックリンク作成）する。

### 本バッチの処理概要

`assets:install`コマンドは、Symfonyアプリケーションに登録された全バンドルの`Resources/public`または`public`ディレクトリに格納されたWebアセットを、アプリケーションのpublicディレクトリ配下の`bundles/`ディレクトリにインストールするコマンドである。

**業務上の目的・背景**：Symfonyバンドルは、独自のCSS、JavaScript、画像などのWebアセットを含むことがある。これらのアセットはバンドルのディレクトリ構造内に格納されているため、Webサーバーから直接アクセスできない。本コマンドは、これらのアセットをWebサーバーがアクセス可能なpublicディレクトリに配置することで、ブラウザからアクセス可能にする。デプロイ時やバンドル追加・更新時に必須の操作である。

**バッチの実行タイミング**：デプロイ時やバンドルの追加・更新時に手動で実行される。`composer install`のpost-installスクリプトとして自動実行される場合もある。

**主要な処理内容**：
1. ターゲットディレクトリ（publicディレクトリ）を特定する
2. 各バンドルの`Resources/public`または`public`ディレクトリの存在を確認する
3. インストール方法（相対シンボリックリンク、絶対シンボリックリンク、ハードコピー）を決定する
4. 各バンドルのアセットをターゲットディレクトリにインストールする
5. 存在しなくなったバンドルのアセットディレクトリをクリーンアップする（`--no-cleanup`でスキップ可能）
6. 結果をテーブル形式で表示する

**前後の処理との関連**：`cache:clear`（No.1）や`cache:warmup`（No.2）と併せてデプロイ時に実行されることが多い。AssetMapperコンポーネントの`asset-map:compile`（No.46）とは異なり、バンドルアセットのみを対象とする。

**影響範囲**：publicディレクトリ配下の`bundles/`ディレクトリに対してファイルシステム操作（コピー、シンボリックリンク作成、削除）を行う。

## バッチ種別

アセット管理 / ファイルデプロイ

## 実行スケジュール

| 項目 | 内容 |
|-----|------|
| 実行頻度 | 随時（デプロイ時） |
| 実行時刻 | 任意 |
| 実行曜日 | 該当なし |
| 実行日 | 該当なし |
| トリガー | 手動 / composer post-installスクリプト |

## 実行条件

### 前提条件

| 条件 | 説明 |
|-----|------|
| ターゲットディレクトリの存在 | publicディレクトリが存在し書き込み可能であること |
| バンドルが登録済み | カーネルにバンドルが登録されていること |
| Filesystemコンポーネント | Symfony Filesystemコンポーネントが利用可能であること |

### 実行可否判定

ターゲットディレクトリが存在しない場合はInvalidArgumentExceptionがスローされる。アセットを持つバンドルが存在しない場合は「No assets were provided by any bundle.」メッセージで正常終了する。

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | デフォルト値 | 説明 |
|-------------|-----|-----|-------------|------|
| target | string | No | null（composer.jsonのextra.public-dirまたは"public"） | アセットのインストール先ディレクトリ |
| --symlink | bool | No | false | コピーの代わりにシンボリックリンクを作成 |
| --relative | bool | No | false | 相対シンボリックリンクを作成 |
| --no-cleanup | bool | No | false | 存在しなくなったバンドルのアセットを削除しない |

### 入力データソース

| データソース | 形式 | 説明 |
|-------------|------|------|
| バンドルアセットディレクトリ | ファイルシステム | 各バンドルの`Resources/public`または`public`ディレクトリ |
| composer.json | JSON | publicディレクトリのパス設定（extra.public-dir） |

## 出力仕様

### 出力データ

| 出力先 | 形式 | 説明 |
|-------|------|------|
| publicディレクトリ/bundles/ | ファイルシステム | バンドルアセットのコピーまたはシンボリックリンク |
| コンソール（stdout） | テーブル | 各バンドルのインストール結果 |

### 出力ファイル仕様

| 項目 | 内容 |
|-----|------|
| ファイル名 | バンドル名から"Bundle"サフィックスを除去した小文字名のディレクトリ |
| 出力先 | {target}/bundles/{バンドル名}/ |
| インストール方法 | copy / absolute symlink / relative symlink |

## 処理フロー

### 処理シーケンス

```
1. ターゲットディレクトリ決定
   └─ 引数未指定時はcomposer.jsonのextra.public-dirまたは"public"
2. インストール方法決定
   └─ --relative: 相対シンボリックリンク
   └─ --symlink: 絶対シンボリックリンク
   └─ デフォルト: ハードコピー
3. バンドルループ処理
   └─ 各バンドルのResources/publicまたはpublicディレクトリを確認
   └─ 存在しない場合はスキップ
   └─ 既存のターゲットディレクトリを削除
   └─ 選択されたメソッドでインストール（フォールバックあり）
4. クリーンアップ処理
   └─ --no-cleanup未指定時、存在しないバンドルのアセットディレクトリを削除
5. 結果表示
   └─ バンドル名、インストール方法、状態をテーブル形式で出力
```

### フローチャート

```mermaid
flowchart TD
    A[バッチ開始] --> B[ターゲットディレクトリ決定]
    B --> C{ディレクトリ存在?}
    C -->|No| D[InvalidArgumentException]
    C -->|Yes| E[インストール方法決定]
    E --> F[バンドルループ開始]
    F --> G{アセットディレクトリ存在?}
    G -->|No| H[スキップ]
    G -->|Yes| I[既存ターゲット削除]
    I --> J{インストール方法}
    J -->|relative symlink| K[相対リンク作成]
    J -->|absolute symlink| L[絶対リンク作成]
    J -->|copy| M[ハードコピー]
    K -->|失敗| L
    L -->|失敗| M
    K --> N[結果記録]
    L --> N
    M --> N
    H --> F
    N --> F
    F -->|ループ終了| O{--no-cleanup?}
    O -->|No| P[不要アセット削除]
    O -->|Yes| Q[結果テーブル表示]
    P --> Q
    Q --> R[バッチ終了]
    D --> R
```

## データベース操作仕様

### 操作別データベース影響一覧

データベース操作なし。本コマンドはファイルシステム操作のみを行う。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| 1 | インストールエラー | ファイルコピーまたはシンボリックリンク作成に失敗 | ファイルシステムの権限を確認 |
| InvalidArgumentException | ディレクトリ未存在 | ターゲットディレクトリが存在しない | 正しいパスを指定するかディレクトリを作成 |

### リトライ仕様

| 項目 | 内容 |
|-----|------|
| リトライ回数 | なし（フォールバック機構あり） |
| リトライ間隔 | 該当なし |
| リトライ対象エラー | シンボリックリンク作成失敗時、自動的にハードコピーにフォールバック |

### 障害時対応

シンボリックリンク作成に失敗した場合は自動的にハードコピーにフォールバックする。ハードコピーも失敗した場合はエラーとして結果テーブルに表示される。手動でファイルシステムの権限を確認し、再実行する。

## トランザクション仕様

| 項目 | 内容 |
|-----|------|
| トランザクション範囲 | バンドル単位 |
| コミットタイミング | 各バンドルのインストール完了時 |
| ロールバック条件 | 個別バンドルの失敗は他に影響しない |

## パフォーマンス要件

| 項目 | 内容 |
|-----|------|
| 想定処理件数 | アプリケーションに登録されたバンドル数（通常数個〜数十個） |
| 目標処理時間 | 数秒〜数十秒（アセット量に依存） |
| メモリ使用量上限 | 標準的なCLIメモリ制限内 |

## 排他制御

同時実行は推奨されない。同一ターゲットディレクトリへの並行書き込みはファイルシステムの不整合を引き起こす可能性がある。

## ログ出力

| ログ種別 | 出力タイミング | 出力内容 |
|---------|--------------|---------|
| 開始ログ | バッチ開始時 | インストール方法（copy/symlink/relative symlink） |
| 結果ログ | 各バンドル処理後 | バンドル名、インストール方法、成否 |
| 終了ログ | バッチ終了時 | 成功メッセージまたはエラーメッセージ |
| 注意ログ | コピーフォールバック時 | アセット変更時に再実行が必要な旨の注意 |

## 監視・アラート

| 監視項目 | 閾値 | アラート先 |
|---------|-----|----------|
| 該当なし | 該当なし | 該当なし |

デプロイ時実行コマンドのため、CIパイプラインでの終了コード監視が推奨される。

## 備考

- シンボリックリンク作成に失敗した場合は絶対シンボリックリンク、さらにハードコピーへの段階的フォールバック機構を持つ
- `--no-cleanup`オプションを指定しない場合、削除されたバンドルのアセットディレクトリが自動的にクリーンアップされる
- publicディレクトリのパスはcomposer.jsonの`extra.public-dir`設定から自動検出される
- VCSファイル（.gitなど）はコピー時に無視されない（`ignoreDotFiles(false)`で明示的に含まれる）
