# 機能設計書 61-フッター表示

## 概要

本ドキュメントは、Shopware Storefrontにおけるフッター領域を表示する機能について、その処理内容、入出力仕様、およびコード構造を記述した機能設計書である。

### 本機能の処理概要

本機能は、ストアフロントの全ページに共通して表示されるフッター領域を動的に生成し、レンダリングする。

**業務上の目的・背景**：ECサイトにおいてフッター領域は、サイトナビゲーション、法的情報（プライバシーポリシー、利用規約等）、問い合わせ先、利用可能な支払方法・配送方法などの重要な情報を提供する共通UI部品である。全ページで一貫したフッター表示を実現することで、ユーザーエクスペリエンスの向上とブランド一貫性を確保する。

**機能の利用シーン**：
- ユーザーがストアフロントの任意のページを閲覧した際に、ページ下部にフッターが表示される
- ESI（Edge Side Includes）を活用した部分的なページキャッシュの更新時
- AJAXリクエストによるフッター部分の動的更新時

**主要な処理内容**：
1. フッターカテゴリのナビゲーションツリー読み込み
2. サービスメニューカテゴリの読み込み
3. 販売チャネルで利用可能な支払方法一覧の取得
4. 販売チャネルで利用可能な配送方法一覧の取得
5. FooterPageletオブジェクトの生成とイベントディスパッチ
6. Twigテンプレートによるフッター領域のレンダリング

**関連システム・外部連携**：Store APIを経由したPaymentMethodRoute、ShippingMethodRoute、NavigationLoaderとの連携

**権限による制御**：特別な権限制御なし（公開領域）

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 1 | ホームページ | 補助機能 | 共通フッターの表示処理 |
| 全画面 | 全ストアフロントページ | 補助機能 | 各ページ下部に共通フッターを表示 |

## 機能種別

データ連携 / 画面表示

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| request | Request | Yes | HTTPリクエストオブジェクト | Symfony Requestオブジェクト |
| context | SalesChannelContext | Yes | 販売チャネルコンテキスト | 有効なコンテキストであること |
| footerParameters | array | No | フッターに渡す追加パラメータ | なし |

### 入力データソース

- SalesChannelContext: 現在の販売チャネル情報（フッターカテゴリID、サービスカテゴリID等）
- NavigationLoader: カテゴリナビゲーションツリー
- PaymentMethodRoute: 支払方法一覧（Store API経由）
- ShippingMethodRoute: 配送方法一覧（Store API経由）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| footer | FooterPagelet | フッター情報を含むページレットオブジェクト |
| footer.navigation | Tree\|null | フッターナビゲーションツリー |
| footer.serviceMenu | CategoryCollection | サービスメニューカテゴリコレクション |
| footer.paymentMethods | PaymentMethodCollection | 利用可能な支払方法一覧 |
| footer.shippingMethods | ShippingMethodCollection | 利用可能な配送方法一覧 |

### 出力先

HTMLレスポンス（Twigテンプレート `@Storefront/storefront/layout/footer.html.twig` によるレンダリング）

## 処理フロー

### 処理シーケンス

```
1. NavigationController::footer() がリクエストを受信
   └─ ルート: /_esi/global/footer (ESI対応)

2. FooterPageletLoader::load() を呼び出し
   └─ SalesChannelContextからフッターカテゴリIDを取得

3. フッターナビゲーションの読み込み
   └─ NavigationLoader::load() でフッターカテゴリのツリー構造を取得

4. サービスメニューの読み込み
   └─ NavigationLoader::load() でサービスカテゴリを取得し、CategoryCollectionに変換

5. 支払方法の読み込み
   └─ PaymentMethodRoute::load() で利用可能な支払方法を取得

6. 配送方法の読み込み
   └─ ShippingMethodRoute::load() で利用可能な配送方法を取得

7. FooterPageletオブジェクトの生成
   └─ 取得したデータをFooterPageletにセット

8. FooterPageletLoadedEventのディスパッチ
   └─ 拡張ポイントとしてイベントを発火

9. FooterPageletLoadedHookの実行
   └─ App Scriptsによる拡張ポイント

10. Twigテンプレートのレンダリング
    └─ footer.html.twig でHTMLを生成してレスポンスを返却
```

