# 機能設計書 33-Validator

## 概要

本ドキュメントは、Symfony Validatorコンポーネントの機能設計を記述する。Validatorコンポーネントは、PHP値やオブジェクトのバリデーション（検証）を制約（Constraint）ベースで宣言的に行う機能を提供する。

### 本機能の処理概要

Validatorコンポーネントは、PHPアトリビュート（またはYAML/XML設定）で定義されたバリデーション制約に基づいて、値やオブジェクトの妥当性を検証する。検証結果は制約違反（ConstraintViolation）のリストとして返却される。

**業務上の目的・背景**：Webアプリケーションにおいて、ユーザー入力データや外部システムからの入力データの妥当性検証は不可欠である。Validatorコンポーネントは、バリデーションルールをドメインモデルに宣言的に定義することで、ビジネスルールの明確化と再利用性を向上させる。JSR 303 Bean Validation仕様に着想を得たAPIを提供する。

**機能の利用シーン**：フォーム送信データの検証、APIリクエストパラメータの検証、エンティティのデータ整合性チェック、コマンド入力値の検証など、あらゆるデータ検証場面で使用される。Formコンポーネントと密接に連携し、フォームの自動バリデーションを実現する。

**主要な処理内容**：
1. バリデーション制約の定義（アトリビュート、YAML、XML、PHP）
2. 制約メタデータのロードとキャッシュ
3. バリデータビルダーによるバリデータインスタンスの構築
4. RecursiveValidatorによるオブジェクト/値の再帰的検証
5. 制約バリデータ（ConstraintValidator）による個別制約の検証実行
6. 制約違反リスト（ConstraintViolationList）の生成と返却
7. グループベースのバリデーション（バリデーショングループの指定）
8. コールバックバリデーション（createCallable / createIsValidCallable）

**関連システム・外部連携**：Formコンポーネント（フォームバリデーション統合）、DependencyInjectionコンポーネント（DIコンテナ経由のバリデータファクトリ）、Translationコンポーネント（エラーメッセージの翻訳）、Doctrine Bridge（Doctrineエンティティの制約定義）と連携する。

**権限による制御**：バリデーション自体には権限制御はない。バリデーション結果に基づくアクセス制御は呼び出し元で実装する。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 23 | フォームパネル | 補助機能 | フォームに適用されたバリデーション制約の表示 |
| 24 | バリデーターパネル | 主機能 | Validatorコンポーネントによるバリデーション制約・結果の表示 |

## 機能種別

バリデーション処理

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| value | mixed | Yes | 検証対象の値またはオブジェクト | - |
| constraints | Constraint\|Constraint[] | No | 適用する制約。省略時はオブジェクトのメタデータから取得 | Constraintインスタンスであること |
| groups | string\|string[] | No | バリデーショングループ | 有効なグループ名 |

### 入力データソース

- 検証対象の値/オブジェクト（プログラムからの直接入力）
- アトリビュートによる制約定義（PHPクラスのメタデータ）
- YAML/XML設定ファイルによる制約定義
- ValidatorBuilderによる設定

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| violations | ConstraintViolationListInterface | 制約違反のリスト。違反がない場合は空のリスト |

### 出力先

呼び出し元のPHPコード（メソッドの戻り値として返却）

## 処理フロー

### 処理シーケンス

```
1. バリデータの構築
   ├─ ValidatorBuilder の設定
   │   ├─ メタデータローダーの設定（Attribute/YAML/XML/StaticMethod）
   │   ├─ 翻訳設定
   │   └─ キャッシュ設定
   └─ RecursiveValidator の生成
2. バリデーションの実行
   ├─ validate() メソッドの呼び出し
   ├─ ExecutionContext の生成
   ├─ メタデータの取得（LazyLoadingMetadataFactory）
   ├─ グループの解決（GroupSequence対応）
   ├─ 制約ごとのバリデーション
   │   ├─ ConstraintValidatorFactory による ConstraintValidator の取得
   │   └─ ConstraintValidator::validate() の実行
   └─ ConstraintViolationList の返却
3. 違反情報の構築
   └─ ConstraintViolation オブジェクトの生成
       ├─ メッセージテンプレート
       ├─ パラメータ
       ├─ ルート値
       └─ プロパティパス
```

### フローチャート

