# 機能設計書 45-Cache

## 概要

本ドキュメントは、Symfony Cacheコンポーネントの機能設計を記述する。CacheはPSR-6（CacheItemPoolInterface）およびPSR-16（SimpleCache）のキャッシュ実装を提供し、タグベースのキャッシュ無効化にも対応するコンポーネントである。

### 本機能の処理概要

Cacheコンポーネントは、アプリケーションのパフォーマンス向上のためのキャッシュ機構を提供する。Redis、Memcached、ファイルシステム、APCu、PDO/Doctrine DBAL等の多様なバックエンドに対応し、PSR-6/PSR-16の標準インターフェースを実装する。

**業務上の目的・背景**：Webアプリケーションにおいて、データベースクエリ結果、APIレスポンス、計算結果等の頻繁にアクセスされるデータをキャッシュすることは、パフォーマンスとスケーラビリティの向上に不可欠である。Cacheコンポーネントは、PSR標準に準拠した統一APIを提供し、バックエンドの切り替えを容易にする。タグベースのキャッシュ無効化により、関連するキャッシュエントリを効率的に管理できる。

**機能の利用シーン**：データベースクエリ結果のキャッシュ、APIレスポンスのキャッシュ、テンプレートレンダリング結果のキャッシュ、セッションデータの保存、レートリミッター用のトークンストレージ等。

**主要な処理内容**：
1. CacheItemの生成、値の設定、有効期限の管理
2. PSR-6（getItem/save/deleteItem）およびPSR-16（get/set/delete）のキャッシュ操作
3. タグベースのキャッシュ無効化（TagAwareAdapter）
4. チェーンアダプター（ChainAdapter）による多層キャッシュ
5. バッチ操作（getItems/saveDeferred/commit）
6. キャッシュのプルーニング（期限切れエントリの削除）
7. Messenger統合による非同期キャッシュウォームアップ
8. LockRegistryによるキャッシュスタンピード防止

**関連システム・外部連携**：Redis、Memcached、APCu等のキャッシュバックエンド、PDO/Doctrine DBALデータベース、ファイルシステムと連携する。

**権限による制御**：Cacheコンポーネント自体には権限制御機構はない。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 25 | キャッシュパネル | 主画面 | Cacheコンポーネントのヒット/ミス/呼び出し統計の表示 |
| 41 | テンプレート表示 | 参照画面 | レスポンスキャッシュ設定（maxAge、sharedAge）の管理 |

## 機能種別

キャッシュ管理 / パフォーマンス最適化

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| key | string | Yes | キャッシュキー | 空文字列不可、PSR-6予約文字（{}()/\@:）不可 |
| value | mixed | Yes（set時） | キャッシュする値 | - |
| ttl | int\|DateInterval\|null | No | 有効期限（秒数またはDateInterval） | - |
| tags | string\|string[] | No | キャッシュタグ | 空文字列不可、予約文字不可 |
| expiration | DateTimeInterface\|null | No | 有効期限の絶対時刻 | - |

### 入力データソース

- アプリケーションコードからの直接操作
- DIコンテナ経由のアダプター設定（DSN文字列）
- Symfony設定ファイル（framework.cache）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| CacheItem | CacheItem | PSR-6キャッシュアイテム（key、value、isHit、metadata） |
| mixed (PSR-16) | mixed | PSR-16のget()メソッドの返却値 |
| bool | bool | 操作の成否（save、delete等） |

### 出力先

- アプリケーションコード（取得結果）
- キャッシュバックエンド（保存時）
- WebProfilerBundleキャッシュパネル（デバッグ時）

## 処理フロー

### 処理シーケンス

```
1. CacheItemPoolInterface::getItem(key)
   └─ キーのバリデーション（validateKey）
   └─ バックエンドからの取得
   └─ CacheItemオブジェクトの生成（isHit判定含む）
2. CacheItem::set(value) / expiresAfter(ttl) / tag(tags)
   └─ 値の設定、有効期限の設定、タグの付与
3. CacheItemPoolInterface::save(item)
   └─ バックエンドへの永続化
   └─ タグ情報の保存（TagAwareAdapter時）
4. CacheItemPoolInterface::deleteItem(key)
   └─ バックエンドからの削除
```

