# 帳票設計書 29-コンパイル済みURLマッチャーダンプ

## 概要

本ドキュメントは、Symfony Routingコンポーネントにおける `CompiledUrlMatcherDumper` クラスの帳票設計書である。ルーティング定義をコンパイル済みPHP配列として出力し、URLマッチングの高速化に使用される機能について、出力仕様・処理フロー・データ構造を定義する。

### 本帳票の処理概要

`CompiledUrlMatcherDumper` は、RouteCollectionに登録されたルーティング定義を、CompiledUrlMatcherが使用可能な最適化されたPHP配列としてダンプするクラスである。静的ルートと動的ルートを分離し、動的ルートにはツリー構造の正規表現を生成することで、URLマッチングのパフォーマンスを最大化する。

**業務上の目的・背景**：Symfonyアプリケーションでは数百〜数千のルーティング定義が存在する場合がある。リクエストごとにYAML/XMLの設定ファイルを解析してルーティングマッチングを行うのは非効率である。CompiledUrlMatcherDumperは、ルーティング定義を事前にコンパイルしてPHPファイルとして出力し、本番環境でのルーティングマッチングを高速化する。

**帳票の利用シーン**：キャッシュのウォームアップ時（`cache:warmup`コマンド）、ルーティングキャッシュの再構築時に自動的に実行される。

**主要な出力内容**：
1. ホストマッチングフラグ（$matchHost）
2. 静的ルートの連想配列（$staticRoutes）
3. 動的ルートの正規表現リスト（$regexpList）
4. 動的ルートの詳細配列（$dynamicRoutes）
5. 条件チェック関数（$checkCondition）

**帳票の出力タイミング**：`cache:warmup` コマンド実行時、ルーティングキャッシュが無効な状態での初回リクエスト時にダンプが生成される。

**帳票の利用者**：Symfony Router（内部利用）、アプリケーション実行環境

## 帳票種別

コンパイル済み設定ファイル（PHP配列出力）

## 利用画面

| 画面No | 画面名 | URL/ルーティング | 出力操作 |
|--------|--------|-----------------|---------|
| - | CLIコマンド | `php bin/console cache:warmup` | 自動生成 |
| - | 初回リクエスト | 任意のURL | 自動生成（キャッシュミス時） |

## 出力形式

### 基本仕様

| 項目 | 内容 |
|-----|------|
| ファイル形式 | PHP（配列を返すPHPファイル） |
| 用紙サイズ | N/A |
| 向き | N/A |
| ファイル名 | `var/cache/{env}/url_matching_routes.php`（環境依存） |
| 出力方法 | ファイル書き込み |
| 文字コード | UTF-8 |

### PDF固有設定

該当なし

### Excel固有設定

該当なし

## 帳票レイアウト

### レイアウト概要

PHPファイルとしてreturn文で配列を返す形式。5つの要素からなる配列構造。

```
┌─────────────────────────────────────┐
│  <?php                               │
│                                      │
│  /**                                 │
│   * Auto-generated by Symfony        │
│   * Routing Component                │
│   */                                 │
│                                      │
│  return [                            │
│    false, // $matchHost              │
│    [ // $staticRoutes                │
│      '/path' => [[...], ...],        │
│    ],                                │
│    [ // $regexpList                  │
│      0 => '...',                     │
│    ],                                │
│    [ // $dynamicRoutes               │
│      42 => [[...], ...],             │
│    ],                                │
│    null, // $checkCondition          │
│  ];                                  │
└─────────────────────────────────────┘
```

### ヘッダー部

| No | 項目名 | 説明 | データ取得元 | 表示形式 |
|----|-------|------|-------------|---------|
| 1 | PHPタグ | PHPファイル開始 | 固定 | `<?php` |
| 2 | 自動生成コメント | 生成元情報 | 固定テンプレート | PHPコメント |
| 3 | matchHost | ホストマッチングの要否 | ルート定義のホスト設定有無 | `true` / `false` |

### 明細部

| No | 項目名 | 説明 | データ取得元 | 表示形式 | 列幅 |
|----|-------|------|-------------|---------|-----|
| 1 | 静的ルート | パス変数なしのルート | `groupStaticRoutes()` | URLパス => ルート配列 | 可変 |
| 2 | 正規表現リスト | 動的ルートマッチング正規表現 | `compileDynamicRoutes()` | マーク位置 => 正規表現文字列 | 可変 |
| 3 | 動的ルート | パス変数ありのルート | `compileDynamicRoutes()` | マーク位置 => ルート配列 | 可変 |
| 4 | 各ルート配列 | ルートのコンパイル結果 | `compileRoute()` | `[defaults, vars, methods, schemes, hasTrailingSlash, hasTrailingVar, condition]` | 7要素 |

### フッター部

