# 機能設計書 75-テーマ変更

## 概要

本ドキュメントは、Shopware管理画面におけるテーマ変更機能の設計を記載する。ストアフロントの外観（デザイン、スタイル、色など）を管理・変更するためのAPIエンドポイント群である。

### 本機能の処理概要

テーマ変更機能は、管理者がストアフロントのビジュアルデザインを設定・変更するための機能である。テーマの設定値（色、フォント、レイアウトなど）を更新し、SCSSをコンパイルしてスタイルシートを生成する。

**業務上の目的・背景**：ECサイトの外観は顧客体験とブランドイメージに直結する重要な要素である。コードを直接編集することなく、管理画面からテーマ設定を変更できることで、運用効率の向上とブランドアイデンティティの一貫性を保つことができる。季節キャンペーンやプロモーションに合わせたデザイン変更も容易になる。

**機能の利用シーン**：
- 管理者がストアフロントの配色を変更する
- 管理者がロゴや背景画像を設定する
- 管理者がフォントやタイポグラフィを調整する
- 管理者がテーマを販売チャネルに割り当てる
- 管理者がテーマ設定をデフォルトにリセットする
- 管理者が新しいテーマの設定値を検証する

**主要な処理内容**：
1. テーマ設定値の取得
2. テーマ設定値の更新
3. テーマの販売チャネルへの割り当て
4. テーマ設定のリセット
5. SCSS設定値のバリデーション
6. テーマのコンパイル（SCSS→CSS）

**関連システム・外部連携**：
- SCSSコンパイラー
- ファイルシステム（CSS出力）
- メッセージキュー（非同期コンパイル）
- 通知サービス（コンパイル完了通知）

**権限による制御**：
- 管理画面APIのみ（StoreAPIではない）
- 管理者ログインが必要
- テーマ管理権限が必要

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 48 | 拡張機能管理 | 補助画面 | プラグイン・アプリのインストール・管理 |
| 47 | 販売チャネル管理 | 関連画面 | テーマと販売チャネルの紐付け |

## 機能種別

CRUD操作 / 設定管理 / ビルド処理

## 入力仕様

### 入力パラメータ

#### テーマ設定取得（GET /api/_action/theme/{themeId}/configuration）

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| themeId | string (UUID) | Yes | テーマID | UUIDフォーマット |

#### テーマ更新（PATCH /api/_action/theme/{themeId}）

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| themeId | string (UUID) | Yes | テーマID | UUIDフォーマット |
| config | object | No | テーマ設定値 | 各フィールドの型に応じた検証 |
| parentThemeId | string (UUID) | No | 親テーマID | UUIDフォーマット |
| reset | boolean | No | リセットフラグ | クエリパラメータ |
| validate | boolean | No | バリデーションフラグ | クエリパラメータ |
| sanitize | boolean | No | サニタイズフラグ | クエリパラメータ |

#### テーマ割り当て（POST /api/_action/theme/{themeId}/assign/{salesChannelId}）

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| themeId | string (UUID) | Yes | テーマID | UUIDフォーマット |
| salesChannelId | string (UUID) | Yes | 販売チャネルID | UUIDフォーマット |

#### テーマリセット（PATCH /api/_action/theme/{themeId}/reset）

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| themeId | string (UUID) | Yes | テーマID | UUIDフォーマット |

#### フィールド検証（POST /api/_action/theme/validate-fields）

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| fields | array | Yes | 検証対象フィールド | 配列形式 |
| fields[].name | string | Yes | フィールド名 | 文字列 |
| fields[].value | mixed | Yes | フィールド値 | 型に依存 |
| fields[].type | string | No | フィールド型 | color/text/number等 |

### 入力データソース

- URLパスパラメータ：themeId, salesChannelId
- クエリパラメータ：reset, validate, sanitize
- リクエストボディ：config, parentThemeId, fields

## 出力仕様

### 出力データ（テーマ設定取得）

