# 画面設計書 5-プロファイラー検索結果

## 概要

本ドキュメントは、Symfony WebProfilerBundleが提供する「プロファイラー検索結果」画面の設計書である。本画面はプロファイラーの検索結果一覧を表示し、各プロファイルへのアクセスや追加検索を可能にする画面である。

### 本画面の処理概要

本画面は、プロファイリングデータの検索結果をテーブル形式で一覧表示し、開発者が各プロファイルの詳細パネルにアクセスできるようにする画面である。

**業務上の目的・背景**：開発者がアプリケーションの過去のリクエストやコマンド実行を一覧形式で把握し、特定のリクエストのプロファイルデータに素早くアクセスできるようにすることが目的である。HTTPリクエストとコンソールコマンドの検索結果をタブで切り替えて表示でき、各結果行からプロファイラーパネルへ遷移してデバッグ情報を確認できる。検索結果の各列（IP、メソッド、URL）からさらに絞り込み検索も可能である。

**画面へのアクセス方法**：
- プロファイラーホーム（No.1）からのリダイレクト
- プロファイラー検索（No.3）からのリダイレクト
- URLに直接アクセス（`/_profiler/{token}/search/results`）

**主要な操作・処理内容**：
1. URLパスのtokenパラメータとクエリパラメータから検索条件を取得
2. Profiler::loadProfile()でトークンに対応するプロファイルを読み込み（サイドバー情報用）
3. Profiler::find()で検索条件に合致するプロファイルトークン一覧を取得（profile_typeフィルタリング付き）
4. レイアウトテンプレート（layout.html.twig）を継承したresults.html.twigをレンダリング
5. サイドバーに検索バー（No.4）を埋め込みレンダリング
6. HTTP Requests/Console Commandsのタブ切り替え
7. 結果テーブルにステータスコード、IP、メソッド、URL、日時、トークンを表示
8. 各結果行のIP、メソッド、URLに検索フィルターリンクを付与

**画面遷移**：
- 遷移元：プロファイラーホーム（No.1）、プロファイラー検索（No.3）
- 遷移先：プロファイラーパネル（No.2 - トークンリンク）、プロファイラー検索（No.3 - フィルターリンク）

**権限による表示制御**：プロファイラーが有効な環境でのみ動作する。プロファイルタイプ（request/command）に応じてテーブルのカラムラベルが動的に変化する。

## 関連機能

| 機能No | 機能名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 63 | WebProfilerBundle | 主機能 | ProfilerController::searchResultsActionによる検索結果一覧の表示 |
| 2 | HttpKernel | 主機能 | Profilerサービスによるプロファイルデータの検索・読み込み |
| 35 | TwigBundle | 補助機能 | Twig Environmentによるresults.html.twigテンプレートのレンダリング |

## 画面種別

一覧

## URL/ルーティング

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

## 入出力項目

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

| 項目名 | 入出力 | 型 | 必須 | 説明 |
|--------|--------|-----|------|------|
| token | 入力（URLパス） | string | はい | プロファイルトークン（`empty`で空検索） |
| ip | 入力（クエリ） | string | いいえ | IPアドレスフィルター |
| method | 入力（クエリ） | string | いいえ | HTTPメソッドフィルター |
| status_code | 入力（クエリ） | string | いいえ | ステータスコードフィルター |
| url | 入力（クエリ） | string | いいえ | URLフィルター |
| start | 入力（クエリ） | string | いいえ | 開始日フィルター |
| end | 入力（クエリ） | string | いいえ | 終了日フィルター |
| limit | 入力（クエリ） | string | いいえ | 結果件数上限 |
| type | 入力（クエリ） | string | いいえ | プロファイルタイプ（デフォルト: `request`） |

## 表示項目

### タブナビゲーション

