【Laravel】メール送信内容をバリデーションする方法（with フォームリクエスト）。エラーメッセージの変更方法など

Laravelの**フォームリクエスト**という便利機能を使ってバリデーションを実装する方法について。

[フォームリクエストを使わないコントローラのみのバリデーション方法](https://qiita.com/yuta-38/items/bc1dd1e63749186a4a7b)の続きです。


>メール送信機能の作成方法については以下を参照。
・[【Laravel】Localhostでgmailを使ってメールを送信する方法。Mailableを使わない方法](https://qiita.com/yuta-38/items/5db343324b967046f7e1)

>・[【Laravel】Mailableを使ってメールを送信する方法。データや画像を添付する方法や入力データをメール本文に渡す方法](https://qiita.com/yuta-38/items/77543199f1150d71e2bf)



##目次

1. [フォームリクエストとは？](#フォームリクエストとは)
2. [フォームリクエストの作成](#1-フォームリクエストの作成)
3. [バリデーションルールの作成](#2-バリデーションルールの作成)
4. [authorizeメソッドの編集](#3-authorizeメソッドの編集)
5. [コントローラの編集](#4-コントローラの編集)
6. [バリデーション処理の確認](#5-バリデーション処理の確認)
7. [エラーメッセージの変更](#エラーメッセージの変更)
8. [（参考）使用コード一覧](#参考使用コード一覧)


<br>
##フォームリクエストとは？
バリデーションのコードをコントローラの外に記述する方法。Requestsディレクトリの中のファイルに専用のクラスを作成する。

**バリデーションはコントローラにデータを渡す前に実行**される。


##1. フォームリクエストの作成
以下コマンドを使えばファイルが自動生成できる。（自分でクラスを作成することもできる）

・`$ php artisan make:request フォームリクエスト名`

<br>
**▼実例**

```
$ php artisan make:request MailFormRequest
Request created successfully.
```

ファイルは、app > Http > Requests　配下に生成される。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/563526/c2c133fc-4b22-5d06-7705-254a8f589724.png)


###フォームリクエストの中身

```php:
<?php

namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;

class MailFormRequest extends FormRequest
{
    /**
     * Determine if the user is authorized to make this request.
     *
     * @return bool
     */
    public function authorize()
    {
        return false;
    }

    /**
     * Get the validation rules that apply to the request.
     *
     * @return array
     */
    public function rules()
    {
        return [
            //
        ];
    }
}
```

認証関連のバリデーションを行う`authorize`メソッドと、バリデーションルールを記述する`rules`メソッドが用意されている。


<br>
##2. バリデーションルールの作成
ルールは`rules`メソッドの中に記述する。


```php:
    public function rules()
    {
        return [
            'name' => 'required|min:3|max:10',
        ];
    }
```

ルールを複数設置する場合はカンマでつなげていく。

**・`'name' => 'required|min:3|max:10'`**
渡されたname属性に対し、`required`(必須)、`min:3`(３文字以上)、`max:10`（10文字以下）の３つのルールを適用している。


<br>
##3. authorizeメソッドの編集
フォームリクエストの`authorize`メソッドは初期状態でfalseになっている。

この状態だと認証をパスしていない場合は`403 | 
THIS ACTION IS UNAUTHORIZED.`に飛ばされる。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/563526/e2f143ef-4bee-2756-3826-cd59eeebabd0.png)

今回は認証設定をしないため、この値をtrueに変更する。

```php:
    public function authorize()
    {
        return true;
    }
```


<br>
##4. コントローラの編集
###4-1. 冒頭で作成したフォームリクエストのuse宣言をする。

・`use App\Http\Requests\[フォームリクエスト名];`


###4-2. sendアクションにバリデーション後のデータを渡す

・`public function send([フォームリクエスト名] $変数)`

DI（依存注入）で、フォームリクエストクラスのインスタンスを変数に入れて渡す。


**▼実例**

```php:
<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Mail;                   //Mailファサード使用
use App\Mail\ValidatedMail; //Mailable使用
use App\Http\Requests\MailFormRequest;  //追記（フォームリクエスト）

class ValidatorController extends Controller
{
    public function index() //コンタクトフォームの表示
    {
        return view('contact.validate');
    }

    public function send(MailFormRequest $validatedRequest)  //メールの自動送信設定
    {
        $data = $validatedRequest;

        Mail::to('xxx@gmail.com')
                ->send(new ValidatedMail($data));

        return back()->withInput()
                     ->with('sent', '送信完了しました。');    //送信完了を表示
    }
}
```


以上で設定が完了。


###5. バリデーション処理の確認

|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/563526/d7bb5bed-95f2-077e-4de4-2a095028d73c.png)|
|:--|

設定通りにバリデーションできた。



<br>
##エラーメッセージの変更
デフォルトでは英語の定型メッセージが表示されるため、これを好きな文字列に変更する。

フォームリクエストに`messages`メソッドを追加して戻り値で指定する。

```php:
    public function messages()
    {
        return [
            'name.required' => '名前を入力して下さい。',
            'name.max' => ':max 文字以下で入力して下さい。',
            'name.min' => ':min 文字以上で入力して下さい。',
        ];
    }
```

カスタムメッセージの指定方法は２パターン。今回は(2)を使用。

**（１）ルール毎にメッセージを指定する場合**
・'ルール' => 'カスタムメッセージ'

**（２）属性に適用したルール毎にメッセージを指定する場合**
・'属性名.ルール' => 'カスタムメッセージ'


<br>
**▼処理の確認**

|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/563526/8bca0db5-7ba9-3113-3d5f-f1af613c4541.png)|
|:--|

以上で完了。


<br>
##（参考）使用コード一覧
今回のテストで使用したファイルとコードは以下。

1. 環境変数
2. ルーティング
3. コントローラ
4. Mailableクラス
5. フォームリクエスト
6. コンタクトフォーム
7. メール本文




###1. 環境変数

```:.env
MAIL_MAILER=smtp
MAIL_HOST=smtp.gmail.com
MAIL_PORT=587
MAIL_USERNAME=your address@gmail.com
MAIL_PASSWORD=your app password
MAIL_ENCRYPTION=tls
MAIL_FROM_NAME="mail title"
```


###2. ルーティング

```php:web.php
//Validatorファサード
Route::get('validator', 'ValidatorController@index');
Route::post('validator', 'ValidatorController@send');
```


###3. コントローラ

```php:ValidatorController.php
<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Mail;                   //追記
use App\Mail\ValidatedMail; //追記
use App\Http\Requests\MailFormRequest;  //追記（フォームリクエスト）

class ValidatorController extends Controller
{
    //以下追記
    public function index() //コンタクトフォームの表示
    {
        return view('contact.validate');
    }

    public function send(MailFormRequest $validatedRequest)  //メールの自動送信設定
    {
        $data = $validatedRequest;

        Mail::to('xxx@gmail.com')
                ->send(new ValidatedMail($data));

        return back()->withInput()
                     ->with('sent', '送信完了しました。');    //送信完了を表示
    }
}
```


###4. Mailableクラス

```php:ValidatedMail.php
<?php

namespace App\Mail;

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

class ValidatedMail extends Mailable
{
    use Queueable, SerializesModels;
    public $data;
    /**
     * Create a new message instance.
     *
     * @return void
     */
    public function __construct($data)
    {
        $this->data = $data;
    }

    /**
     * Build the message.
     *
     * @return $this
     */
    public function build()
    {
        //以下追記
        return $this->view('emails.validated')
                    ->subject('メールの標題')
                    ->with('data', $this->data);
    }
}
```


###5. フォームリクエスト

```php:MailFormRequest.php
<?php

namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;

class MailFormRequest extends FormRequest
{
    /**
     * Determine if the user is authorized to make this request.
     *
     * @return bool
     */
    public function authorize()
    {
        return true;
    }

    /**
     * Get the validation rules that apply to the request.
     *
     * @return array
     */
    public function rules()
    {
        return [
            'name' => 'required|min:3|max:10',
        ];
    }


    public function messages()
    {
        return [
            'name.required' => '名前を入力して下さい。',
            'name.max' => ':max 文字以下で入力して下さい。',
            'name.min' => ':min 文字以上で入力して下さい。',
        ];
    }
}

```


###6. コンタクトフォーム

```php:validate.blade.php
@if ( Session::has('sent'))
<div>
    <p>{{old('name')}}さん、{{ session('sent') }}</p>
</div>
@endif

<form action="{{ url('validator') }}" method="POST">
@csrf

 <p>名前：<input type="text" name="name" value="{{ old('name') }}" ></p>
  @error('name')
    <p style="color:red;">{{ $message }}</p>
  @enderror

 <input type="submit" value="送信する">
</form>
```



###7. メール本文

```php:validated.blade.php
<p>名前：{{ $data['name'] }}さんから連絡がありました。</p>
```




<br>
##まとめ
これまで、以下３つの方法でバリデーションを試してきた。

1. Requestファサードのvalidateメソッドでコントローラに直接記述
2. Validatorファサードでコントローラに直接記述
3. フォームリクエストを使用

<br>
カスタムメッセージを表示したり、バリデーションを使いまわすなど**利便性が高いのは、(3)のフォームリクエスト**。

**管理するファイル数を増やしたくない場合は(2)のValidatorファサード**の使用がいいと感じた。