Laravel6.xでパスワードリセットメールをカスタマイズする

## やりたいこと
* Laravelのauthで導入されるログイン機能は便利だけど、パスワードリセットやメール認証のメールが英語なので、日本語にしたい。
* 言語ファイルいじるだけでも日本語化は出来るが、できれば好きなデザイン・内容にしたい。

## 環境
* Laravel 6.x (執筆時点では6.5.2)

```
$ php artisan --version
Laravel Framework 6.5.2
```

* 事前に[認証機能の導入](https://readouble.com/laravel/6.x/ja/authentication.html)を済ませている。
    * 具体的に言うと下記コマンドを実行済みで、プロジェクトも作ってある。

```
$ composer require laravel/ui "^1.0" --dev
$ php artisan ui vue --auth
```

## 大雑把な流れ
* Userクラスの通知関数をオーバーライド
* そこで用いるためのNotificationを作成、コーディング
* メール文面を作成

## 手順（パスワードリセットの場合）

### 通知クラスの作成

artisanを利用してまずは空で作る。中身は後の手順で書く。

```
$ php artisan make:notification PasswordResetNotification
Notification created successfully.
```

これで `app/Notifications/PasswordResetNotification.php` が作成される。

### Userクラスの通知関数をオーバーライド

既存のUserモデルクラスに対して、以下のオーバーライド処理を**追記**する。

```app/User.php
    /**
     * Override to send for password reset notification.
     *
     * @param [type] $token
     * @return void
     */
    public function sendPasswordResetNotification($token)
    {
        $this->notify(new PasswordResetNotification($token));
    }
```

### 通知クラスの中身をコーディング

1からNotificationクラスを書いても良いけど、折角なのでデフォルトで導入されて使われている `ResetPassword` クラスをパクｒ……継承して使わせてもらう。
まずは全文がこちら。

```app/Notifications/PasswordResetNotification.php
<?php

namespace App\Notifications;

use Illuminate\Bus\Queueable;
use Illuminate\Notifications\Messages\MailMessage;
use Illuminate\Auth\Notifications\ResetPassword;

class PasswordResetNotification extends ResetPassword
{
    use Queueable;

    /**
     * Get the mail representation of the notification.
     *
     * @param  mixed  $notifiable
     * @return \Illuminate\Notifications\Messages\MailMessage
     */
    public function toMail($notifiable)
    {
        if (static::$toMailCallback) {
            return call_user_func(static::$toMailCallback, $notifiable, $this->token);
        }

        return (new MailMessage)
                    ->subject('パスワードリセット通知')
                    ->view('emails.password_reset', [
                        'reset_url' => url(config('app.url').route('password.reset', ['token' => $this->token, 'email' => $notifiable->getEmailForPasswordReset()], false))
                    ]);
    }
}
```

順に解説する。
`make:notification` 時でデフォルトで書かれている内容は割愛するが、以下の関数は不要なので削除してしまう（オーバーライドの必要性がない）。

* `__construct()`
* `via()`
* `toArray()`

次に `use` について。

```php
use Illuminate\Auth\Notifications\ResetPassword;
```

こちらを追加しておく。
今回のカスタマイズをしない場合に使用されるのがこのクラスなので、つまりこれをありがたく流用させてもらうことで、がっつりと手間を省いてしまう。
なので `extends` の部分も、

```php
class PasswordResetNotification extends ResetPassword
```

としておく。
もとは `extends Notification` だがここを流用するクラスに変えておく。

あとはメール送信部分である `toMail()` だけコーディングしてあげれば良い。

```php
    /**
     * Get the mail representation of the notification.
     *
     * @param  mixed  $notifiable
     * @return \Illuminate\Notifications\Messages\MailMessage
     */
    public function toMail($notifiable)
    {
        if (static::$toMailCallback) {
            return call_user_func(static::$toMailCallback, $notifiable, $this->token);
        }

        return (new MailMessage)
                    ->subject('パスワードリセット通知')
                    ->view('emails.password_reset', [
                        'reset_url' => url(config('app.url').route('password.reset', ['token' => $this->token, 'email' => $notifiable->getEmailForPasswordReset()], false))
                    ]);
    }
```

if文部分は流用元そのままなので、そのまま利用。

件名を `->subject()` の引数に入れておき、メールで送りたいViewを `->view()` で指定してあげればOK。
ここでは `'emails.password_reset'` を指定しているので、 `resources/views/emails/password_reset.blade.php` がViewとして扱われてメールで送られていく、ということになる。

`view()` 指定で送るようにすれば、Bladeテンプレートが利用できるのでとても便利。
第2引数にはArrayで変数を送ることもできる。上記の例でリンクURLとして使用するための `url(config('app.url').～～` としている部分は、流用元そのままなので深く考えずにコピペで良いと思う。

### メール文面の作成

あとは普段通りにViewを作るだけ！

## 手順（メール認証の場合）

基本的にはパスワード認証と同じ。以下の点が異なるだけ。

* 継承元クラスは `VerifyEmail` になる。
    * `use Illuminate\Auth\Notifications\VerifyEmail;` になる。
* `toMail()` のコードは以下のような感じ。

```php
    public function toMail($notifiable)
    {
        $verificationUrl = $this->verificationUrl($notifiable);

        if (static::$toMailCallback) {
            return call_user_func(static::$toMailCallback, $notifiable, $verificationUrl);
        }

        return (new MailMessage)
                    ->subject('メール認証')
                    ->view('emails.email_verify', [
                        'verify_url' => $verificationUrl
                    ]);
    }
```

* view側で `verify_url` の変数参照する際は `{{ $verify_url }}` ではなく `{!! $verify_url !!}` とする。URL内にアンパサンドが入ってくるので。

## 参考：Framework側のコード

困ったらFramework側のコードを見てしまうと参考になるかも。
このあたり。

* `vendor\laravel\framework\src\Illuminate\Auth\Notifications`
    * ResetPassword.php
    * VerifyEmail.php
* `vendor\laravel\framework\src\Illuminate\Notifications\resources\views`
    * email.blade.php

単に日本語化するだけであれば、今回のような手間をかけなくても、上記のファイルを見ながら `resources\lang\ja.json` にゴリゴリと対訳を書いてしまうだけでも良い。

* [多言語化 6\.x Laravel](https://readouble.com/laravel/6.x/ja/localization.html)

## 参考URL
* [Laravel5\.7のEmail Verificationを読む \- Laravelコードリーディング \- Qiita](https://qiita.com/yamaji_daisuke/items/731868a4de6037794976)
* [Laravelパスワードリセットメールの文面・デザインを変更する](https://www.ritolab.com/entry/52#customize_password_reset_email)
* [パスワードリセット 6\.x Laravel](https://readouble.com/laravel/6.x/ja/passwords.html)
* [通知 6\.x Laravel](https://readouble.com/laravel/6.x/ja/notifications.html)