| タブ名 | リンク先 | 説明 |
|--------|---------|------|
| HTTP Requests | `_profiler_search_results`（token=empty, limit=10） | HTTPリクエストの検索結果 |
| Console Commands | `_profiler_search_results`（token=empty, limit=10, type=command） | コンソールコマンドの検索結果 |

### 検索結果テーブル

| カラム | requestタイプ表示 | commandタイプ表示 | 説明 |
|--------|------------------|------------------|------|
| Status/Exit code | ステータスコード（ラベル付き） | 終了コード（ラベル付き） | 色分け: 成功=緑、警告=黄、エラー=赤 |
| IP/Application | IPアドレス + 検索リンク | Application名 + 検索リンク | フィルター検索可能 |
| Method/Mode | HTTPメソッド + 検索リンク | コマンドモード + 検索リンク | フィルター検索可能 |
| URL/Command | URL + 検索リンク | コマンド名 + 検索リンク | フィルター検索可能 |
| Time | 日時（ユーザータイムゾーン変換対応） | 同左 | date + time の2行表示 |
| Token | トークン（プロファイラーパネルへのリンク） | 同左 | クリックでNo.2へ遷移 |

### ステータスコードの色分けルール

| プロファイルタイプ | 条件 | CSSクラス | 表示色 |
|------------------|------|-----------|--------|
| request | status_code > 399 | status-error | 赤 |
| request | status_code > 299 | status-warning | 黄 |
| request | それ以外 | status-success | 緑 |
| command | exit_code == 113 | status-warning | 黄 |
| command | exit_code > 0 | status-error | 赤 |
| command | exit_code == 0 | status-success | 緑 |

### サイドバー

| 要素 | 説明 |
|------|------|
| Search profilesリンク | 検索画面へのリンク |
| Latestリンク | 最新プロファイルへのリンク |
| 検索バー | No.4のsearchBarActionを埋め込みレンダリング |

## イベント仕様

### 1-検索結果表示

1. `denyAccessIfProfilerDisabled()`でプロファイラー有効性を確認
2. CSPを無効化
3. Profiler::loadProfile()でトークンに対応するプロファイルを読み込み
4. クエリパラメータから検索条件を取得
5. Profiler::find()で検索実行（virtual_typeフィルタリング付き）
6. results.html.twigをレンダリング

### 2-タブ切り替え

HTTP Requests / Console Commands タブをクリックすると、typeパラメータを切り替えた`_profiler_search_results`ルートへ遷移する。

### 3-フィルター検索

検索結果テーブルの各行のIP、メソッド、URL列に表示される検索アイコンをクリックすると、その値をフィルター条件としたリクエストが`_profiler_search_results`ルートに送信される。

### 4-プロファイル詳細表示

トークン列のリンクをクリックすると、`_profiler`ルート（`/_profiler/{token}`）へ遷移し、プロファイラーパネル（No.2）が表示される。

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

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

| 操作（イベント） | 対象テーブル | 操作種別 | 概要 |
|----------------|-------------|---------|------|
| 検索結果表示 | なし（ファイルベース） | SELECT | Profilerサービスがファイルシステムからプロファイルデータを検索する |

## メッセージ仕様

| メッセージID | 種別 | メッセージ内容 | 表示条件 |
|-------------|------|--------------|----------|
| result_count | 情報 | "{N} results found" | 検索結果がある場合 |
| no_results | 情報 | "No results found" | 検索結果がない場合 |
| empty_panel | 情報 | "The query returned no result." | 検索結果が空の場合のパネル内メッセージ |

## 例外処理

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

## 備考

