# 画面設計書 2-プロファイラーパネル

## 概要

本ドキュメントは、Symfony WebProfilerBundleが提供する「プロファイラーパネル」画面の設計書である。本画面は指定されたプロファイルトークンに対応するプロファイリングデータを、コレクターに応じた動的パネルテンプレートでレンダリングして表示する、プロファイラーの中核的な画面である。

### 本画面の処理概要

本画面は、Symfonyアプリケーションの各リクエストまたはコマンドの実行情報を、データコレクターごとに分類されたパネル形式で詳細表示する画面である。

**業務上の目的・背景**：Webアプリケーション開発において、個々のHTTPリクエストやコンソールコマンドの詳細情報（パフォーマンス、メモリ使用量、ログ、例外情報など）を調査する必要がある。本画面はプロファイラーに蓄積されたデータを、コレクター（データ収集器）ごとに整理されたパネル形式で提示し、開発者が効率的にデバッグやパフォーマンス分析を行えるようにする。サイドバーにはコレクター一覧が表示され、パネルを切り替えながら各種情報を閲覧できる。

**画面へのアクセス方法**：
- Webデバッグツールバーからのクリック（`/_profiler/{token}`）
- プロファイラー検索結果画面からトークンを選択
- URLに直接トークンを指定してアクセス（`/_profiler/{token}?panel={panel_name}`）
- `latest`をトークンとして指定すると最新のプロファイルが表示される

**主要な操作・処理内容**：
1. 指定されたトークンのプロファイルデータをProfilerサービスから読み込む
2. `latest`トークンの場合、最新のプロファイルのトークンに置換する
3. プロファイルが見つからない場合、情報画面（info.html.twig）を表示する
4. パネル指定がない場合、プロファイルタイプに基づくデフォルトパネルを選択（例外がある場合はexceptionパネル、dumpデータがある場合はdumpパネルを優先表示）
5. TemplateManagerを使用して対象パネルのテンプレート名を解決し、レンダリングする
6. サイドバーにコレクター一覧を表示し、パネル切り替えを可能にする
7. 設定モーダル（テーマ・ページ幅）をサイドバーに含める

**画面遷移**：
- 遷移元：Webデバッグツールバー（No.12）、プロファイラー検索結果（No.5）、プロファイラー検索（No.3 - トークン指定時）
- 遷移先：ソースファイル表示（No.7）、PHP情報表示（No.8）、Xdebug情報表示（No.9）、プロファイラー設定（No.10 - モーダル）、プロファイラー情報（No.6 - トークン不明時）、各コレクターパネル（No.14-37）

**権限による表示制御**：プロファイラーが有効な環境でのみ動作する。プロファイルタイプ（`request`/`command`）によりサイドバーに表示されるコレクター一覧がフィルタリングされる（`request`タイプの場合は`command`を除外、`command`タイプの場合は`request`と`router`を除外）。

## 関連機能

| 機能No | 機能名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 63 | WebProfilerBundle | 主機能 | ProfilerController::panelActionによるプロファイラーパネルの動的テンプレートレンダリング |
| 2 | HttpKernel | 主機能 | Profilerサービスによるプロファイルデータの読み込みとDataCollectorの取得 |
| 35 | TwigBundle | 補助機能 | Twig Environmentによるレイアウトテンプレートおよびパネルテンプレートのレンダリング |
| 1 | HttpFoundation | 補助機能 | Requestオブジェクトからのクエリパラメータ取得とResponseの生成 |

## 画面種別

詳細（動的パネル表示）

## URL/ルーティング

| 項目 | 値 |
|------|-----|
| ルート名 | `_profiler` |
| URLパターン | `/_profiler/{token}` |
| HTTPメソッド | GET |
| コントローラー | `web_profiler.controller.profiler::panelAction` |

## 入出力項目

### 入力（URLパラメータ・クエリパラメータ）

| 項目名 | 入出力 | 型 | 必須 | 説明 |
|--------|--------|-----|------|------|
| token | 入力（URLパス） | string | はい | プロファイルトークン。`latest`指定で最新プロファイル |
| panel | 入力（クエリ） | string | いいえ | 表示するパネル名（例: `request`, `exception`）。未指定時は自動選択 |
| page | 入力（クエリ） | string | いいえ | ページ種別（デフォルト: `home`） |
| type | 入力（クエリ） | string | いいえ | プロファイルタイプ（デフォルト: `request`）。`request`または`command` |

## 表示項目

### レイアウト構成

