# 機能設計書 60-WebLink

## 概要

本ドキュメントは、Symfony WebLinkコンポーネントの機能設計を記述する。WebLinkコンポーネントはリソース間のリンク管理機能を提供し、HTTP/2 Server Push、Resource Hints(preload、prefetch等)をHTTPレスポンスヘッダーとして出力する。

### 本機能の処理概要

WebLinkコンポーネントは、PSR-13(HTTP Link)仕様に準拠したリンクオブジェクトの管理とHTTP Linkヘッダーへのシリアライズ機能を提供する。リソースのpreload、prefetch、preconnect等のヒントをブラウザに伝達し、ページ読み込みパフォーマンスを向上させる。

**業務上の目的・背景**：モダンなWebアプリケーションでは、重要なリソース(CSS、フォント、JavaScriptなど)のプリロードや、次のナビゲーション先のプリフェッチにより、体感速度を大幅に向上できる。WebLinkコンポーネントは、これらのResource HintsをPSR-13互換のAPIで管理し、HTTPレスポンスのLinkヘッダーとして自動出力する。

**機能の利用シーン**：CSS/JSファイルのpreload指示、Webフォントのpreload、APIエンドポイントへのpreconnect、次ページのprefetch、ES ModuleのmodulepreloadなどのResource Hints設定。

**主要な処理内容**：
1. LinkオブジェクトによるPSR-13準拠のリンク定義(href, rel, attributes)
2. GenericLinkProviderによるリンクコレクションの管理
3. HttpHeaderSerializerによるHTTP Linkヘッダー形式へのシリアライズ(RFC 5988)
4. AddLinkHeaderListenerによるKernelResponseイベントでの自動ヘッダー出力

**関連システム・外部連携**：Webブラウザ(Resource Hints対応)、HTTP/2対応Webサーバー(Server Push対応時)。

**権限による制御**：権限制御は実装されていない。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | - | - | 全画面のHTTPレスポンスに対してLinkヘッダーを付与する基盤として機能 |

## 機能種別

HTTPヘッダー管理 / パフォーマンス最適化

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| rel | string | No | リンクリレーション(例: 'preload', 'prefetch', 'preconnect') | IANA登録済みまたはカスタムリレーション |
| href | string | Yes | リソースのURL | 有効なURL文字列 |
| attribute | string | Yes(withAttribute) | 属性名(例: 'as', 'type', 'crossorigin') | 文字列型 |
| value | scalar\|\Stringable\|array | Yes(withAttribute) | 属性値 | スカラー型、\Stringable、またはその配列 |

### 入力データソース

アプリケーションコード(コントローラー、イベントリスナー等)からのLink定義。

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| linkHeader | string | HTTP Linkヘッダー文字列(RFC 5988形式) |
| links | LinkInterface[] | リンクオブジェクトの配列 |

### 出力先

HTTPレスポンスのLinkヘッダー。

## 処理フロー

### 処理シーケンス

```
1. Linkオブジェクトの作成
   └─ new Link('preload', '/assets/style.css')->withAttribute('as', 'style')
2. GenericLinkProviderへのリンク追加
   └─ $provider->withLink($link) (イミュータブル)
3. RequestオブジェクトへのLinkProvider設定
   └─ $request->attributes->set('_links', $provider)
4. KernelResponseイベント時にAddLinkHeaderListenerが発火
   └─ RequestからLinkProviderを取得
5. HttpHeaderSerializer::serialize()でLinkヘッダー文字列を生成
   └─ RFC 5988形式: <URL>; rel="relation"; attr="value"
6. ResponseにLinkヘッダーを追加
```

### フローチャート