| No | 項目名 | 説明 | データ取得元 | 表示形式 |
|----|-------|------|-------------|---------|
| 1 | checkCondition | ルート条件チェック関数 | ExpressionLanguageコンパイル結果 | PHP callable / null |

## 出力条件

### 抽出条件

| 条件名 | 説明 | 必須 |
|-------|------|-----|
| RouteCollection | ルーティング定義コレクション | Yes（コンストラクタ注入） |
| ExpressionLanguageProviders | 条件式プロバイダー | No |

### ソート順

| 優先度 | 項目 | 昇順/降順 |
|-------|------|---------|
| 1 | 静的ルート | URLパス順 |
| 2 | 動的ルート | 同一接頭辞によるツリー構造でグループ化 |

### 改ページ条件

該当なし

## データベース参照仕様

### 参照テーブル一覧

該当なし

### テーブル別参照項目詳細

該当なし

## 計算仕様

### 計算項目一覧

| 項目名 | 計算式 | 端数処理 | 備考 |
|-------|-------|---------|------|
| ホスト正規表現 | `'/'.strtr(strrev($host), '}.{', '(/)')` | なし | ホストを逆順にして正規表現用に変換 |
| trailing slash判定 | 正規表現末尾の`$`前が`/`か | なし | URLの末尾スラッシュ処理 |
| 正規表現チャンクサイズ | `1 + ($chunkLimit >> 1)` | なし | 正規表現サイズ超過時に自動分割 |
| 条件式コンパイル | `ExpressionLanguage::compile($condition, ['context', 'request', 'params'])` | なし | ルート条件のPHPコード化 |

## 処理フロー

### 出力フロー

```mermaid
flowchart TD
    A[dump呼び出し] --> B[getCompiledRoutes forDump=true]
    B --> C[ホストマッチング判定]
    C --> D[groupStaticRoutes: 静的/動的分離]
    D --> E[compileStaticRoutes: 静的ルートコンパイル]
    E --> F[compileDynamicRoutes: 動的ルートコンパイル]
    F --> G{正規表現サイズ超過?}
    G -->|Yes| H[チャンクサイズ縮小して再試行]
    G -->|No| I[条件式コンパイル]
    H --> F
    I --> J[generateCompiledRoutes: PHPコード生成]
    J --> K[PHPファイルテンプレートに埋め込み]
    K --> L[PHP文字列返却]
```

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 表示メッセージ | 対処方法 |
|----------|---------|--------------|---------|
| 正規表現サイズ超過 | 動的ルートが非常に多い場合 | `Compilation failed: regular expression is too large` | 自動的にチャンクサイズを縮小して再試行 |
| ExpressionLanguage未インストール | 条件式使用時にコンポーネント未導入 | `Unable to use expressions as the Symfony ExpressionLanguage component is not installed.` | `composer require symfony/expression-language` |
| ルートにオブジェクト含有 | ルートデフォルト値にオブジェクト | `Route cannot contain objects, but "{type}" given.` | スカラー値のみ使用 |

## パフォーマンス要件

| 項目 | 内容 |
|-----|------|
| 想定データ件数 | 数百〜数千ルート |
| 目標出力時間 | 数秒以内（キャッシュウォームアップ時の1回実行） |
| 同時出力数上限 | 1（キャッシュ生成は排他的） |

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

- 生成されるPHPファイルはeval/includeで実行されるため、キャッシュディレクトリの書き込み権限を適切に管理すること
- 条件式（ExpressionLanguage）はコンパイルされたPHPコードとして実行される
- キャッシュファイルにルーティング定義のデフォルト値が含まれる

## 備考

- `StaticPrefixCollection` を使用して同一接頭辞のルートをグループ化し、正規表現の効率を最大化
- 正規表現の名前付きサブパターン（`(*:mark)`）でマッチしたルートを特定
- `(*F)` によるバックリスティング（マッチ失敗の強制）で、条件不一致時の再マッチを実現
- Unicode/非Unicode正規表現の混在を避けるため、修飾子ごとにチャンクを分割
- `export()` 静的メソッドは他のDumper（CompiledUrlGeneratorDumper）からも参照される

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | RouteCollection.php | `src/Symfony/Component/Routing/RouteCollection.php` | ルーティング定義のコレクション。all()で全ルート取得 |
| 1-2 | Route.php | `src/Symfony/Component/Routing/Route.php` | 個別ルート定義。getPath(), getHost(), getMethods(), getSchemes(), getDefaults(), getCondition() |
| 1-3 | CompiledRoute.php | `src/Symfony/Component/Routing/CompiledRoute.php` | コンパイル済みルート。getRegex(), getStaticPrefix(), getPathVariables(), getHostVariables() |