```mermaid
flowchart TD
    A[validate呼び出し] --> B[ExecutionContext生成]
    B --> C{制約指定あり?}
    C -->|Yes| D[指定された制約を使用]
    C -->|No| E[メタデータから制約取得]
    E --> F[LazyLoadingMetadataFactory]
    D --> G[グループ解決]
    F --> G
    G --> H[制約ループ]
    H --> I[ConstraintValidatorFactory]
    I --> J[ConstraintValidator::validate]
    J --> K{違反あり?}
    K -->|Yes| L[ConstraintViolation生成]
    K -->|No| H
    L --> H
    H --> M[ConstraintViolationList返却]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-33-01 | グループベースバリデーション | 指定されたグループに属する制約のみを検証する | groupsパラメータ指定時 |
| BR-33-02 | GroupSequence | グループを順序付けて検証し、先のグループで違反があれば後続グループの検証を中断する | GroupSequence指定時 |
| BR-33-03 | 再帰的検証 | オブジェクトのプロパティにValid制約がある場合、関連オブジェクトも再帰的に検証する | Valid制約指定時 |
| BR-33-04 | カスタムバリデータ | ConstraintValidatorを拡張して独自の検証ロジックを実装できる | カスタムConstraint定義時 |
| BR-33-05 | メタデータキャッシュ | 制約メタデータをキャッシュして繰り返しのリフレクションアクセスを回避する | CacheItemPoolInterface設定時 |
| BR-33-06 | コールバックバリデーション | createCallable/createIsValidCallableによりバリデーションをcallableとして利用できる | Validation::createCallable/createIsValidCallable使用時 |

### 計算ロジック

特になし。

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

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

本機能自体はデータベース操作を行わない。ただしUniqueEntity等のDoctrine連携バリデータは間接的にDBクエリを発行する。

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| - | - | - | 直接のデータベース操作なし |

### テーブル別操作詳細

該当なし。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | ValidatorException | バリデータの設定が不正 | ValidatorBuilderの設定を確認する |
| - | ValidationFailedException | createCallable使用時にバリデーション失敗 | 入力値を修正するか、制約を見直す |
| - | UnexpectedTypeException | 制約バリデータに不正な型が渡された | 正しい型の値を渡す |
| - | ConstraintDefinitionException | 制約定義が不正 | 制約アトリビュートの設定を修正する |

### リトライ仕様

リトライは不要（同期処理のため）。

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

トランザクション管理は行わない。

## パフォーマンス要件

- メタデータのキャッシュにより、繰り返しのバリデーションでのパフォーマンスを確保
- ConstraintValidatorはファクトリパターンで生成され、再利用される
- LazyLoadingMetadataFactoryにより、メタデータの遅延読み込みが行われる

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

- バリデーションエラーメッセージにユーザー入力値を含める場合、XSS対策（エスケープ処理）が必要
- バリデーションルールのバイパスを防止するため、サーバーサイドバリデーションは必須とする

## 備考

- ConstraintViolationListはCountable、IteratorAggregate、ArrayAccessを実装しており、配列のように扱える
- DataCollectorが用意されており、WebProfilerのバリデーターパネルでバリデーション結果を可視化できる
- PSR互換性は直接提供されていないが、Symfony独自の成熟したAPIを持つ

---

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

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

### 推奨読解順序

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

制約（Constraint）と制約違反（ConstraintViolation）のデータ構造を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | Constraint.php | `src/Symfony/Component/Validator/Constraint.php` | 制約の基底抽象クラス。groups, payload, ERROR_NAMESの定義 |
| 1-2 | ConstraintViolation.php | `src/Symfony/Component/Validator/ConstraintViolation.php` | 制約違反のデータクラス |
| 1-3 | ConstraintViolationList.php | `src/Symfony/Component/Validator/ConstraintViolationList.php` | 制約違反リスト |

**読解のコツ**: Constraintクラスはabstractで、各具体的な制約（NotBlank, Length等）が継承する。`DEFAULT_GROUP`定数と`CLASS_CONSTRAINT`/`PROPERTY_CONSTRAINT`定数がグループとターゲットを表す。

#### Step 2: エントリーポイントを理解する

バリデーションの起点となるクラスを確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | Validation.php | `src/Symfony/Component/Validator/Validation.php` | エントリーポイント。createValidator, createCallable等のスタティックメソッド |
| 2-2 | ValidatorBuilder.php | `src/Symfony/Component/Validator/ValidatorBuilder.php` | バリデータの構築。ローダー、翻訳、キャッシュの設定 |

**主要処理フロー**:
1. **69-72行目** (Validation.php): `createValidator()` - ValidatorBuilderを使ってバリデータを生成
2. **27-38行目** (Validation.php): `createCallable()` - 検証失敗時に例外をスローするcallableを生成
3. **45-61行目** (Validation.php): `createIsValidCallable()` - 検証結果をboolで返すcallableを生成

#### Step 3: バリデーション実行エンジンを理解する

RecursiveValidatorとExecutionContextを確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | RecursiveValidator.php | `src/Symfony/Component/Validator/Validator/RecursiveValidator.php` | メインのバリデータ実装 |
| 3-2 | ExecutionContextFactory.php | `src/Symfony/Component/Validator/Context/ExecutionContextFactory.php` | 実行コンテキストファクトリ |

#### Step 4: メタデータとローダーを理解する

制約メタデータの読み込みの仕組みを確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | LazyLoadingMetadataFactory.php | `src/Symfony/Component/Validator/Mapping/Factory/LazyLoadingMetadataFactory.php` | メタデータの遅延ロードとキャッシュ |
| 4-2 | AttributeLoader.php | `src/Symfony/Component/Validator/Mapping/Loader/AttributeLoader.php` | PHPアトリビュートからの制約ロード |

#### Step 5: 組み込み制約を理解する

代表的な組み込み制約を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 5-1 | Constraints/ | `src/Symfony/Component/Validator/Constraints/` | 組み込み制約群（NotBlank, Length, Email等） |
| 5-2 | ConstraintValidatorFactory.php | `src/Symfony/Component/Validator/ConstraintValidatorFactory.php` | 制約バリデータのファクトリ |

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

```
Validation::createValidator()
    |
    +-- ValidatorBuilder::getValidator()
            |
            +-- RecursiveValidator (生成)
                    |
                    +-- validate()
                    |       |
                    |       +-- ExecutionContextFactory::createContext()
                    |       +-- LazyLoadingMetadataFactory::getMetadataFor()
                    |       |       +-- LoaderChain::loadClassMetadata()
                    |       |           +-- AttributeLoader::loadClassMetadata()
                    |       |           +-- YamlFileLoader::loadClassMetadata()
                    |       |           +-- XmlFileLoader::loadClassMetadata()
                    |       |
                    |       +-- ConstraintValidatorFactory::getInstance()
                    |       +-- ConstraintValidator::validate()
                    |       +-- ConstraintViolationList (結果蓄積)
                    |
                    +-- validateProperty()
                    +-- validatePropertyValue()