### フローチャート

```mermaid
flowchart TD
    A[getItem key] --> B{キャッシュヒット?}
    B -->|Yes| C[CacheItem isHit=true]
    B -->|No| D[CacheItem isHit=false]
    C --> E[値の取得 get]
    D --> F[値の計算]
    F --> G[set value]
    G --> H{TTL設定?}
    H -->|Yes| I[expiresAfter ttl]
    H -->|No| J{タグ設定?}
    I --> J
    J -->|Yes| K[tag tags]
    J -->|No| L[save item]
    K --> L
    L --> M[バックエンドに永続化]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-45-01 | キーバリデーション | キャッシュキーは空文字列不可、PSR-6予約文字を含んではならない | validateKey()呼び出し時 |
| BR-45-02 | タグバリデーション | タグは空文字列不可、PSR-6予約文字を含んではならない | tag()呼び出し時 |
| BR-45-03 | タグ非対応プール制限 | タグ非対応プールのCacheItemにtag()を呼ぶとLogicException | isTaggable=false時 |
| BR-45-04 | 有効期限 | TTL=nullの場合、アダプターのデフォルトTTLが適用される | expiresAfter(null)時 |

### 計算ロジック

有効期限の計算: `microtime(true) + DateInterval秒数` または `microtime(true) + int秒数`（**CacheItem.php 77-89行目**）

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| save | cache_items（PDO/Doctrine） | INSERT/UPDATE | キャッシュアイテムの保存 |
| deleteItem | cache_items | DELETE | キャッシュアイテムの削除 |
| prune | cache_items | DELETE | 期限切れアイテムの一括削除 |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | InvalidArgumentException | キャッシュキーが空文字列 | 非空のキーを使用する |
| - | InvalidArgumentException | キャッシュキーにPSR-6予約文字が含まれる | 予約文字を除外する |
| - | LogicException | タグ非対応プールでtag()を呼んだ | TagAwareAdapterを使用する |
| - | InvalidArgumentException | タグが空文字列またはStringable以外 | 正しいタグ形式を使用する |

### リトライ仕様

バックエンド接続エラー時のリトライはアダプター実装に依存する。ChainAdapterでは上位アダプターの失敗時に下位アダプターにフォールバックする。

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

saveDeferred()とcommit()によるバッチ保存をサポートする。commit()で一括永続化が行われる。

## パフォーマンス要件

- LockRegistryによるキャッシュスタンピード防止（同一キーへの同時計算を防止）
- ChainAdapterによる多層キャッシュ（APCu -> Redis -> Database等）
- PhpFilesAdapterでOPcacheを活用した高速キャッシュ

## セキュリティ考慮事項

- キャッシュキーのバリデーションにより、インジェクション攻撃を防止
- 機密データのキャッシュ時は暗号化を検討する必要がある

## 備考

- Psr16CacheクラスでPSR-6アダプターをPSR-16インターフェースにラップ可能
- Marshallerインターフェースにより、キャッシュ値のシリアライズ方式をカスタマイズ可能

---

## コードリーディングガイド

本機能を理解するために参照すべきファイルと、推奨する読み解き順序を以下に示す。

### 推奨読解順序

#### Step 1: データ構造を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | CacheItem.php | `src/Symfony/Component/Cache/CacheItem.php` | キャッシュアイテムのデータ構造（key、value、isHit、expiry、metadata） |

**読解のコツ**: CacheItemのプロパティはprotectedで宣言されており、これは友好クラス（アダプター）からのアクセスを意図している（**202行目**のコメント参照）。`METADATA_EXPIRY_OFFSET`定数（**25行目**）はメタデータの有効期限オフセット。`VALUE_WRAPPER`（**26行目**）はメタデータ付き値のラッピングに使用される。

#### Step 2: PSR-16ラッパーを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | Psr16Cache.php | `src/Symfony/Component/Cache/Psr16Cache.php` | PSR-6をPSR-16にラップするクラス |

**主要処理フロー**:
1. **80-95行目**: get() - PSR-6のgetItem()をラップし、isHit()で判定
2. **97-115行目**: set() - createCacheItemクロージャでCacheItem生成、PSR-6のsave()で永続化
3. **165-211行目**: setMultiple() - saveDeferred()とcommit()によるバッチ保存

#### Step 3: アダプター層を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | AbstractAdapter.php | `src/Symfony/Component/Cache/Adapter/AbstractAdapter.php` | アダプターの基底クラス |
| 3-2 | RedisAdapter.php | `src/Symfony/Component/Cache/Adapter/RedisAdapter.php` | Redisバックエンド実装 |
| 3-3 | FilesystemAdapter.php | `src/Symfony/Component/Cache/Adapter/FilesystemAdapter.php` | ファイルシステムバックエンド実装 |

#### Step 4: タグ対応アダプターを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | AbstractTagAwareAdapter.php | `src/Symfony/Component/Cache/Adapter/AbstractTagAwareAdapter.php` | タグ対応アダプターの基底クラス |

### プログラム呼び出し階層図

```
アプリケーションコード
    |
    ├─ PSR-6: CacheItemPoolInterface
    |      ├─ getItem(key) → CacheItem
    |      ├─ save(CacheItem) → bool
    |      ├─ deleteItem(key) → bool
    |      ├─ saveDeferred(CacheItem) → bool
    |      └─ commit() → bool
    |
    ├─ PSR-16: Psr16Cache
    |      ├─ get(key, default)
    |      ├─ set(key, value, ttl)
    |      └─ delete(key)
    |
    └─ Adapter層
           ├─ AbstractAdapter (共通ロジック)
           ├─ RedisAdapter / MemcachedAdapter
           ├─ FilesystemAdapter / PhpFilesAdapter
           ├─ PdoAdapter / DoctrineDbalAdapter
           ├─ ApcuAdapter
           ├─ ChainAdapter (多層キャッシュ)
           └─ TagAwareAdapter (タグ対応)
