[baserCMS]メールフォームでhtmlメールを使えるようにしてみる


baserCMSのメールフォームで、通知メールにhtmlメールを利用するにはどうするのかな？って場面があったので調べてみました。
現状では、baserCMS側に、text と html メールを切り換える機能はないため、作るとしたらこんな感じになるかなぁ、といった例です。

その前に、先に簡単な方法挙げておくと、こんな感じに手を加えて、後述するhtmlメール用のテンプレを作るだけで可能です。

```php:/lib/Baser/Plugin/Mail/Controller/MailController.php
$options['format'] = 'html';
$this->sendMail($userMail, $mailContent['subject_user'], $data, $options);
```


## 想定している対象者
- baserCMSでウェブサイトを制作をしている方
- HTMLコーディングを主とするフロントエンジニア
	- htmlメールを作る方
- PHPer, CakePHPer, baserSer（ん？）


### 環境
- 普通のLAMP
 - PHP 5.4.19
 - baserCMS 3.0.5.1, 4.0.10.1


## 準備

コントローラーイベントディスパッチャにディスパッチ内容を追加。

### 定義の追加（2箇所）

```php:/lib/Baser/Event/BcControllerEventDispatcher.php
public function implementedEvents() {
	return array(
		// 既存の定義が並んでるところに、以下の1行を追加
+		'Controller.beforeSendEmailMoment'	 => array('callable' => 'beforeSendEmailMoment'),
	);
}
```

```php:/lib/Baser/Event/BcControllerEventDispatcher.php
// メソッド群の最後とかに以下を追加
public function beforeSendEmailMoment(CakeEvent $event) {
	if ($event->subject->name != 'CakeError' && $event->subject->name != '') {
		if (!method_exists($event->subject(), 'dispatchEvent')) {
			return;
		}
		$event->subject->dispatchEvent('beforeSendEmailMoment', $event->data);
	}
}
```

この準備をすることで、コントローライベントで beforeSendEmailMoment が利用できるようになります。

### 発火場所の追加

メール送信処理の直前に、option値を渡すディスパッチャーを追加。
これをすることで、引数に渡ってきている $options の内容を、後述するイベント処理に渡すことができるようになります。

```php:/lib/Baser/Controller/BcAppController.php
public function sendMail($to, $title = '', $body = '', $options = array()) {
	$options = array_merge(array(
		'agentTemplate' => true,
		'template' => 'default'
	), $options);

+	// beforeSendEmailMoment
+	$event = $this->dispatchEvent('beforeSendEmailMoment', array(
+		'data' => $options,
+	));
+	if ($event !== false) {
+		$options = $event->result === true ? $event->data['data'] : $event->result;
+	}

	※以降、省略
```


## イベント処理の作成
任意のプラグイン内に、コントローライベントを作ります。
このサンプル例では、通知メールをhtmlメールとするフォームをどれにするか、コンテンツ名を見て対象判別する例を入れてます。

```php:/app/Plugin/Hoge/Event/HogeControllerEventListener.php
<?php
class HogeControllerEventListener extends BcControllerEventListener {

	public $events = array(
		'Mail.Mail.beforeSendEmailMoment',
	);

	/**
	 * mailMailBeforeSendEmailMoment
	 * 
	 * @param CakeEvent $event
	 * @return boolean
	 */
	public function mailMailBeforeSendEmailMoment(CakeEvent $event) {
		if (BcUtil::isAdminSystem()) {
			return;
		}

		$Controller = $event->subject();

		$mailContent = Hash::get($Controller->dbDatas, 'mailContent');
		// フォームのコンテンツネームを指定して対象判別する例
		if ($mailContent['MailContent']['name'] === 'TARGET_MAIL_CONTENTS_NAME') {
			$event->data['data']['format'] = 'html';
		}

		return true;
	}

}
```


## HTMLメールのビューを作る

動作する準備ができたら、HTML通知メール用のビューを配置します。

### HTML通知メール用のレイアウトを作成

```php:/theme/YOUR_THEME/Layouts/Emails/html/default.php

<?php
/**
 * HTML通知メール用レイアウト
 */
?>
<html>
<head>
	<meta name="viewport" content="width=device-width" />
	<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
	<title><?php echo $this->fetch('title'); ?></title>
	<style type="text/css">
		/* htmlメールに適用するスタイルを書く */
	</style>
</head>
<body>
	<?php echo $this->fetch('content'); ?>
</body>
</html>
```

### HTML通知メール用のレイアウトが適用される中身を作成
/lib/Baser/Plugin/Mail/View/Emails/text/mail_default.php の内容をもとにして、html 形式で内容を書くと良いです。
ここで書くのは、通知メールの案内文とかの概要にしておくと良いです。

```php:/theme/YOUR_THEME/Emails/html/mail_default.php
<?php
/**
 * [EMAIL] メール送信: HTML
 */
?>
<?php if ($other['mode'] === 'user'): ?>
	<p>この度は、お問い合わせいただきありがとうございます。<br>送信内容は下記のようになっております。</p>
<?php elseif ($other['mode'] === 'admin'): ?>
	<p>お問い合わせを受け付けました。受信内容は下記のとおりです。</p>
<?php endif; ?>
<?php echo $this->element('../Emails/html/mail_data'); ?>
```

実際の入力内容が、HTMLに反映される箇所を書いて行きます。
このサンプルでは、管理側で定義したメールフィールド名をもとに対象フィールドの値を抜き出してます。
通常は each で回しながら取ってくる箇所を、html構造では、任意の箇所に任意の入力値を表示するための処理です。
「YOUR_FIELD_NAME」＝メールフィールド名、です。

```php:/theme/YOUR_THEME/Emails/html/mail_data.php
<?php
/**
 * [EMAIL] メール送信データ: HTML
 */
?>
<h3>サンプル項目名</h3>
<?php
$targetFieldList = Hash::extract($mailFields, '{n}.MailField[field_name=YOUR_FIELD_NAME]');
if ($targetFieldList) {
	$targetField = $targetFieldList[0];
	echo $this->Maildata->control($targetField['type'], $message[$targetField['field_name']], $this->Mailfield->getOptions($targetField));
}
?>

<h3>サンプル項目名2</h3>
<?php
$targetFieldList = Hash::extract($mailFields, '{n}.MailField[field_name=YOUR_FIELD_NAME]');
if ($targetFieldList) {
$targetField = $targetFieldList[0];
echo $this->Maildata->control($targetField['type'], $message[$targetField['field_name']], $this->Mailfield->getOptions($targetField));
}
?>
```

## 終わり
ここまでやってみて、あとはメールフォームの送信動作してみると良いです。
ローカルでのお試しには [mailcather](http://www.materializing.net/archives/2016/02/07184547.php)とか使うと良いです。

あと、メールフォーム設定内の「送信メールテンプレート名」はそのまま適用されます。
mail_default ならこのまま。mail_your_template に変えてる場合は、
/theme/YOUR_THEME/Emails/html/mail_your_template.php になる、ということです。

フォームの入力値を、フィールド名を元にして取ってこれるようなヘルパメソッドがあると良いかもですね。