# 画面設計書 26-CMSページ（ウィジェット）

## 概要

本ドキュメントは、Shopware 6 StorefrontのCMSページ（ウィジェット）の画面設計書である。CMSで作成されたレイアウトを単体表示するための画面（AJAX用途）について記載する。

### 本画面の処理概要

CMSページ（ウィジェット）は、CMSで作成されたレイアウトをヘッダー・フッターなしで単体表示するための画面である。主にJavaScriptから動的にコンテンツを読み込む用途で使用される。

**業務上の目的・背景**：ECサイトでは、商品詳細ページのモーダル表示、ポップアップバナー、動的に読み込まれるコンテンツブロックなど、ページ全体ではなく部分的なCMSコンテンツが必要な場面がある。このウィジェット形式のエンドポイントにより、そうした用途に対応できる。

**画面へのアクセス方法**：
- JavaScriptからのAJAXリクエスト
- data-ajax-modal属性を持つリンクのクリック
- URLへの直接アクセス（通常は推奨されない）

**主要な操作・処理内容**：
1. CMSページIDに基づくレイアウトの読み込み
2. セクション・ブロック・エレメントの描画
3. カテゴリナビゲーションIDに基づくレイアウトの読み込み（別ルート）
4. フィルターの取得（商品一覧用）

**画面遷移**：
- 遷移元：任意のページ（AJAXリクエスト）
- 遷移先：なし（インライン表示）

**権限による表示制御**：
- 特になし（公開コンテンツ）
- HTTPキャッシュが有効

## 関連機能

| 機能No | 機能名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 62 | CMSページ表示 | 主機能 | CMSレイアウトの単体表示（CmsController::page） |

## 画面種別

詳細 / ウィジェット

## URL/ルーティング

| ルート名 | URL | HTTPメソッド | 説明 |
|----------|-----|--------------|------|
| frontend.cms.page | /widgets/cms/{id} | GET, POST | CMSページのウィジェット表示 |
| frontend.cms.navigation.page | /widgets/cms/navigation/{navigationId} | GET, POST | カテゴリのCMSページ表示 |
| frontend.cms.navigation.filter | /widgets/cms/navigation/{navigationId}/filter | GET, POST | フィルター取得 |

## 入出力項目

### 入力項目

| 項目名 | パラメータ名 | 型 | 必須 | 説明 |
|--------|-------------|-----|------|------|
| CMSページID | id | string(UUID) | 必須 | CMSページのID |
| ナビゲーションID | navigationId | string(UUID) | - | カテゴリID |

### 出力項目

| 項目名 | 型 | 説明 |
|--------|-----|------|
| cmsPage | CmsPageEntity | CMSページエンティティ |

## 表示項目

### CMSページ構造

| 項目名 | データソース | 説明 |
|--------|-------------|------|
| セクション | cmsPage.sections | ページを構成するセクション |
| 背景色 | section.backgroundColor | セクションの背景色 |
| 背景画像 | section.backgroundMedia | セクションの背景画像 |
| CSSクラス | section.cssClass | カスタムCSSクラス |
| 可視性設定 | section.visibility | モバイル/タブレット/デスクトップの表示制御 |

## イベント仕様

### 1-CMSページ読み込み

ページIDを指定してCmsRouteを呼び出し、CMSページデータを取得。CmsPageLoadedHookを実行後、detail.html.twigでレンダリング。

### 2-カテゴリCMSページ読み込み

カテゴリIDを指定してCategoryRouteを呼び出し、そのカテゴリに紐づくCMSページを取得。

### 3-フィルター取得

商品一覧を含むカテゴリページのフィルター情報（アグリゲーション）を取得。only-aggregations、reduce-aggregationsフラグを設定してリクエスト。

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

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

| 操作（イベント） | 対象テーブル | 操作種別 | 概要 |
|----------------|-------------|---------|------|
| なし | - | SELECT | 参照のみ |

## メッセージ仕様

| メッセージID | 種別 | メッセージ内容 | 表示条件 |
|-------------|------|---------------|----------|
| なし | - | - | - |

## 例外処理