| 項目名 | 型 | 説明 |
|--------|-----|------|
| fields | object | テーマ設定フィールド定義 |
| currentFields | object | 現在の設定値 |
| baseThemeFields | object | ベーステーマの設定値 |

### 出力データ（更新/割り当て/リセット）

| 項目名 | 型 | 説明 |
|--------|-----|------|
| - | empty | 空のJSONオブジェクト（成功時） |

### 出力先

JSONレスポンス

## 処理フロー

### 処理シーケンス（テーマ更新）

```
1. リクエスト受信
   └─ ThemeController::updateTheme がPATCHリクエストを受け取る

2. パラメータ取得
   ├─ config設定値を取得
   ├─ validateフラグを確認
   └─ resetフラグを確認

3. バリデーション（オプション）
   └─ ThemeService::validateThemeConfig でSCSS検証

4. リセット（オプション）
   └─ ThemeService::resetTheme でデフォルト値に戻す

5. テーマ更新
   └─ ThemeService::updateTheme
       ├─ テーマエンティティの検索
       ├─ 設定値のマージ
       ├─ イベントディスパッチ（ThemeConfigChangedEvent）
       └─ データベース更新

6. テーマコンパイル
   ├─ 同期コンパイル（デフォルト）
   │   └─ ThemeCompiler::compileTheme
   └─ 非同期コンパイル（設定による）
       └─ CompileThemeMessage をキューに送信

7. レスポンス返却
   └─ 空のJSONオブジェクトを返却
```

### フローチャート

