# 機能設計書 32-Yaml

## 概要

本ドキュメントは、Symfony Yamlコンポーネントの機能設計を記述する。YamlコンポーネントはYAMLファイルの読み込み（パース）とPHP値からYAML文字列への出力（ダンプ）機能を提供する。

### 本機能の処理概要

YamlコンポーネントはYAML形式のテキストデータとPHPのネイティブデータ構造（配列、オブジェクト等）の間の相互変換を行う。YAML仕様に基づいたパーサーとダンパーを提供し、設定ファイルの読み書きを容易にする。

**業務上の目的・背景**：Symfonyフレームワークではサービス定義、ルーティング設定、バリデーション制約定義、翻訳ファイルなど、多くの設定ファイルにYAML形式を採用している。YamlコンポーネントはこれらYAML設定ファイルを正確にパースしてPHPの配列構造に変換し、フレームワーク全体の設定管理基盤として機能する。またPHPデータからYAMLへのダンプは、設定ファイルの自動生成やデバッグ出力に使用される。

**機能の利用シーン**：Symfonyアプリケーションのサービスコンテナ設定（services.yaml）、ルーティング定義（routes.yaml）、バリデーション設定、翻訳メッセージカタログの読み込み時に使用される。また、開発者がカスタム設定ファイルをYAML形式で記述し、アプリケーション内で読み込む場面でも利用される。CLIコマンドでの設定ダンプやデバッグ表示にも活用される。

**主要な処理内容**：
1. YAML文字列のパース（Yaml::parse / Parser::parse）：YAML文字列をPHP値に変換する
2. YAMLファイルのパース（Yaml::parseFile / Parser::parseFile）：YAMLファイルを読み込んでPHP値に変換する
3. PHPデータのダンプ（Yaml::dump / Dumper::dump）：PHP値をYAML文字列に変換する
4. インライン記法の処理（Inline クラス）：フロースタイル（インライン）YAMLの解析とダンプ
5. タグ付き値の処理（TaggedValue クラス）：YAMLのカスタムタグの処理
6. エスケープ処理（Escaper / Unescaper）：特殊文字のエスケープとアンエスケープ

**関連システム・外部連携**：Configコンポーネント（YamlFileLoader）、DependencyInjectionコンポーネント（サービス設定のロード）、Routingコンポーネント（ルート定義のロード）、Validatorコンポーネント（制約定義のロード）、Translationコンポーネント（翻訳カタログのロード）と連携する。

**権限による制御**：ファイルパース時のファイルシステムアクセス権限に依存する。YAML自体には権限制御の仕組みはない。

## 関連画面

本機能は設定ファイルの読み書き処理であり、直接関連する画面はない。

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | - | - | 画面関連なし |

## 機能種別

データ変換処理（YAML <-> PHP）

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| input (parse) | string | Yes | パース対象のYAML文字列 | 有効なUTF-8文字列であること |
| filename (parseFile) | string | Yes | パース対象のYAMLファイルパス | ファイルが存在し読み取り可能であること |
| flags (parse) | int | No | パース動作を制御するビットフラグ（PARSE_*定数の組み合わせ） | 有効なフラグ値 |
| input (dump) | mixed | Yes | ダンプ対象のPHP値 | - |
| inline (dump) | int | No | インラインYAMLに切り替えるネストレベル（デフォルト: 2） | 0以上の整数 |
| indent (dump) | int | No | インデントのスペース数（デフォルト: 4） | 1以上の整数 |
| flags (dump) | int | No | ダンプ動作を制御するビットフラグ（DUMP_*定数の組み合わせ） | 有効なフラグ値 |

### 入力データソース

- YAMLテキスト文字列（プログラムからの直接入力）
- YAMLファイル（ファイルシステムからの読み込み）
- PHPネイティブデータ構造（配列、オブジェクト等）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| パース結果 | mixed | YAML文字列をパースしたPHP値（配列、文字列、数値、null等） |
| ダンプ結果 | string | PHP値をYAML形式に変換した文字列 |

### 出力先

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

## 処理フロー

### 処理シーケンス

```
■ パース処理（parse/parseFile）
1. 入力の取得
   └─ parseFile: ファイル存在・読み取り可能チェック後、file_get_contentsで読み込み
2. UTF-8バリデーション
   └─ preg_matchでUTF-8の有効性を検証
3. BOM除去
   └─ UTF-8 BOMの除去
4. 行単位の解析
   ├─ コメント行のスキップ
   ├─ アンカー（&ref）とエイリアス（*ref）の処理
   ├─ ブロックスカラー（|, >）の処理
   ├─ マッピング（key: value）の解析
   ├─ シーケンス（- item）の解析
   └─ インライン記法（{}, []）の解析
5. 型変換と値の返却

■ ダンプ処理（dump）
1. フラグの検証
   └─ 相互排他フラグの検証（DUMP_NULL_AS_EMPTY + DUMP_NULL_AS_TILDE）
2. 再帰的なダンプ処理
   ├─ インラインレベル判定（inline <= 0でインライン出力）
   ├─ 配列のダンプ（マッピング/シーケンス判定）
   ├─ TaggedValueのダンプ
   ├─ マルチラインリテラルブロックの処理
   └─ オブジェクトのダンプ（DUMP_OBJECT_AS_MAP対応）
3. YAML文字列の返却
```