**読解のコツ**: Route::compile()がCompiledRouteを返す。正規表現やパス変数はこのコンパイル結果から取得される。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | CompiledUrlMatcherDumper.php | `src/Symfony/Component/Routing/Matcher/Dumper/CompiledUrlMatcherDumper.php` | dump()（37-51行目）、getCompiledRoutes()（61-127行目） |
| 2-2 | MatcherDumper.php | `src/Symfony/Component/Routing/Matcher/Dumper/MatcherDumper.php` | 基底クラス。RouteCollectionの保持 |

**主要処理フロー**:
1. **37行目**: `dump()` - PHPファイルテンプレートに`generateCompiledRoutes()`の結果を埋め込み
2. **61行目**: `getCompiledRoutes()` - メインコンパイルロジック
3. **66行目**: ホストマッチング判定（ルートにホスト設定があるか）
4. **83行目**: `groupStaticRoutes()` - 静的/動的ルートの分離
5. **86行目**: `compileStaticRoutes()` - 静的ルートのコンパイル
6. **89-102行目**: `compileDynamicRoutes()` - 動的ルートのコンパイル（チャンクサイズ自動調整付き）

#### Step 3: コンパイル詳細を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | CompiledUrlMatcherDumper.php | `src/Symfony/Component/Routing/Matcher/Dumper/CompiledUrlMatcherDumper.php` | groupStaticRoutes()（164-202行目）、compileDynamicRoutes()（252-368行目）、compileRoute()（421-446行目） |

**主要処理フロー**:
- **164-202行目**: `groupStaticRoutes()` - パス変数なしのルートを静的、ありを動的に分類
- **212-232行目**: `compileStaticRoutes()` - 静的ルートのコンパイル
- **252-368行目**: `compileDynamicRoutes()` - ツリー構造正規表現の生成、`StaticPrefixCollection` による接頭辞グループ化
- **376-416行目**: `compileStaticPrefixCollection()` - 再帰的な正規表現ツリー構築
- **421-446行目**: `compileRoute()` - 個別ルートの配列化（defaults, vars, methods, schemes, trailingSlash, trailingVar, condition）

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

```
CompiledUrlMatcherDumper::dump()
    |
    +-- getCompiledRoutes(forDump=true)
    |       |
    |       +-- RouteCollection::all()
    |       +-- groupStaticRoutes(RouteCollection)
    |       |       +-- Route::compile() --> CompiledRoute
    |       |       +-- 静的ルート / 動的ルート分離
    |       |
    |       +-- compileStaticRoutes(staticRoutes)
    |       |       +-- compileRoute(Route, ...)
    |       |
    |       +-- compileDynamicRoutes(dynamicRoutes, matchHost, chunkLimit)
    |       |       +-- StaticPrefixCollection::addRoute()
    |       |       +-- compileStaticPrefixCollection(tree, state) [再帰]
    |       |       |       +-- compileRoute(Route, ...)
    |       |       +-- preg_match() [正規表現サイズ検証]
    |       |
    |       +-- [条件式] ExpressionLanguage::compile()
    |
    +-- generateCompiledRoutes()
            +-- export() [値のPHPエクスポート]
```

### データフロー図

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

RouteCollection -----> groupStaticRoutes()
                          |
                    +-----+-----+
                    |           |
              静的ルート    動的ルート
                    |           |
                    v           v
            compileStatic   compileDynamic
            Routes()        Routes()
                    |           |
                    v           v
              [url=>routes]  [regexpList, routes]
                    |           |
                    +-----+-----+
                          |
                          v
                 generateCompiledRoutes()
                          |
                          v
                 PHP配列文字列 -----> var/cache/{env}/url_matching_routes.php
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| CompiledUrlMatcherDumper.php | `src/Symfony/Component/Routing/Matcher/Dumper/CompiledUrlMatcherDumper.php` | ソース | メインクラス（502行） |
| MatcherDumper.php | `src/Symfony/Component/Routing/Matcher/Dumper/MatcherDumper.php` | ソース | 基底クラス（32行） |
| MatcherDumperInterface.php | `src/Symfony/Component/Routing/Matcher/Dumper/MatcherDumperInterface.php` | ソース | インターフェース |
| StaticPrefixCollection.php | `src/Symfony/Component/Routing/Matcher/Dumper/StaticPrefixCollection.php` | ソース | 接頭辞ツリー |
| CompiledUrlMatcher.php | `src/Symfony/Component/Routing/Matcher/CompiledUrlMatcher.php` | ソース | ダンプ結果の利用クラス |
| RouteCollection.php | `src/Symfony/Component/Routing/RouteCollection.php` | ソース | ルーティング定義コレクション |
| Route.php | `src/Symfony/Component/Routing/Route.php` | ソース | 個別ルート定義 |
| CompiledRoute.php | `src/Symfony/Component/Routing/CompiledRoute.php` | ソース | コンパイル済みルート |