```

### データフロー図

```
[入力]                    [処理]                         [出力]

key (string)         CacheItemPoolInterface          CacheItem
value (mixed)        ├─ validateKey()                 (key, value, isHit)
ttl (int/interval)   ├─ Adapter::getItem()
tags (string[])      ├─ CacheItem::set()               bool
                     ├─ CacheItem::expiresAfter()      (save/delete結果)
                     └─ Adapter::save()
                            |
                     バックエンド
                     ├─ Redis
                     ├─ Memcached
                     ├─ Filesystem
                     ├─ APCu
                     └─ PDO/Doctrine
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| CacheItem.php | `src/Symfony/Component/Cache/CacheItem.php` | ソース | キャッシュアイテムデータ構造 |
| Psr16Cache.php | `src/Symfony/Component/Cache/Psr16Cache.php` | ソース | PSR-16ラッパー |
| LockRegistry.php | `src/Symfony/Component/Cache/LockRegistry.php` | ソース | キャッシュスタンピード防止 |
| AbstractAdapter.php | `src/Symfony/Component/Cache/Adapter/AbstractAdapter.php` | ソース | アダプター基底クラス |
| RedisAdapter.php | `src/Symfony/Component/Cache/Adapter/RedisAdapter.php` | ソース | Redisアダプター |
| MemcachedAdapter.php | `src/Symfony/Component/Cache/Adapter/MemcachedAdapter.php` | ソース | Memcachedアダプター |
| FilesystemAdapter.php | `src/Symfony/Component/Cache/Adapter/FilesystemAdapter.php` | ソース | ファイルシステムアダプター |
| ChainAdapter.php | `src/Symfony/Component/Cache/Adapter/ChainAdapter.php` | ソース | チェーンアダプター |
| DataCollector/ | `src/Symfony/Component/Cache/DataCollector/` | ソース | プロファイラー用データ収集 |
| Marshaller/ | `src/Symfony/Component/Cache/Marshaller/` | ソース | シリアライズ処理 |
