# 機能設計書 17-URL生成

## 概要

本ドキュメントは、Laravel FrameworkのURL生成（UrlGenerator）機能の設計を詳細に記述したものである。アプリケーション内のURL生成、名前付きルートへのURL生成、署名付きURL生成などの機能を提供する。

### 本機能の処理概要

URL生成機能は、アプリケーション内で一貫したURL生成を行い、環境に応じたスキーム・ホストの適用、名前付きルートの解決、セキュアな署名付きURLの生成を実現する。

**業務上の目的・背景**：Webアプリケーションでは、ビュー、コントローラ、メール通知など様々な場所でURLを生成する必要がある。URL生成を一元化することで、ルート定義の変更に強い保守性の高いコードを実現し、HTTPSへの強制やCDNドメインの設定などの横断的な設定を容易にする。また、パスワードリセットやメール認証などで使用する署名付きURLにより、有効期限と改ざん検知を備えたセキュアなリンクを生成できる。

**機能の利用シーン**：
- ビューでのリンク生成（url(), route(), action()ヘルパー）
- リダイレクト時のURL生成
- メール通知内のリンク生成
- パスワードリセット・メール認証の署名付きURL
- アセット（CSS、JavaScript、画像）のURL生成
- APIレスポンス内のリソースURL生成

**主要な処理内容**：
1. 絶対URLの生成（to メソッド）
2. 名前付きルートへのURL生成（route メソッド）
3. コントローラアクションへのURL生成（action メソッド）
4. 署名付きURL生成（signedRoute, temporarySignedRoute メソッド）
5. 署名検証（hasValidSignature, hasCorrectSignature メソッド）
6. アセットURL生成（asset, secureAsset メソッド）
7. 前のURL取得（previous メソッド）

**関連システム・外部連携**：
- ルートコレクション：名前付きルートの解決
- セッション：前のURLの取得
- 暗号化キー：署名付きURLのHMAC生成

**権限による制御**：URL生成自体は権限制御を持たない。署名付きURLにより、有効期限付きのアクセス制御を実現。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | - | - | 全画面で使用されるユーティリティ機能 |

## 機能種別

ユーティリティ / URL操作 / セキュリティ

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| path | string | Yes（to時） | URLパス | - |
| extra | mixed | No | 追加パスセグメント | - |
| secure | bool/null | No | HTTPS強制 | - |
| name | BackedEnum/string | Yes（route時） | ルート名 | 登録済みルート |
| parameters | mixed | No（route時） | ルートパラメータ | - |
| absolute | bool | No | 絶対URL生成 | デフォルトtrue |
| action | string/array | Yes（action時） | コントローラアクション | 登録済みルート |
| expiration | DateTimeInterface/DateInterval/int/null | No（signedRoute時） | 有効期限 | - |

### 入力データソース

- HTTPリクエスト：スキーム、ホスト、パス情報
- ルートコレクション：名前付きルート定義
- 設定：APP_URL、暗号化キー
- セッション：前のURL

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| url | string | 生成されたURL |
| isValidSignature | bool | 署名が有効か |
| signatureHasNotExpired | bool | 有効期限内か |

### 出力先

- 文字列としてのURL（ビュー、リダイレクト、レスポンスで使用）

## 処理フロー

### 処理シーケンス

```
1. URL生成要求
   └─ to(), route(), action() 等の呼び出し
2. パラメータの整形
   └─ UrlRoutableの処理、配列の展開
3. スキームの決定
   └─ forcedScheme または リクエストから取得
4. ルートの決定
   └─ formatRoot でベースURL生成
5. パスの生成
   └─ ルートパラメータの埋め込み
6. URL結合
   └─ format でroot + path結合
7. 署名追加（signedRouteの場合）
   └─ HMAC-SHA256署名をクエリパラメータに追加
```

### フローチャート

```mermaid
flowchart TD
    A[URL生成要求] --> B{メソッド種別}
    B -->|to| C[絶対URL生成]
    B -->|route| D[ルート名解決]
    B -->|action| E[アクション解決]
    D --> F{ルート存在?}
    F -->|No| G[RouteNotFoundException]
    F -->|Yes| H[RouteUrlGenerator::to]
    E --> I{アクション存在?}
    I -->|No| J[InvalidArgumentException]
    I -->|Yes| H
    C --> K[formatRoot]
    H --> K
    K --> L[format]
    L --> M{署名付き?}
    M -->|Yes| N[HMAC署名追加]
    M -->|No| O[URL返却]
    N --> O
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-17-01 | 有効URL透過 | 既に有効なURL（http://等で始まる）はそのまま返却 | to()呼び出し時 |
| BR-17-02 | 予約パラメータ | signature、expiresは署名付きURLの予約パラメータ | signedRoute時 |
| BR-17-03 | パラメータソート | 署名前にパラメータをキーでソート | signedRoute時 |
| BR-17-04 | キー配列対応 | 暗号化キーが配列の場合、全キーで署名検証 | hasCorrectSignature時 |
| BR-17-05 | バックエンド有効URLスキーム | BackedEnumの場合はvalueプロパティを使用 | route()呼び出し時 |

### 計算ロジック

```php
// 署名生成
signature = hash_hmac('sha256', $url, $key)