### フローチャート

```mermaid
flowchart TD
    A[Yaml::parse / parseFile] --> B{ファイル入力?}
    B -->|Yes| C[ファイル存在チェック]
    C --> D[ファイル読み込み]
    B -->|No| E[YAML文字列受取]
    D --> E
    E --> F[UTF-8バリデーション]
    F --> G[BOM除去]
    G --> H[行単位解析ループ]
    H --> I{行種別判定}
    I -->|コメント| H
    I -->|マッピング| J[key: value解析]
    I -->|シーケンス| K[リスト項目解析]
    I -->|ブロックスカラー| L[複数行テキスト解析]
    I -->|インライン| M[フロースタイル解析]
    J --> H
    K --> H
    L --> H
    M --> H
    H --> N[PHP値返却]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-32-01 | PARSE_EXCEPTION_ON_INVALID_TYPE | 不正な型を検出した場合に例外をスローする | フラグ指定時 |
| BR-32-02 | PARSE_OBJECT | YAMLオブジェクトタグ（!!php/object）をPHPオブジェクトに変換する | フラグ指定時 |
| BR-32-03 | PARSE_DATETIME | 日付文字列をDateTimeオブジェクトに変換する | フラグ指定時 |
| BR-32-04 | PARSE_CONSTANT | PHPの定数参照（!php/const）を解決する | フラグ指定時 |
| BR-32-05 | PARSE_CUSTOM_TAGS | カスタムタグをTaggedValueオブジェクトとして返す | フラグ指定時 |
| BR-32-06 | DUMP_MULTI_LINE_LITERAL_BLOCK | 改行を含む文字列をリテラルブロック（|）で出力する | フラグ指定時 |
| BR-32-07 | DUMP_NULL_AS_TILDE / DUMP_NULL_AS_EMPTY | null値の出力形式を制御する（~ または空文字列）。両方同時指定は不可 | フラグ指定時 |
| BR-32-08 | DUMP_COMPACT_NESTED_MAPPING | ネストされたマッピングをコンパクト形式で出力する | フラグ指定時 |

### 計算ロジック

特になし。

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

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

本機能はデータベース操作を行わない。

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

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

該当なし。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | ParseException | YAML構文エラー | YAML構文を修正する |
| - | ParseException | ファイルが存在しない | ファイルパスを確認する |
| - | ParseException | ファイルが読み取れない | ファイル権限を確認する |
| - | ParseException | 不正なUTF-8文字列 | 文字エンコーディングを修正する |
| - | InvalidArgumentException | インデントが1未満 | 1以上のインデント値を指定する |
| - | InvalidArgumentException | DUMP_NULL_AS_EMPTYとDUMP_NULL_AS_TILDEの同時指定 | どちらか一方のみ指定する |

### リトライ仕様

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

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

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

## パフォーマンス要件

- パーサーは行単位の逐次処理を行い、大量のYAMLデータも効率的に処理できる
- Dumperはインラインレベルの制御により、ネストの深いデータの出力を最適化できる
- Inline クラスはフロースタイル（インライン記法）の解析を高速に行う

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

- `PARSE_OBJECT`フラグを有効にすると、YAMLデータからPHPオブジェクトをデシリアライズできるため、信頼できないYAML入力に対しては使用しないこと
- `PARSE_CONSTANT`フラグも同様に、信頼できない入力では無効にすべき
- ファイルパースの際は、パスインジェクションに注意が必要

## 備考

- YamlコンポーネントはSymfonyの最も基本的なコンポーネントの一つであり、フレームワーク全体の設定基盤として広く使用されている
- YAML 1.2仕様の大部分をサポートしているが、完全準拠ではない
- `Yaml`クラスは便利なスタティックメソッド群を提供するファサードであり、内部でParser/Dumperインスタンスを生成している

---

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

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

### 推奨読解順序

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

まず、YAMLのタグ付き値とフラグ定数を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | Yaml.php | `src/Symfony/Component/Yaml/Yaml.php` | フラグ定数の定義（25-40行目）とファサードメソッド |
| 1-2 | TaggedValue.php | `src/Symfony/Component/Yaml/Tag/TaggedValue.php` | カスタムタグ付き値のデータクラス |

**読解のコツ**: フラグ定数はビットマスクで定義されており、`|`演算子で組み合わせて使用する。`PARSE_*`はパース時、`DUMP_*`はダンプ時に使用される。

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

Yamlクラスのスタティックメソッドがエントリーポイントである。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | Yaml.php | `src/Symfony/Component/Yaml/Yaml.php` | 3つのスタティックメソッド: parseFile, parse, dump |

**主要処理フロー**:
1. **55-60行目**: `parseFile()` - Parserインスタンスを生成してparseFileに委譲
2. **76-81行目**: `parse()` - Parserインスタンスを生成してparseに委譲
3. **94-99行目**: `dump()` - Dumperインスタンスを生成してdumpに委譲

#### Step 3: パーサーの処理を理解する

YAML文字列をPHP値に変換するパース処理の詳細を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | Parser.php | `src/Symfony/Component/Yaml/Parser.php` | メインのパーサー。行単位でYAMLを解析する |
| 3-2 | Inline.php | `src/Symfony/Component/Yaml/Inline.php` | インライン（フロースタイル）YAMLの解析 |

**主要処理フロー**:
- **50-67行目** (Parser.php): `parseFile()` - ファイル存在・読み取りチェック後、parse()に委譲
- **77-80行目** (Parser.php): `parse()` - UTF-8チェックを最初に行う
- **26-28行目** (Parser.php): 正規表現パターン定数（TAG_PATTERN, BLOCK_SCALAR_HEADER_PATTERN, REFERENCE_PATTERN）

#### Step 4: ダンパーの処理を理解する

PHP値からYAML文字列へのダンプ処理を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | Dumper.php | `src/Symfony/Component/Yaml/Dumper.php` | メインのダンパー。再帰的にPHP値をYAML文字列に変換する |

**主要処理フロー**:
- **28-33行目**: コンストラクタ。インデント値の設定と検証
- **43-50行目**: `dump()`メソッド。フラグ検証後、doDump()に委譲
- **52-145行目**: `doDump()`メソッド。再帰的にインライン/ブロック形式を判定して出力

#### Step 5: 補助クラスを理解する

エスケープ処理などの補助機能を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 5-1 | Escaper.php | `src/Symfony/Component/Yaml/Escaper.php` | YAML文字列のエスケープ処理 |
| 5-2 | Unescaper.php | `src/Symfony/Component/Yaml/Unescaper.php` | YAML文字列のアンエスケープ処理 |

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

```
Yaml::parse() / Yaml::parseFile()
    |
    +-- Parser::parse() / Parser::parseFile()
    |       |
    |       +-- Parser::parseBlock() [再帰]
    |       |       +-- Parser::parseMapping()
    |       |       +-- Parser::parseSequence()
    |       |       +-- Parser::parseBlockScalar()
    |       |
    |       +-- Inline::parse()
    |       |       +-- Inline::parseMapping()
    |       |       +-- Inline::parseSequence()
    |       |       +-- Inline::parseScalar()
    |       |
    |       +-- Unescaper::unescapeCharacter()
    |
