Laravelでイベントを用いてメールを送信する

## 概要
Laravelのイベントとリスナーを使って、フォームからの問い合わせが来たときに、通知メールを送信する処理を実装します。

## 実行環境
https://qiita.com/ucan-lab/items/5fc1281cd8076c8ac9f4

上記の記事を参考に、GitHubのテンプレートリポジトリから環境を構築しています。

Laravel6.*


## 実装の大まかな流れ
1. 環境変数にメール送信に必要な情報を設定
2. メール送信用クラスの作成
3. メールのViewを作成 
4. イベントの作成
5. リスナーの作成
6. イベントとリスナーを紐づけ
7. イベントの発行

### 環境変数(.env)に必要情報を設定

```env:.env
MAIL_DRIVER=smtp
MAIL_HOST=XXXXX.jp　//サーバのドメイン名やIPアドレス
MAIL_PORT=587　//ポート番号は各環境に依存
MAIL_USERNAME=XXXXX@XXXXX.co.jp　//メールで利用するユーザ名
MAIL_PASSWORD=XXXXX //メールで利用するパスワード
MAIL_ENCRYPTION=null
MAIL_FROM_ADDRESS=XXXXX@XXXXX.co.jp //メールの送信元アドレス
ACCEPT_MAIL_ADDRESS=XXXXX@XXXXX.co.jp // メールの送信先アドレス

```

```php:\config\app.php
<?php

return [
    'aliases' => [
    // 省略
    ],

    // 問い合わせ用メールアドレスを設定
    'mail_from_address' => env('MAIL_FROM_ADDRESS'),
    'accept_mail_address' => env('ACCEPT_MAIL_ADDRESS'),
];

```

### メール送信用クラスの作成
app\Mail配下にContactMail.phpを作成

```
$ php artisan make:mail ContactMail
```

### メール送信用クラスの編集
```php:ContactMail.php
<?php

namespace App\Mail;

use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;

class ContactMail extends Mailable
{
    use Queueable, SerializesModels;

　　// 追記
    private $contact;

    /**
     * Create a new message instance.
     *
     * @return void
     */
    public function __construct($contact)　// コンストラクタの引数で値を受け取る
    {
        // ContactMailクラスのprivate変数に引数の値を代入
        $this->contact = $contact;
    }

    /**
     * Build the message.
     *
     * @return $this
     */
    public function build()
    {
        return $this
            ->from(config('app.mail_from_address')) // 送信元のメールアドレスを指定
            ->subject('お問い合わせ完了のご連絡') // メールの件名
            ->view('emails.contact_mail') // どのテンプレートを呼び出すか
            ->with(['contact' => $this->contact]); // withオプションでセットしたデータをテンプレートへ受け渡す
    }
}

```

### メール送信用のViewを作成
resources\views配下にemailsフォルダを作成

```
$ mkdir emails
```
フォルダ作成後、resources\views\emails配下に、contact_mail.blade.phpを作成

### メール送信のViewを編集
```php:contact_mail.blade.php
<html>
    <head>
        <title>sample</title>
    </head>
    <body>
        メール送信しました
    </body>
</html>

```



### イベントの作成
app\Events配下にContactRequestCompleted.phpを作成


```
$ php artisan make:event ContactRequestCompleted
```

### イベントの編集
イベントのコンストラクタを修正
イベント発火時に必要な情報をコンストラクタで渡しておく。

```php:ContactRequestCompleted.php
class ContactRequestCompleted
{
    use Dispatchable, InteractsWithSockets, SerializesModels;

　　// 追記
    public $contact;

    /**
     * Create a new event instance.
     *
     * @return void
     */
    public function __construct($post)　// コンストラクタの引数でフォームから値を受け取る
    {
        // ContactRequestCompletedクラスのpublic変数に引数の値を代入
        $this->contact = $post;
    }

    /**
     * Get the channels the event should broadcast on.
     *
     * @return \Illuminate\Broadcasting\Channel|array
     */
    public function broadcastOn()
    {
        return new PrivateChannel('channel-name');
    }
}

```

### リスナーの作成
app\Listeners配下にSendContactRequestEmail.phpを作成

```
$ php artisan make:listener SendContactRequestEmail
```

### リスナーの編集
SendContactRequestEmail内のhandleメソッドを修正
handleメソッド内に、メール送信などの具体的な処理を追加する。

```php:SendContactRequestEmail.php
<?php

namespace App\Listeners;

use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;

use Mail;
use App\Mail\ContactMail;

class SendContactRequestEmail
{
    /**
     * Create the event listener.
     *
     * @return void
     */
    public function __construct()
    {
        //
    }

    /**
     * Handle the event.
     *
     * @param  object  $event
     * @return void
     */
    public function handle($event)
    {
        // メールの送信先アドレスに、.envで指定したACCEPT_MAIL_ADDRESSの値を代入
        $to_address_admin = config('app.accept_mail_address');
        // 送信先アドレスにメールを送信
        Mail::to($to_address_admin)->send(new ContactMail($event->contact));
    }
}

```

### イベントとリスナーを紐づけ
Providers\EventServiceProvider.phpを編集

```php:EventServiceProvider.php
<?php

namespace App\Providers;

use Illuminate\Auth\Events\Registered;
use Illuminate\Auth\Listeners\SendEmailVerificationNotification;
use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;
use Illuminate\Support\Facades\Event;

use App\Events\ContactRequestCompleted;
use App\Listeners\SendContactRequestEmail;

class EventServiceProvider extends ServiceProvider
{
    /**
     * The event listener mappings for the application.
     *
     * @var array
     */
    protected $listen = [
        Registered::class => [
            SendEmailVerificationNotification::class,
        ],
        // 作成したイベントと紐付けたいリスナーを追記
        ContactRequestCompleted::class => [
            SendContactRequestEmail::class,
        ],
    ];

    /**
     * Register any events for your application.
     *
     * @return void
     */
    public function boot()
    {
        parent::boot();

        //
    }
}

```

### イベントの発行
コントローラー等にイベントの発行処理を追加

```php:SampleController.php
use App\Events\ContactRequestCompleted;

class SampleController extends Controller
{
     // イベントの発火処理(引数で値渡しが可能)
     event(new ContactRequestCompleted($post));
}

```