// 有効期限設定
expires = $this->availableAt($expiration)

// スキーム決定
scheme = $forceScheme ?? $request->getScheme().'://'

// ベースURL生成
root = preg_replace('~'.$start.'~', $scheme, $root, 1)
```

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

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

URL生成はデータベースを操作しない。

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| - | - | - | UrlGenerator自体はDB操作なし |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | RouteNotFoundException | 未定義のルート名を指定 | ルート定義を確認 |
| - | InvalidArgumentException | 未定義のアクションを指定 | アクション定義を確認 |
| - | InvalidArgumentException | signatureを手動でパラメータに含めた | パラメータ名を変更 |
| - | InvalidArgumentException | expiresを手動でパラメータに含めた | パラメータ名を変更 |
| - | InvalidArgumentException | BackedEnumで文字列以外のvalue | 文字列BackedEnumを使用 |

### リトライ仕様

URL生成にリトライ機構はない。

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

URL生成はトランザクションを使用しない。

## パフォーマンス要件

- cachedRoot、cachedSchemeでリクエスト単位のキャッシュ
- routeGeneratorの遅延生成
- ルートコレクションからの高速なルート検索

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

- 署名付きURL：HMAC-SHA256による改ざん検知
- 有効期限：expiresパラメータで時間制限
- キーローテーション：複数キー対応で安全な移行
- HTTPS強制：forceScheme/forceHttpsで全URLをHTTPS化

## 備考

- Macroableトレイト：カスタムURL生成メソッドの追加が可能
- InteractsWithTimeトレイト：有効期限計算のヘルパー
- missingNamedRouteResolver：未定義ルートのカスタムハンドリング

---

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

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

### 推奨読解順序

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

まず、URL生成が保持するデータ構造を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | UrlGenerator.php | `src/Illuminate/Routing/UrlGenerator.php` | プロパティ定義（$routes, $request, $assetRoot）を確認 |
| 1-2 | UrlGenerator.php | `src/Illuminate/Routing/UrlGenerator.php` | キャッシュ関連（$cachedRoot, $cachedScheme） |
| 1-3 | UrlGenerator.php | `src/Illuminate/Routing/UrlGenerator.php` | リゾルバー関連（$sessionResolver, $keyResolver） |

**読解のコツ**: UrlGeneratorは多数のプロパティを持つ。`$routes`はルートコレクション、`$request`は現在のリクエスト、`$forcedRoot`と`$forceScheme`は強制設定、`$cachedRoot`と`$cachedScheme`はパフォーマンス最適化用のキャッシュである。

#### Step 2: 基本URL生成を理解する

toメソッドによる基本的なURL生成を把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | UrlGenerator.php | `src/Illuminate/Routing/UrlGenerator.php` | toメソッド（208-231行目） |
| 2-2 | UrlGenerator.php | `src/Illuminate/Routing/UrlGenerator.php` | formatSchemeメソッド（334-345行目） |
| 2-3 | UrlGenerator.php | `src/Illuminate/Routing/UrlGenerator.php` | formatRootメソッド（630-643行目） |
| 2-4 | UrlGenerator.php | `src/Illuminate/Routing/UrlGenerator.php` | formatメソッド（653-666行目） |

**主要処理フロー**:
1. **208-231行目**: `to` - 有効URL透過、パラメータ整形、スキーム・ルート決定
2. **334-345行目**: `formatScheme` - secure引数またはforceSchemeからスキーム決定
3. **630-643行目**: `formatRoot` - forcedRootまたはリクエストからベースURL取得
4. **653-666行目**: `format` - コールバックを通じてホスト・パスを整形

#### Step 3: 名前付きルートURL生成を理解する

routeメソッドによる名前付きルートへのURL生成を把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | UrlGenerator.php | `src/Illuminate/Routing/UrlGenerator.php` | routeメソッド（513-529行目） |
| 3-2 | UrlGenerator.php | `src/Illuminate/Routing/UrlGenerator.php` | toRouteメソッド（541-546行目） |
| 3-3 | UrlGenerator.php | `src/Illuminate/Routing/UrlGenerator.php` | routeUrlメソッド（688-695行目） |

**主要処理フロー**:
- **513-529行目**: `route` - BackedEnum対応、ルート名解決、missingNamedRouteResolver
- **541-546行目**: `toRoute` - RouteUrlGeneratorに委譲
- **688-695行目**: `routeUrl` - RouteUrlGeneratorの遅延生成

#### Step 4: 署名付きURL生成を理解する

セキュアな署名付きURL生成を把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | UrlGenerator.php | `src/Illuminate/Routing/UrlGenerator.php` | signedRouteメソッド（358-379行目） |
| 4-2 | UrlGenerator.php | `src/Illuminate/Routing/UrlGenerator.php` | hasValidSignatureメソッド（426-430行目） |
| 4-3 | UrlGenerator.php | `src/Illuminate/Routing/UrlGenerator.php` | hasCorrectSignatureメソッド（452-488行目） |
| 4-4 | UrlGenerator.php | `src/Illuminate/Routing/UrlGenerator.php` | signatureHasNotExpiredメソッド（496-501行目） |

**主要処理フロー**:
- **358-379行目**: `signedRoute` - 予約パラメータチェック、expires設定、HMAC署名生成
- **452-488行目**: `hasCorrectSignature` - クエリ文字列再構築、複数キー対応の署名検証
- **496-501行目**: `signatureHasNotExpired` - 現在時刻とexpiresの比較

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

```
UrlGenerator::route($name, $parameters, $absolute)
    │
    ├─ BackedEnum::value (enum対応)
    │
    ├─ RouteCollection::getByName($name)
    │      └─ Route インスタンス取得
    │
    └─ UrlGenerator::toRoute($route, $parameters, $absolute)
           │
           └─ RouteUrlGenerator::to($route, $parameters, $absolute)
                  │
                  ├─ RouteUrlGenerator::replaceRouteParameters()
                  │      └─ パラメータ埋め込み
                  │
                  ├─ UrlGenerator::formatRoot()
                  │      └─ スキーム + ホスト
                  │
                  └─ UrlGenerator::format($root, $path, $route)
                         └─ 最終URL生成