| 例外 | 原因 | 処理内容 |
|------|------|----------|
| RoutingException | CMSページIDが未指定 | 必須パラメータエラー |
| CmsException::pageNotFound | CMSページが存在しない | 404エラー |

## 備考

- レスポンスヘッダーに `x-robots-tag: noindex` が設定される
- HTTPキャッシュが有効（PlatformRequest::ATTRIBUTE_HTTP_CACHE => true）
- ヘッダー・フッターは含まれない（detail.html.twigのみ）
- カテゴリのCMSページ取得時はそのカテゴリに設定されたCMSページを使用

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | CmsPageEntity.php | `src/Core/Content/Cms/CmsPageEntity.php` | sections, cssClassプロパティ |
| 1-2 | CmsSectionEntity.php | `src/Core/Content/Cms/Aggregate/CmsSection/CmsSectionEntity.php` | blocks, backgroundColor, backgroundMedia |
| 1-3 | CmsBlockEntity.php | `src/Core/Content/Cms/Aggregate/CmsBlock/CmsBlockEntity.php` | slots構造 |

**読解のコツ**: CMSはPage > Section > Block > Slotの階層構造。各レベルで異なる表示設定を持つ。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | CmsController.php | `src/Storefront/Controller/CmsController.php` | page(), category(), filter()メソッド |

**主要処理フロー**:
1. **54-78行**: page() - CMSページの単体表示
2. **104-133行**: category() - カテゴリのCMSページ表示
3. **138-169行**: filter() - フィルター取得（商品一覧用）

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | detail.html.twig | `src/Storefront/Resources/views/storefront/page/content/detail.html.twig` | セクションループ、可視性制御 |
| 3-2 | cms-section-*.html.twig | `src/Storefront/Resources/views/storefront/section/` | セクションタイプ別テンプレート |

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

```
CmsController::page()
    │
    ├─ idパラメータチェック
    │
    ├─ AbstractCmsRoute::load()
    │      │
    │      └─ CmsPageEntity取得
    │
    ├─ CmsPageLoadedHook dispatch
    │
    └─ renderStorefront('detail.html.twig')

CmsController::category()
    │
    ├─ navigationIdパラメータチェック
    │
    ├─ AbstractCategoryRoute::load()
    │      │
    │      └─ CategoryEntity取得
    │             │
    │             └─ cmsPage取得
    │
    ├─ CmsPageLoadedHook dispatch
    │
    └─ renderStorefront('detail.html.twig')

CmsController::filter()
    │
    ├─ only-aggregations = true 設定
    ├─ reduce-aggregations = true 設定
    │
    └─ AbstractProductListingRoute::load()
           │
           └─ Aggregations取得 → JsonResponse
```

### データフロー図

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

Request (id)
         │
         ▼
 CmsController::page()
         │
         ├─► AbstractCmsRoute::load()
         │         │
         │         ▼
         │    CmsPageEntity
         │         │
         │         └─► sections
         │                 │
         │                 └─► blocks
         │                       │
         │                       └─► slots
         │
         ├─► CmsPageLoadedHook
         │
         └─► detail.html.twig
                   │
                   └─► cms-section-{type}.html.twig
                            │
                            └─► cms-block-{type}.html.twig
                                     │
                                     └─► cms-element-{type}.html.twig
                                              │
                                              ▼
                                         Response (HTML)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| CmsController.php | `src/Storefront/Controller/CmsController.php` | コントローラー | リクエスト処理 |
| AbstractCmsRoute.php | `src/Core/Content/Cms/SalesChannel/AbstractCmsRoute.php` | Store API | CMSページ取得 |
| AbstractCategoryRoute.php | `src/Core/Content/Category/SalesChannel/AbstractCategoryRoute.php` | Store API | カテゴリ取得 |
| detail.html.twig | `src/Storefront/Resources/views/storefront/page/content/detail.html.twig` | テンプレート | セクション描画 |
| cms-section-default.html.twig | `src/Storefront/Resources/views/storefront/section/cms-section-default.html.twig` | テンプレート | デフォルトセクション |
| cms-section-sidebar.html.twig | `src/Storefront/Resources/views/storefront/section/cms-section-sidebar.html.twig` | テンプレート | サイドバーセクション |
