# 通知設計書 46-Mail Before Validate

## 概要

本ドキュメントは、ShopwareにおけるMailBeforeValidateEventの仕様を定義する設計書である。これはメール通知ではなく、メール送信前の検証フェーズで発火されるイベント通知であり、開発者がメールデータを変更・検証するためのフックポイントを提供する機能について記載する。

### 本通知の処理概要

本イベントは、MailServiceがメールを送信する直前のバリデーションフェーズで発火されるシステムイベントである。これにより、開発者やプラグインはメールデータ（受信者、件名、本文、テンプレートデータなど）を送信前に検査・変更することができる。

**業務上の目的・背景**：ECシステムでは、送信されるメールの内容を動的に変更したり、特定の条件で送信を抑止したりするニーズがある。例えば、特定の顧客グループへのメール内容をカスタマイズする、メールヘッダーを追加する、ログ目的でメール内容を記録する、といったユースケースに対応するため、メール送信パイプラインにフックポイントを提供している。

**通知の送信タイミング**：MailService::send()メソッドの最初のステップとして発火される。バリデーション実行前、メールオブジェクト作成前に呼び出される。

**通知の受信者**：イベントリスナーとして登録されたPHPクラス。プラグインやカスタムコードからEventSubscriberとして登録する。

**通知内容の概要**：メール送信に使用されるdata配列（受信者、件名、本文HTML、本文プレーン、添付ファイル等）とtemplateData配列（テンプレート変数）が含まれる。

**期待されるアクション**：イベントリスナーはデータを検査・変更し、必要に応じてイベントの伝播を停止（stopPropagation）することでメール送信を抑止できる。

## 通知種別

イベント通知（システムイベント）

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| イベント方式 | 同期（EventDispatcher） |
| 発火タイミング | メールバリデーション前 |
| 伝播停止 | 可能（stopPropagation） |

### イベントリスナー登録方法

```php
use Shopware\Core\Content\MailTemplate\Service\Event\MailBeforeValidateEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;

class MyMailSubscriber implements EventSubscriberInterface
{
    public static function getSubscribedEvents(): array
    {
        return [
            MailBeforeValidateEvent::class => 'onMailBeforeValidate',
        ];
    }

    public function onMailBeforeValidate(MailBeforeValidateEvent $event): void
    {
        // メールデータを変更
        $data = $event->getData();
        $data['subject'] = 'Modified: ' . $data['subject'];
        $event->setData($data);
    }
}
```

## イベントプロパティ

### イベントクラス

| プロパティ | 型 | 説明 | 変更可能 |
|-----------|-----|------|---------|
| data | array | メール送信データ | Yes（setData） |
| context | Context | Shopwareコンテキスト | No |
| templateData | array | テンプレート変数 | Yes（setTemplateData） |

### data配列の構造

| キー | 型 | 説明 |
|-----|-----|------|
| recipients | array | 受信者（email => name） |
| senderName | string | 送信者名 |
| senderMail | string | 送信者メールアドレス |
| subject | string | 件名 |
| contentHtml | string | HTML本文 |
| contentPlain | string | テキスト本文 |
| salesChannelId | string | 販売チャネルID |
| mediaIds | array | 添付メディアID |
| binAttachments | array | バイナリ添付ファイル |

### templateData配列の構造

| キー | 型 | 説明 |
|-----|-----|------|
| eventName | string | トリガーイベント名 |
| salesChannel | SalesChannelEntity | 販売チャネルエンティティ |
| order | OrderEntity | 注文エンティティ（注文関連の場合） |
| customer | CustomerEntity | 顧客エンティティ（顧客関連の場合） |
| （その他） | mixed | イベント固有のデータ |

## テンプレート変数

本イベントはメールテンプレートを使用しないため、該当なし。

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 発火条件 | 説明 |
|------------|----------------|---------|------|
| MailService | send()メソッド | 常時 | メール送信リクエスト発生時 |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| stopPropagation() | リスナーがイベント伝播を停止した場合、メール送信がスキップされる |

## 処理フロー

### イベントフロー

```mermaid
flowchart TD
    A[MailService::send呼び出し] --> B[MailBeforeValidateEvent生成]
    B --> C[EventDispatcher::dispatch]
    C --> D{リスナー処理}
    D --> E[リスナー1: データ変更]
    E --> F[リスナー2: ログ記録]
    F --> G{stopPropagation?}
    G -->|Yes| H[メール送信スキップ return null]
    G -->|No| I[イベントからデータ取得]
    I --> J[バリデーション実行]
    J --> K[メール作成・送信]
    H --> L[終了]
    K --> L
```

## データベース参照・更新仕様

### 参照テーブル一覧

本イベント自体はデータベースを参照しない。templateDataに含まれるエンティティは、呼び出し元で事前に取得されている。