UrlGenerator::signedRoute($name, $parameters, $expiration, $absolute)
    │
    ├─ UrlGenerator::ensureSignedRouteParametersAreNotReserved()
    │      └─ signature/expires の予約チェック
    │
    ├─ ksort($parameters)
    │      └─ パラメータソート
    │
    ├─ UrlGenerator::route($name, $parameters, $absolute)
    │      └─ 署名なしURL生成
    │
    └─ hash_hmac('sha256', $url, $key)
           └─ 署名追加
```

### データフロー図

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

ルート名          ───▶  getByName()               ───▶  Routeインスタンス
    │                        │
パラメータ        ───▶  formatParameters()        ───▶  整形済みパラメータ
    │                        │
                         replaceRouteParameters()  ───▶  パス文字列
    │                        │
forcedRoot/Request ───▶  formatRoot()             ───▶  ベースURL
    │                        │
forceScheme/secure ───▶  formatScheme()           ───▶  スキーム文字列
    │                        │
                         format()                  ───▶  完全URL

有効期限          ───▶  availableAt()             ───▶  UNIXタイムスタンプ
    │                        │
暗号化キー        ───▶  hash_hmac()               ───▶  署名文字列
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| UrlGenerator.php | `src/Illuminate/Routing/UrlGenerator.php` | ソース | URL生成コア実装 |
| RouteUrlGenerator.php | `src/Illuminate/Routing/RouteUrlGenerator.php` | ソース | ルートURL生成 |
| UrlGeneratorContract.php | `src/Illuminate/Contracts/Routing/UrlGenerator.php` | インターフェース | URL生成契約 |
| UrlRoutable.php | `src/Illuminate/Contracts/Routing/UrlRoutable.php` | インターフェース | URLルータブル契約 |
| InteractsWithTime.php | `src/Illuminate/Support/InteractsWithTime.php` | トレイト | 時間計算ヘルパー |
| RouteCollection.php | `src/Illuminate/Routing/RouteCollection.php` | ソース | ルートコレクション |
| Route.php | `src/Illuminate/Routing/Route.php` | ソース | ルートエンティティ |
| RoutingServiceProvider.php | `src/Illuminate/Routing/RoutingServiceProvider.php` | ソース | サービスプロバイダー |