```mermaid
flowchart TD
    A[PATCH リクエスト受信] --> B{validateフラグ?}
    B -->|Yes| C[SCSS バリデーション]
    C -->|成功| D{resetフラグ?}
    C -->|失敗| E[エラーレスポンス]
    B -->|No| D
    D -->|Yes| F[テーマリセット]
    D -->|No| G[テーマ更新]
    F --> G
    G --> H[テーマ検索]
    H --> I[設定値マージ]
    I --> J[ThemeConfigChangedEvent]
    J --> K[DB更新]
    K --> L{非同期コンパイル?}
    L -->|Yes| M[キューにメッセージ送信]
    L -->|No| N[同期コンパイル]
    M --> O[通知送信]
    N --> P[成功レスポンス]
    O --> P
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-75-01 | 管理者権限 | テーマ変更は管理者権限が必要 | 全API操作 |
| BR-75-02 | SCSS検証 | 設定値はSCSSとしてコンパイル可能である必要がある | validate=true時 |
| BR-75-03 | 親テーマ継承 | テーマは親テーマの設定を継承できる | 親テーマ設定時 |
| BR-75-04 | 販売チャネル単位 | 1つの販売チャネルには1つのテーマのみ割り当て可能 | テーマ割り当て時 |
| BR-75-05 | 依存テーマ更新 | テーマ更新時に依存する全テーマも再コンパイル | テーマ更新時 |
| BR-75-06 | 非同期コンパイル | システム設定で非同期コンパイルを有効化可能 | コンパイル時 |

### 計算ロジック

- 設定値マージ：`array_replace_recursive(currentConfig, newConfig)`

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| テーマ検索 | theme | SELECT | themeIdでテーマを検索 |
| テーマ更新 | theme | UPDATE | config_valuesを更新 |
| 販売チャネル割り当て | theme_sales_channel | UPSERT | テーマと販売チャネルの紐付け |
| 依存テーマ取得 | theme, theme_sales_channel | SELECT | 親子関係と販売チャネル取得 |

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

#### theme

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| SELECT | id, config_values, parent_theme_id | WHERE id = :themeId | テーマ取得 |
| UPDATE | config_values | 新しい設定値 | 設定更新 |
| UPDATE | config_values | NULL | リセット時 |

#### theme_sales_channel

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| UPSERT | theme_id, sales_channel_id | テーマIDと販売チャネルID | 割り当て |
| SELECT | theme_id, sales_channel_id | JOIN theme | 依存関係取得 |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| THEME_NOT_FOUND | ビジネスエラー | 指定されたthemeIdのテーマが存在しない | 404エラーを返却 |
| INVALID_THEME_CONFIG | バリデーションエラー | SCSS設定値が不正 | 検証エラー詳細を返却 |
| FILE_TYPE_NOT_SUPPORTED | バリデーションエラー | サポートされていないファイル形式 | エラーメッセージを返却 |

### リトライ仕様

- コンパイルエラー：エラー内容を確認後に設定値を修正して再試行
- 非同期コンパイル失敗：管理画面から手動で再コンパイル可能

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

- テーマ割り当て時にトランザクションを使用
- コンパイルと販売チャネル更新を一括でコミット
- エラー発生時はロールバック

## パフォーマンス要件

- テーマ設定取得：1秒以内
- テーマ更新（同期コンパイル）：10秒以内
- テーマ更新（非同期コンパイル）：即時レスポンス（バックグラウンド処理約1分）

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

- **認証**：管理画面API（ApiRouteScope）のみアクセス可能
- **SCSS検証**：悪意のあるSCSS入力によるサーバー攻撃を防止
- **サニタイズ**：HTML/CSS入力のサニタイズ
- **権限**：テーマ管理権限の確認

## 備考

- 非同期コンパイルは`core.storefrontSettings.asyncThemeCompilation`設定で有効化
- コンパイル完了時に管理画面に通知を送信
- テーマはStorefrontPluginRegistryで管理される

---

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

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

### 推奨読解順序

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

まず、テーマエンティティとイベント構造を理解することが重要。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | ThemeEntity.php | `src/Storefront/Theme/ThemeEntity.php` | テーマのDB構造（config_values, parent_theme_id） |
| 1-2 | ThemeConfigChangedEvent.php | `src/Storefront/Theme/Event/ThemeConfigChangedEvent.php` | 設定変更イベント |

**読解のコツ**: ThemeEntityはconfigValuesに設定値を保持。親テーマからの継承関係をparentThemeIdで管理。

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

処理の起点となるコントローラーを特定。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | ThemeController.php | `src/Storefront/Theme/Controller/ThemeController.php` | 管理API側のエントリーポイント |

**主要処理フロー**:
1. **46-60行目**: `configuration`メソッド - テーマ設定取得
2. **77-107行目**: `updateTheme`メソッド - テーマ更新
3. **80行目**: config取得
4. **82-93行目**: validateフラグ時のバリデーション
5. **95-97行目**: resetフラグ時のリセット
6. **99-104行目**: ThemeService::updateTheme呼び出し
7. **123-129行目**: `assignTheme`メソッド - 販売チャネル割り当て
8. **144-150行目**: `resetTheme`メソッド - テーマリセット
9. **165-179行目**: `structuredFields`メソッド - 構造化フィールド取得
10. **193-216行目**: `validateVariables`メソッド - フィールド検証

#### Step 3: テーマサービスを理解する

テーマの更新、コンパイルロジックの中核。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | ThemeService.php | `src/Storefront/Theme/ThemeService.php` | テーマサービス |

**主要処理フロー**:
- **67-100行目**: `compileTheme`メソッド - テーマコンパイル
- **74-78行目**: 非同期コンパイル判定
- **80-88行目**: 同期コンパイル処理
- **107-128行目**: `compileThemeById`メソッド - ID指定コンパイル
- **133-197行目**: `updateTheme`メソッド - テーマ更新
- **154-159行目**: 有効なフィールドのみを保持
- **168行目**: ThemeConfigChangedEventディスパッチ
- **172-185行目**: 設定値のマージ処理
- **199-215行目**: `assignTheme`メソッド - 販売チャネル割り当て
- **201行目**: トランザクション開始
- **217-233行目**: `resetTheme`メソッド - リセット
- **243-289行目**: `validateThemeConfig`メソッド - 設定値検証

#### Step 4: SCSSバリデーションを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | SCSSValidator.php | `src/Storefront/Theme/Validator/SCSSValidator.php` | SCSS検証ロジック |

**読解のコツ**: SCSSValidatorはSCSSコンパイラを使用して設定値の妥当性を検証。

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

```
ThemeController::updateTheme (Admin API)
    │
    ├─ request->request->all('config')
    │
    ├─ [validate=true] ThemeService::validateThemeConfig
    │      │
    │      ├─ getPlainThemeConfiguration
    │      │
    │      └─ SCSSValidator::validate (各フィールド)
    │
    ├─ [reset=true] ThemeService::resetTheme
    │      │
    │      ├─ themeRepository::search
    │      │
    │      ├─ ThemeConfigResetEvent ディスパッチ
    │      │
    │      └─ themeRepository::update(configValues: null)
    │
    └─ ThemeService::updateTheme
           │
           ├─ themeRepository::search
           │
           ├─ 設定値マージ (array_replace_recursive)
           │
           ├─ ThemeConfigChangedEvent ディスパッチ
           │
           ├─ themeRepository::update
           │
           └─ compileThemeById
                  │
                  ├─ getThemeDependencyMapping
                  │
                  └─ compileTheme (各販売チャネル)
                         │
                         ├─ [async=true] CompileThemeMessage → キュー
                         │
                         └─ [async=false] ThemeCompiler::compileTheme