### フローチャート

```mermaid
flowchart TD
    A[リクエスト受信] --> B[FooterPageletLoader::load]
    B --> C{フッターカテゴリIDあり?}
    C -->|Yes| D[NavigationLoader::load]
    C -->|No| E[nullをセット]
    D --> F[サービスメニュー読み込み]
    E --> F
    F --> G{サービスカテゴリIDあり?}
    G -->|Yes| H[NavigationLoader::load]
    G -->|No| I[空のCategoryCollection]
    H --> J[支払方法読み込み]
    I --> J
    J --> K[PaymentMethodRoute::load]
    K --> L[配送方法読み込み]
    L --> M[ShippingMethodRoute::load]
    M --> N[FooterPagelet生成]
    N --> O[イベントディスパッチ]
    O --> P[Hook実行]
    P --> Q[Twigレンダリング]
    Q --> R[レスポンス返却]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-001 | フッターカテゴリ必須ではない | フッターカテゴリIDが未設定の場合、ナビゲーションはnullとなる | 常時 |
| BR-002 | サービスメニュー必須ではない | サービスカテゴリIDが未設定の場合、空のコレクションを返す | 常時 |
| BR-003 | アクティブな方法のみ表示 | 支払方法・配送方法は販売チャネルでアクティブなもののみ表示 | 常時 |

### 計算ロジック

特になし

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| フッターカテゴリ取得 | category | SELECT | フッターナビゲーション用カテゴリ取得 |
| サービスメニュー取得 | category | SELECT | サービスメニュー用カテゴリ取得 |
| 支払方法取得 | payment_method | SELECT | アクティブな支払方法取得 |
| 配送方法取得 | shipping_method | SELECT | アクティブな配送方法取得 |

### テーブル別操作詳細

#### category

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| SELECT | id, name, path等 | フッターカテゴリID配下 | ツリー構造で取得 |

#### payment_method

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| SELECT | id, name, description等 | sales_channel紐付け + active = true | 販売チャネル限定 |

#### shipping_method

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| SELECT | id, name, description等 | sales_channel紐付け + active = true | 販売チャネル限定 |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | なし | フッターカテゴリが存在しない | ナビゲーションをnullとして処理続行 |
| - | なし | サービスカテゴリが存在しない | 空のコレクションとして処理続行 |

### リトライ仕様

リトライ処理なし（読み取り専用処理のため）

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

読み取り専用のためトランザクション制御なし

## パフォーマンス要件

- HTTPキャッシュ対応（`PlatformRequest::ATTRIBUTE_HTTP_CACHE => true`）
- ESI対応（`_esi => true`）による部分的キャッシュ
- レスポンス時間：100ms以内推奨

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

- 認証不要（公開領域）
- x-robots-tagヘッダーは設定されない（インデックス可能）
- XSS対策：Twigのエスケープ機能を使用

## 備考

- ESI（Edge Side Includes）を活用することで、フッター部分のみを個別にキャッシュ可能
- FooterPageletLoadedEventを利用して、カスタムデータをフッターに追加可能
- App Scriptsからの拡張はFooterPageletLoadedHook経由で可能

---

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

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

### 推奨読解順序

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

まず、フッターに含まれるデータ構造を理解することが重要である。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | FooterPagelet.php | `src/Storefront/Pagelet/Footer/FooterPagelet.php` | フッターに含まれるデータ構造（navigation, serviceMenu, paymentMethods, shippingMethods） |
| 1-2 | NavigationPagelet.php | `src/Storefront/Pagelet/NavigationPagelet.php` | 親クラスのナビゲーション構造 |

**読解のコツ**: FooterPageletはNavigationPageletを継承しており、ナビゲーションツリー以外にサービスメニュー、支払方法、配送方法の3つのコレクションを持つ。

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

処理の起点となるコントローラーを確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | NavigationController.php | `src/Storefront/Controller/NavigationController.php` | footer()メソッド（142-162行目） |

**主要処理フロー**:
1. **152-154行目**: FooterPageletLoaderからフッターを読み込み
2. **156行目**: FooterPageletLoadedHookを実行
3. **158-161行目**: Twigテンプレートをレンダリングしてレスポンス返却

#### Step 3: ページレットローダーを理解する

フッターデータの読み込み処理の詳細を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | FooterPageletLoader.php | `src/Storefront/Pagelet/Footer/FooterPageletLoader.php` | load()メソッド（37-58行目） |
| 3-2 | FooterPageletLoaderInterface.php | `src/Storefront/Pagelet/Footer/FooterPageletLoaderInterface.php` | インターフェース定義 |

**主要処理フロー**:
- **39行目**: SalesChannelからフッターカテゴリIDを取得
- **42-44行目**: フッターナビゲーションツリーを読み込み
- **46-51行目**: FooterPageletを生成（ナビゲーション、サービスメニュー、支払方法、配送方法）
- **53-55行目**: FooterPageletLoadedEventをディスパッチ

#### Step 4: 関連ルート処理を理解する

Store API経由のデータ取得処理を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | AbstractPaymentMethodRoute.php | `src/Core/Checkout/Payment/SalesChannel/AbstractPaymentMethodRoute.php` | 支払方法取得の抽象クラス |
| 4-2 | AbstractShippingMethodRoute.php | `src/Core/Checkout/Shipping/SalesChannel/AbstractShippingMethodRoute.php` | 配送方法取得の抽象クラス |

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

```
NavigationController::footer()
    │
    ├─ FooterPageletLoader::load()
    │      ├─ NavigationLoaderInterface::load() [フッターナビゲーション]
    │      ├─ loadServiceMenu()
    │      │      └─ NavigationLoaderInterface::load() [サービスメニュー]
    │      ├─ loadPaymentMethods()
    │      │      └─ AbstractPaymentMethodRoute::load()
    │      └─ loadShippingMethods()
    │             └─ AbstractShippingMethodRoute::load()
    │
    ├─ hook(FooterPageletLoadedHook)
    │
    └─ renderStorefront() → footer.html.twig