- 検索結果の日時表示は`data-convert-to-user-timezone`属性によりJavaScriptでユーザーのローカルタイムゾーンに変換される
- 検索結果が空の場合は「The query returned no result.」メッセージが表示される
- フィルター検索リンク（虫眼鏡アイコン）はホバー時のみ表示される（CSS: `visibility: hidden` → `visible`）
- コマンドタイプの場合、終了コード113は「警告」として黄色表示される（SIGPIPEシグナルに対応）
- layout.html.twigを継承しているため、プロファイラー共通のヘッダー、サイドバー構成が適用される

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | profiler.php | `src/Symfony/Bundle/WebProfilerBundle/Resources/config/routing/profiler.php` | `_profiler_search_results`ルート（33-35行目）のURLパターン`/{token}/search/results`を確認 |

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | ProfilerController.php | `src/Symfony/Bundle/WebProfilerBundle/Controller/ProfilerController.php` | `searchResultsAction`メソッド（225-257行目）がエントリーポイント。検索パラメータ取得、Profiler::find()による検索、テンプレート変数の構築を把握する |

**主要処理フロー**:
1. **227行目**: プロファイラー有効性の確認
2. **229行目**: CSP無効化
3. **231行目**: Profiler::loadProfile()でトークンに対応するプロファイルを読み込み
4. **233-240行目**: クエリパラメータからの検索条件取得
5. **246行目**: Profiler::find()で検索実行（virtual_typeフィルタリング付きコールバック）
6. **242-256行目**: テンプレート変数の構築とresults.html.twigのレンダリング

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | results.html.twig | `src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/results.html.twig` | 検索結果テンプレート。タブナビゲーション（44-57行目）、結果テーブル（62-131行目）、ステータスコード色分けロジック（99-103行目）、フィルター検索マクロ（3-7行目）を確認 |
| 3-2 | layout.html.twig | `src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/layout.html.twig` | 継承元レイアウト。サイドバーの構成、検索バーの埋め込みレンダリング位置を確認 |

**主要処理フロー**:
- **results.html.twig 3-7行目**: `profile_search_filter`マクロ定義（各列の検索フィルターリンクを生成）
- **results.html.twig 40行目**: searchBarActionの埋め込みレンダリング（`render(controller(...))`）
- **results.html.twig 44-57行目**: HTTP Requests / Console Commands のタブナビゲーション
- **results.html.twig 98-103行目**: ステータスコードの色分けロジック
- **results.html.twig 127行目**: トークンリンク（プロファイラーパネルへの遷移）

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

```
ProfilerController::searchResultsAction($request, $token)
    |
    +-- denyAccessIfProfilerDisabled()
    |       +-- Profiler::disable()
    |
    +-- ContentSecurityPolicyHandler::disableCsp()
    |
    +-- Profiler::loadProfile($token)
    |
    +-- Profiler::find($ip, $url, $limit, $method, $start, $end, $statusCode, callback)
    |
    +-- renderWithCspNonces($request, 'results.html.twig', $variables)
            +-- ContentSecurityPolicyHandler::getNonces()
            +-- Environment::render()
                    +-- layout.html.twig (継承)
                    +-- searchBarAction (埋め込みレンダリング)
```

### データフロー図

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

HTTPリクエスト               --> ProfilerController           --> HTMLレスポンス
(GET /_profiler/{token}/         ::searchResultsAction()          (results.html.twig)
 search/results)                      |
    |                            +-- Profiler::loadProfile()      検索結果テーブル
    +-- token (URL)              +-- Profiler::find()             - ステータス
    +-- ip, method, etc.         +-- Twig::render()               - IP/Method/URL
        (query params)                                            - 日時/トークン
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| ProfilerController.php | `src/Symfony/Bundle/WebProfilerBundle/Controller/ProfilerController.php` | ソース | searchResultsActionメソッドを含むコントローラー |
| results.html.twig | `src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/results.html.twig` | テンプレート | 検索結果テーブルの表示 |
| layout.html.twig | `src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/layout.html.twig` | テンプレート | 共通レイアウト（継承元） |
| search.html.twig | `src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/search.html.twig` | テンプレート | サイドバーに埋め込まれる検索バー |
| profiler.php | `src/Symfony/Bundle/WebProfilerBundle/Resources/config/routing/profiler.php` | 設定 | ルーティング定義 |