```mermaid
flowchart TD
    A[Link作成] --> B[withRel/withAttribute]
    B --> C[GenericLinkProvider::withLink]
    C --> D[Request attributes に設定]
    D --> E[KernelResponse イベント]
    E --> F[AddLinkHeaderListener]
    F --> G[HttpHeaderSerializer::serialize]
    G --> H{テンプレート化URL?}
    H -->|Yes| I[スキップ]
    H -->|No| J[Linkヘッダー文字列生成]
    J --> K[Response::headers::set Link]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-60-01 | テンプレートURLスキップ | isTemplated()がtrueのリンク(URLに{,}を含む)はシリアライズから除外される | HttpHeaderSerializer::serialize()実行時 |
| BR-60-02 | イミュータブルリンク | Link、GenericLinkProviderは全操作でイミュータブル(clone)で動作する | withHref、withRel、withAttribute等 |
| BR-60-03 | 属性値エスケープ | 属性値中のダブルクォートはバックスラッシュでエスケープされる | HttpHeaderSerializer::serialize()実行時 |
| BR-60-04 | ブール属性 | 属性値がtrueの場合は属性名のみ出力、falseの場合は省略 | HttpHeaderSerializer::serialize()実行時 |

### 計算ロジック

特になし。

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

本コンポーネントはデータベース操作を行わない。

## エラー処理

### エラーケース一覧

エラーが発生するケースは少ない。不正な入力はPHPの型システムで防止される。

### リトライ仕様

リトライ機構は不要。

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

トランザクション管理は対象外。

## パフォーマンス要件

- リンクヘッダーの生成は軽量な文字列操作のみで高速
- AddLinkHeaderListenerはKernelResponseイベントで1回のみ実行

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

- href値はエスケープされないため、ユーザー入力を直接使用しないこと
- preload/prefetchのURLは信頼できるリソースのみを指定すること

## 備考

HTTP/2 Server Pushは多くのブラウザで非推奨となったが、preload/prefetch等のResource HintsはLinkヘッダー経由で引き続き有効。103 Early Hints(RFC 8297)との組み合わせが推奨される。

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | Link.php | `src/Symfony/Component/WebLink/Link.php` | PSR-13 EvolvableLinkInterface実装、REL_*定数群、イミュータブルAPI |

**読解のコツ**: Linkクラスは約140のREL_*定数を定義しており、IANAのlink-relationsレジストリに対応している。全てのwith*メソッドはclone $thisで新しいインスタンスを返す。

**主要処理フロー**:
- **19-148行目**: REL_*定数定義 - IANA登録済みリレーション型
- **160-167行目**: コンストラクタ - relとhrefの設定
- **174-177行目**: isTemplated() - URLに{,}が含まれるかチェック
- **194-200行目**: withHref() - イミュータブルなhref変更
- **226-232行目**: withAttribute() - イミュータブルな属性追加

#### Step 2: リンクプロバイダーを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | GenericLinkProvider.php | `src/Symfony/Component/WebLink/GenericLinkProvider.php` | PSR-13 EvolvableLinkProviderInterface実装、リンクコレクション管理 |

**主要処理フロー**:
- **27-36行目**: コンストラクタ - リンク配列の初期化(withLinkで追加)
- **43-54行目**: getLinksByRel() - リレーションでフィルタ
- **56-61行目**: withLink() - spl_object_idをキーにリンクを追加(イミュータブル)

#### Step 3: シリアライザーを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | HttpHeaderSerializer.php | `src/Symfony/Component/WebLink/HttpHeaderSerializer.php` | RFC 5988形式のLinkヘッダー生成 |

**主要処理フロー**:
- **30-63行目**: serialize() - テンプレートURLスキップ、rel/属性の組み立て、ブール属性処理、ダブルクォートエスケープ

#### Step 4: イベントリスナーを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | AddLinkHeaderListener.php | `src/Symfony/Component/WebLink/EventListener/AddLinkHeaderListener.php` | KernelResponseイベントでのLinkヘッダー自動付与 |

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

```
[コントローラー/テンプレート]
    |
    +-- new Link('preload', '/css/style.css')
    |       +-- withAttribute('as', 'style')
    |
    +-- GenericLinkProvider::withLink($link)
    |
    +-- Request::attributes::set('_links', $provider)

[KernelResponse イベント]
    |
    +-- AddLinkHeaderListener::onKernelResponse()
            |
            +-- Request::attributes::get('_links')
            +-- HttpHeaderSerializer::serialize($links)
            |       +-- [各Link] isTemplated() チェック
            |       +-- <URL>; rel="..."; attr="..." 形式組み立て
            |
            +-- Response::headers::set('Link', $header)
```

### データフロー図

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

Link定義 ─────────────────> GenericLinkProvider        HTTP Linkヘッダー
(rel, href, attributes)      |
                             +-- Request._links属性
                             |
                             v
                    AddLinkHeaderListener
                             |
                             +-- HttpHeaderSerializer
                             |
                             v
                    <URL>; rel="preload"; as="style"
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| Link.php | `src/Symfony/Component/WebLink/Link.php` | ソース | PSR-13準拠リンクオブジェクト |
| GenericLinkProvider.php | `src/Symfony/Component/WebLink/GenericLinkProvider.php` | ソース | PSR-13準拠リンクプロバイダー |
| HttpHeaderSerializer.php | `src/Symfony/Component/WebLink/HttpHeaderSerializer.php` | ソース | Linkヘッダーシリアライザー |
| HttpHeaderParser.php | `src/Symfony/Component/WebLink/HttpHeaderParser.php` | ソース | Linkヘッダーパーサー |
| AddLinkHeaderListener.php | `src/Symfony/Component/WebLink/EventListener/AddLinkHeaderListener.php` | ソース | レスポンスLinkヘッダー自動追加リスナー |