| 領域 | 表示内容 | テンプレート |
|------|---------|-------------|
| ヘッダー | Symfonyロゴ、プロファイラーホームリンク、Symfony.com検索フォーム | header.html.twig |
| サマリー | プロファイルタイプに応じたリクエスト/コマンドのサマリー情報（ステータスコード、URL/コマンド名等） | _request_summary.html.twig / _command_summary.html.twig |
| サイドバー | Search profilesリンク、Latestリンク、コレクターパネル一覧（メニュー）、設定リンク | layout.html.twig, settings.html.twig |
| コンテンツ | 選択されたコレクターパネルの詳細内容 | 動的（各コレクターのテンプレート） |

### サイドバーメニュー項目

| 項目 | 説明 |
|------|------|
| Search profiles | 検索画面へのリンク |
| Latest | 最新プロファイルへのリンク |
| コレクターメニュー | 各DataCollectorに対応するパネルメニュー（動的生成） |
| Profiler settings | テーマ・ページ幅設定モーダルの開閉リンク |

## イベント仕様

### 1-パネル表示

1. URLパスからtokenパラメータを取得
2. `latest`トークンの場合、`Profiler::find()`で最新トークンを検索し置換
3. `Profiler::loadProfile()`でプロファイルデータを読み込み
4. プロファイルが見つからない場合、info.html.twigでエラー情報を表示
5. panelパラメータ未指定時、デフォルトパネルを自動決定（例外あり→exception、dumpあり→dump、それ以外→プロファイルタイプ名）
6. `TemplateManager::getName()`でパネルのテンプレート名を解決
7. テンプレートをレンダリングしてレスポンスを返却

### 2-サイドバーパネル切り替え

サイドバーのコレクターメニュー項目をクリックすると、`/_profiler/{token}?panel={panel_name}&type={profile_type}`へ遷移し、対応するパネルのコンテンツが表示される。

### 3-設定モーダル表示

サイドバー下部の「Profiler settings」リンクをクリックすると、テーマ設定・ページ幅設定のモーダルが表示される（JavaScript制御、画面遷移なし）。

## データベース更新仕様

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

| 操作（イベント） | 対象テーブル | 操作種別 | 概要 |
|----------------|-------------|---------|------|
| パネル表示 | なし（ファイルベース） | SELECT | Profilerサービスがファイルシステムからプロファイルデータを読み込む |

## メッセージ仕様

| メッセージID | 種別 | メッセージ内容 | 表示条件 |
|-------------|------|--------------|----------|
| no_token_error | エラー | 'Token "{token}" not found.' | プロファイルが見つからない場合（info.html.twigで表示） |
| no_profiles | エラー | 'No profiles found.' | latestトークン指定時にプロファイルが存在しない場合 |
| panel_not_found | エラー | 'Panel "{panel}" is not available for token "{token}".' | 指定パネルがプロファイルに存在しない場合（NotFoundHttpException） |
| profiler_disabled | エラー | 'The profiler must be enabled.' | プロファイラーが無効な場合（NotFoundHttpException） |

## 例外処理

| 例外クラス | 発生条件 | ユーザーへの影響 |
|-----------|---------|----------------|
| `NotFoundHttpException` | プロファイラーが無効な場合 | HTTP 404エラーページが表示される |
| `NotFoundHttpException` | 指定パネルがプロファイルに存在しない場合 | HTTP 404エラーページが表示される |

## 備考

- CSP（Content Security Policy）のnonce処理が`renderWithCspNonces`メソッドで行われ、スクリプトとスタイルのnonceがテンプレートに渡される
- `profiler_markup_version`は3が設定されており、Symfony 6.2以降のプロファイラーUI形式である
- Ajaxリクエスト（`X-Requested-With: XMLHttpRequest`）の場合は`is_ajax`フラグがtrueになり、レイアウトが調整される
- `TemplateManager`はコレクターに対応するテンプレートの存在確認と名前解決を担当する

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | profiler.php | `src/Symfony/Bundle/WebProfilerBundle/Resources/config/routing/profiler.php` | `_profiler`ルート（39行目）のURLパターン`/{token}`を確認 |
| 1-2 | TemplateManager.php | `src/Symfony/Bundle/WebProfilerBundle/Profiler/TemplateManager.php` | テンプレート名解決ロジック（`getName`/`getNames`メソッド、39-83行目） |

**読解のコツ**: TemplateManagerは登録済みのコレクターテンプレート一覧からプロファイルに実際に存在するコレクターのテンプレートのみをフィルタリングして返す。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | ProfilerController.php | `src/Symfony/Bundle/WebProfilerBundle/Controller/ProfilerController.php` | `panelAction`メソッド（65-117行目）がエントリーポイント。トークン解決、プロファイル読み込み、パネル自動選択、テンプレートレンダリングの一連の流れを把握する |