```

### データフロー図

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

themeId ────────────┐
                    │
config ─────────────┼──▶ ThemeController   ───▶ ThemeService
                    │         │                         │
validate ───────────┤         │                         ├──▶ SCSSValidator
                    │         │                         │      (検証)
reset ──────────────┘         │                         │
                              │                         ├──▶ DB: theme
                              │                         │      (UPDATE)
                              │                         │
                              │                         └──▶ ThemeCompiler
                              ▼                                (SCSS→CSS)
                         JsonResponse ◀────────────────────────┘
                    (empty object)                    ファイルシステム出力
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| ThemeController.php | `src/Storefront/Theme/Controller/ThemeController.php` | コントローラー | 管理APIのエントリーポイント |
| ThemeService.php | `src/Storefront/Theme/ThemeService.php` | サービス | テーマ管理の中核ロジック |
| ThemeEntity.php | `src/Storefront/Theme/ThemeEntity.php` | エンティティ | テーマDB構造 |
| ThemeCompilerInterface.php | `src/Storefront/Theme/ThemeCompilerInterface.php` | インターフェース | コンパイラー抽象 |
| ThemeCompiler.php | `src/Storefront/Theme/ThemeCompiler.php` | 実装クラス | SCSSコンパイル |
| SCSSValidator.php | `src/Storefront/Theme/Validator/SCSSValidator.php` | バリデータ | SCSS検証 |
| AbstractScssCompiler.php | `src/Storefront/Theme/AbstractScssCompiler.php` | 抽象クラス | SCSSコンパイラー基底 |
| ThemeConfigChangedEvent.php | `src/Storefront/Theme/Event/ThemeConfigChangedEvent.php` | イベント | 設定変更イベント |
| ThemeAssignedEvent.php | `src/Storefront/Theme/Event/ThemeAssignedEvent.php` | イベント | テーマ割り当てイベント |
| ThemeConfigResetEvent.php | `src/Storefront/Theme/Event/ThemeConfigResetEvent.php` | イベント | リセットイベント |
| CompileThemeMessage.php | `src/Storefront/Theme/Message/CompileThemeMessage.php` | メッセージ | 非同期コンパイル用 |
| ThemeMergedConfigBuilder.php | `src/Storefront/Theme/ThemeMergedConfigBuilder.php` | サービス | 設定マージロジック |
| ThemeRuntimeConfigService.php | `src/Storefront/Theme/ThemeRuntimeConfigService.php` | サービス | ランタイム設定管理 |