### 更新テーブル一覧

本イベント自体はデータベースを更新しない。

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| リスナー例外 | イベントリスナー内で例外発生 | 例外伝播、メール送信中断 |
| データ不正 | setData()で不正なデータ設定 | バリデーションフェーズでエラー |

### リトライ仕様

本イベントはリトライ対象外。同期処理で即座に完了する。

## 配信設定

### レート制限

本イベントにレート制限なし。

### 配信時間帯

制限なし。メール送信リクエスト発生時に即座に発火。

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

- イベントリスナーは信頼されたコードのみ登録すべき
- メールデータにセンシティブ情報が含まれる可能性があるため、ログ出力時は注意
- binAttachmentsはログデータから除外される（getLogData()で削除）

## 備考

- イベント名定数：MailBeforeValidateEvent::EVENT_NAME = 'mail.before.send'
- LogAwareインターフェース実装によりMonolog経由でログ出力可能
- FlowEventAware実装によりFlowビルダーでの利用も可能（ただし主な用途はEventSubscriber）

---

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

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

### 推奨読解順序

#### Step 1: イベントクラスを理解する

イベントクラスの構造とインターフェースを確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | MailBeforeValidateEvent.php | `src/Core/Content/MailTemplate/Service/Event/MailBeforeValidateEvent.php` | イベント名（20行目）、コンストラクタ（26-31行目）、getter/setter |

**読解のコツ**: LogAware, ScalarValuesAware, FlowEventAwareを実装。data配列とtemplateData配列を保持し、セッター経由で変更可能。

#### Step 2: イベント発火箇所を理解する

MailServiceでのイベント発火タイミングを確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | MailService.php | `src/Core/Content/Mail/Service/MailService.php` | send()メソッド内（64-71行目）でのイベント発火 |

**主要処理フロー**:
1. **64行目**: MailBeforeValidateEvent生成（$data, $context, $templateData）
2. **65行目**: eventDispatcher->dispatch() - イベント発火
3. **66-68行目**: isPropagationStopped()チェック - 停止時はnull返却
4. **70-71行目**: イベントから変更後のdata, templateDataを取得

#### Step 3: データ変更機能を理解する

イベントでのデータ変更方法を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | MailBeforeValidateEvent.php | `src/Core/Content/MailTemplate/Service/Event/MailBeforeValidateEvent.php` | setData()（67-70行目）、addData()（75-78行目）、setTemplateData()（96-99行目） |

**主要メソッド**:
- **setData()**: data配列全体を置換
- **addData()**: data配列に項目追加
- **setTemplateData()**: templateData配列全体を置換
- **addTemplateData()**: templateData配列に項目追加

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

```
MailService::send($data, $context, $templateData)
    │
    ├─ new MailBeforeValidateEvent($data, $context, $templateData)
    │
    ├─ eventDispatcher->dispatch(MailBeforeValidateEvent)
    │      │
    │      ├─ EventSubscriber A: onMailBeforeValidate()
    │      │      └─ $event->setData() / addData()
    │      │
    │      ├─ EventSubscriber B: onMailBeforeValidate()
    │      │      └─ $event->setTemplateData() / addTemplateData()
    │      │
    │      └─ EventSubscriber C: onMailBeforeValidate()
    │             └─ $event->stopPropagation() (オプション)
    │
    ├─ if ($event->isPropagationStopped()) return null
    │
    ├─ $data = $event->getData()
    │
    ├─ $templateData = $event->getTemplateData()
    │
    └─ dataValidator->validate($data, ...) - バリデーション続行
```

### データフロー図

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

MailService::send()             MailBeforeValidateEvent              変更後データ
  │                                  │                                    │
  ├─ data (recipients,               ├─ EventDispatcher                   ├─ data (変更可)
  │        subject, etc.)            │                                    │
  └─ templateData                    ├─ Subscribers                       └─ templateData (変更可)
     (eventName,                     │    ├─ setData()
      salesChannel, etc.)            │    ├─ addData()
                                     │    ├─ setTemplateData()
                                     │    └─ stopPropagation()
                                     │
                                     └─ 伝播制御
                                          │
                                          ├─ 続行: バリデーション
                                          └─ 停止: return null
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| MailBeforeValidateEvent.php | `src/Core/Content/MailTemplate/Service/Event/MailBeforeValidateEvent.php` | ソース | イベントクラス定義 |
| MailService.php | `src/Core/Content/Mail/Service/MailService.php` | ソース | イベント発火箇所 |
| BusinessEventRegistry.php | `src/Core/Framework/Event/BusinessEventRegistry.php` | ソース | イベント登録 |
| BusinessEvents.php | `src/Core/Framework/Event/BusinessEvents.php` | ソース | イベント定数 |