**主要処理フロー**:
1. **67行目**: プロファイラー有効性の確認
2. **69行目**: CSPハンドラーによるCSP無効化
3. **71-73行目**: クエリパラメータの取得（panel, page, type）
4. **75-77行目**: `latest`トークンの最新プロファイルへの置換
5. **79-81行目**: プロファイルの読み込み（見つからない場合はinfo画面を表示）
6. **85-98行目**: パネル未指定時のデフォルトパネル自動選択（例外→dump→プロファイルタイプ）
7. **101-103行目**: パネル存在確認（ない場合はNotFoundHttpException）
8. **105-117行目**: テンプレートのレンダリングとレスポンス返却

#### Step 3: レイアウトテンプレートを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | layout.html.twig | `src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/layout.html.twig` | プロファイラー画面の共通レイアウト。ヘッダー、サマリー、サイドバー（コレクターメニュー）、コンテンツ領域の構成を把握する |
| 3-2 | base.html.twig | `src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/base.html.twig` | HTML基盤テンプレート。テーマ切り替えのJavaScript、CSP nonce対応を確認 |
| 3-3 | header.html.twig | `src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/header.html.twig` | ヘッダー部分のテンプレート |
| 3-4 | settings.html.twig | `src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/settings.html.twig` | テーマ・ページ幅設定モーダルのテンプレート |

**主要処理フロー**:
- **layout.html.twig 5行目**: ヘッダーのインクルード
- **layout.html.twig 12行目**: プロファイルタイプに応じたサマリーテンプレートの動的インクルード
- **layout.html.twig 38-59行目**: コレクターメニューの動的生成（テンプレートのmenuブロックを使用）
- **layout.html.twig 63行目**: 設定モーダルのインクルード

#### Step 4: CSP処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | ProfilerController.php | `src/Symfony/Bundle/WebProfilerBundle/Controller/ProfilerController.php` | `renderWithCspNonces`メソッド（419-431行目）でCSP nonceをテンプレート変数に追加する処理 |

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

```
ProfilerController::panelAction($request, $token)
    |
    +-- denyAccessIfProfilerDisabled()
    |       +-- Profiler::disable()
    |
    +-- ContentSecurityPolicyHandler::disableCsp()
    |
    +-- Profiler::find() [latestトークン時のみ]
    |
    +-- Profiler::loadProfile($token)
    |       +-- [見つからない場合] renderWithCspNonces(info.html.twig)
    |
    +-- ExceptionDataCollector::hasException() [パネル自動選択]
    +-- DumpDataCollector::getDumpsCount() [パネル自動選択]
    |
    +-- TemplateManager::getName($profile, $panel)
    |       +-- TemplateManager::getNames($profile)
    |
    +-- renderWithCspNonces($request, $template, $variables)
            +-- ContentSecurityPolicyHandler::getNonces()
            +-- Environment::render($template, $variables)
```

### データフロー図

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

HTTPリクエスト       --> ProfilerController           --> HTMLレスポンス
(GET /_profiler/{token}) ::panelAction()                  (layout.html.twig +
                              |                            動的パネルテンプレート)
    token (URL)         +-- Profiler::loadProfile()
    panel (query)       +-- TemplateManager::getName()
    page (query)        +-- Twig::render()
    type (query)             |
                             +-- CSP nonces
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| ProfilerController.php | `src/Symfony/Bundle/WebProfilerBundle/Controller/ProfilerController.php` | ソース | panelActionメソッドを含むコントローラー |
| TemplateManager.php | `src/Symfony/Bundle/WebProfilerBundle/Profiler/TemplateManager.php` | ソース | パネルテンプレートの名前解決 |
| ContentSecurityPolicyHandler.php | `src/Symfony/Bundle/WebProfilerBundle/Csp/ContentSecurityPolicyHandler.php` | ソース | CSP nonce処理 |
| layout.html.twig | `src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/layout.html.twig` | テンプレート | プロファイラー画面の共通レイアウト |
| base.html.twig | `src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/base.html.twig` | テンプレート | HTML基盤テンプレート |
| header.html.twig | `src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/header.html.twig` | テンプレート | ヘッダー部分 |
| settings.html.twig | `src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/settings.html.twig` | テンプレート | 設定モーダル |
| info.html.twig | `src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/info.html.twig` | テンプレート | トークン不明時の情報表示 |
| profiler.php | `src/Symfony/Bundle/WebProfilerBundle/Resources/config/routing/profiler.php` | 設定 | ルーティング定義 |