Yaml::dump()
    |
    +-- Dumper::dump()
            |
            +-- Dumper::doDump() [再帰]
            |       +-- Inline::dump()
            |       |       +-- Escaper::requiresDoubleQuoting()
            |       |       +-- Escaper::requiresSingleQuoting()
            |       +-- Dumper::dumpTaggedValue()
            +-- Dumper::getBlockIndentationIndicator()
```

### データフロー図

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

YAML文字列 ──────────> Parser::parse()
                            |
                            v
                       行単位の解析
                       (マッピング/シーケンス/
                        スカラー/ブロック)
                            |
                            v
                       Inline::parse()  ──────────> PHP配列/値
                       (インライン記法)

PHP配列/値 ──────────> Dumper::dump()
                            |
                            v
                       再帰的なダンプ処理
                       (ブロック/インライン判定)
                            |
                            v
                       Inline::dump()  ──────────> YAML文字列
                       (スカラー値の出力)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| Yaml.php | `src/Symfony/Component/Yaml/Yaml.php` | ソース | ファサードクラス（スタティックメソッド群） |
| Parser.php | `src/Symfony/Component/Yaml/Parser.php` | ソース | YAMLパーサー本体 |
| Dumper.php | `src/Symfony/Component/Yaml/Dumper.php` | ソース | YAMLダンパー本体 |
| Inline.php | `src/Symfony/Component/Yaml/Inline.php` | ソース | インライン（フロースタイル）YAML処理 |
| Escaper.php | `src/Symfony/Component/Yaml/Escaper.php` | ソース | YAML文字列のエスケープ処理 |
| Unescaper.php | `src/Symfony/Component/Yaml/Unescaper.php` | ソース | YAML文字列のアンエスケープ処理 |
| TaggedValue.php | `src/Symfony/Component/Yaml/Tag/TaggedValue.php` | ソース | カスタムタグ付き値のデータクラス |
| ParseException.php | `src/Symfony/Component/Yaml/Exception/ParseException.php` | ソース | パース例外 |
| LintCommand.php | `src/Symfony/Component/Yaml/Command/LintCommand.php` | ソース | YAMLリントCLIコマンド |