```

### データフロー図

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

Request ────────────────┐
                        ▼
SalesChannelContext ───▶ FooterPageletLoader ───▶ FooterPagelet
                        │                              │
                        ├─ NavigationLoader            ├─ navigation (Tree)
                        ├─ PaymentMethodRoute          ├─ serviceMenu (CategoryCollection)
                        └─ ShippingMethodRoute         ├─ paymentMethods (PaymentMethodCollection)
                                                       └─ shippingMethods (ShippingMethodCollection)
                                                              │
                                                              ▼
                                                       footer.html.twig
                                                              │
                                                              ▼
                                                       HTML Response
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| NavigationController.php | `src/Storefront/Controller/NavigationController.php` | コントローラー | フッター表示のエントリーポイント |
| FooterPageletLoader.php | `src/Storefront/Pagelet/Footer/FooterPageletLoader.php` | ローダー | フッターデータの読み込み |
| FooterPageletLoaderInterface.php | `src/Storefront/Pagelet/Footer/FooterPageletLoaderInterface.php` | インターフェース | ローダーのインターフェース定義 |
| FooterPagelet.php | `src/Storefront/Pagelet/Footer/FooterPagelet.php` | データ構造 | フッターページレットのデータ構造 |
| FooterPageletLoadedEvent.php | `src/Storefront/Pagelet/Footer/FooterPageletLoadedEvent.php` | イベント | フッター読み込み完了イベント |
| FooterPageletLoadedHook.php | `src/Storefront/Pagelet/Footer/FooterPageletLoadedHook.php` | フック | App Scripts用拡張ポイント |
| NavigationPagelet.php | `src/Storefront/Pagelet/NavigationPagelet.php` | データ構造 | ナビゲーションページレットの親クラス |