```

### データフロー図

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

検証対象値 ──────────> RecursiveValidator::validate()
                              |
制約メタデータ ────────> LazyLoadingMetadataFactory
(Attribute/YAML/XML)          |
                              v
                        グループ解決
                              |
                              v
                        制約ごとの検証
                        ConstraintValidator::validate()
                              |
                              v
                        ExecutionContext ─────────> ConstraintViolationList
                        (違反の蓄積)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| Validation.php | `src/Symfony/Component/Validator/Validation.php` | ソース | エントリーポイント |
| ValidatorBuilder.php | `src/Symfony/Component/Validator/ValidatorBuilder.php` | ソース | バリデータ構築 |
| Constraint.php | `src/Symfony/Component/Validator/Constraint.php` | ソース | 制約基底クラス |
| ConstraintValidator.php | `src/Symfony/Component/Validator/ConstraintValidator.php` | ソース | 制約バリデータ基底クラス |
| ConstraintViolation.php | `src/Symfony/Component/Validator/ConstraintViolation.php` | ソース | 制約違反データ |
| ConstraintViolationList.php | `src/Symfony/Component/Validator/ConstraintViolationList.php` | ソース | 制約違反リスト |
| ConstraintValidatorFactory.php | `src/Symfony/Component/Validator/ConstraintValidatorFactory.php` | ソース | バリデータファクトリ |
| Constraints/ | `src/Symfony/Component/Validator/Constraints/` | ソース | 組み込み制約群 |
| Mapping/ | `src/Symfony/Component/Validator/Mapping/` | ソース | メタデータマッピング |
| Context/ | `src/Symfony/Component/Validator/Context/` | ソース | 実行コンテキスト |
| DataCollector/ | `src/Symfony/Component/Validator/DataCollector/` | ソース | WebProfiler用データコレクター |
