Laravelでvalidation

前回作成した[「LaravelでCRUD」](https://qiita.com/apricotcomic/items/07f172a957c1f342fd91)にvalidationを追加する。
ついでにメッセージの日本語化もしていくよ。Go my way!

#validateを追加する
##新規登録の時は必ずチェック！
validationはチェックしたい内容を列挙するだけでやってくれる。便利になったものだね。
試しに追加してみると、こんな感じ。

```php:AdminController.php
public function store(Request $request)
{
    if($request->action === 'back') {
        return redirect()->route('admin.index');
    }
    // validation ここから追加
    $rules = [
        'admin_code' => ['required', 'integer', 'unique:admin'],
        'role' => ['size:1'],
        'password' => ['required', 'string', 'min:8', 'confirmed']
    ];
    $this->validate($request, $rules);
    // ここまで追加
    $admin = new Admin;
    $admin->admin_code = $request->admin_code;
    $admin->name = $request->name;
    $admin->role = $request->role;
    $admin->password = Hash::make($request->password);
    $admin->save();
    return redirect()->route('admin.index');
}
```

admin_codeにはrequired（必須）、integer（数値）、unique（テーブル内でユニーク）のチェック、roleにはsize（桁数）のチェック、passwordにはrequired（必須）、string（文字列）、min（最低桁数）、confimed（確認入力）のチェックを行っている。これだけで。
実際にエラーにしてみる。

|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/137858/5942b829-b296-b6fa-c60a-5aeff3a477b5.png)|
|:-:|

Admin Codeに何も入れないで追加ボタンを押すと。

|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/137858/5263f43c-b331-37d8-c81b-258ed62d42ad.png)|
|:-:|

エラーメッセージが表示される。ブラボー。
ちなみに画面はauthのRegister.blade.phpをぱくって作ったので、エラーの表示方法もすっかりぱくってます。

```php:エラーメッセージを出しているところ
{{-- エラーメッセージ --}}
@if ($errors->any())
    <div class="alert alert-danger">
    <ul>
        @foreach ($errors->all() as $error)
            <li>{{ $error }}</li>
        @endforeach
    </ul>
    </div>
@endif
```

[マニュアル](https://readouble.com/laravel/6.0/ja/validation.html#rule-max)によると、$errorsはShareErrorsFromSessionミドルウェアの中で定義されているので、意識しなくても使えるとのこと。至れり尽くせりだ。
これを表示する仕組みを組み込めば、エラーメッセージが表示できるのだ。

ところでパスワードでエラーが出ると、今の仕組みだと上のエラーメッセージ表示行と項目の下に同じエラーメッセージが出る。

|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/137858/cdad81fa-52a4-4a9f-64cb-02f1a1ef92b9.png)|
|:-:|

これは画面を作るとき、いろんなところからサンプル引っ張ってきたせいだね。すまない。
項目の下にエラーを出している仕組みは、こんな感じで書かれている。

```php
<div class="form-group row">
    <label for="password" class="col-md-4 col-form-label text-md-right">{{ __('Password') }}</label>
    <div class="col-md-6">
        <input id="password" type="password" class="form-control @error('password') is-invalid @enderror" name="password">
            @error('password')
                <span class="invalid-feedback" role="alert">
                     <strong>{{ $message }}</strong>
                </span>
            @enderror
     </div>
</div>
```

classに@errorで属性（ここではpasswordね）にvalidationエラーメッセージがあるか判断し、メッセージがある場合はその下に書いた@errorの内容を表示する。エラーメッセージは$messageに入る。
今回は上に出すのを生かして、項目ごとに出すのは消していくよ。

```php
<div class="form-group row">
    <label for="password" class="col-md-4 col-form-label text-md-right">{{ __('Password') }}</label>
    <div class="col-md-6">
        <input id="password" type="password" class="form-control" name="password">
    </div>
</div>
```

どっちで出すかは趣味で決めていいと思うよ。

##更新の時は入力された項目だけチェック！
普通は必須項目は必須だし、更新だからってvalidationの内容が変わったりしないけど。
例えば、今回のadmin codeみたいに、新規登録時はユニークであってほしいけど、更新の時はもともとのコードをそのまま設定したいとか、パスワードはハッシュ化しているので元の文字列を表示できないので、更新画面に元々の値を持ってこれないから、入力された時だけチェック・更新したいとか。結構新規登録時と違うチェックをしたいときがあるよね。

```php:AdminController.php
public function update(Request $request, $id)
{
    if($request->action === 'back') {
        return redirect()->route('admin.index');
    }
    // validation
    $rules = [
        'admin_code' => ['required', 'integer'],
        'role' => ['size:1'],
        'password' => ['sometimes', 'nullable', 'string', 'min:8', 'confirmed']
    ];
    $this->validate($request, $rules);
    $admin = \App\Admin::find($id);
    $admin->admin_code = $request->admin_code;
    $admin->name = $request->name;
    $admin->role = $request->role;
    if (!empty($request->password)) {
        $admin->password = Hash::make($request->password);
    }
    $admin->save();
    return redirect()->route('admin.index');
}
```

例えば。
admin_codeからuniqueのチェックを外しました。
passwordには「sometimes」、「nullable」を追加して、入力された時だけチェックするようにしました。
ついでにパスワードは入力された時だけ更新するよう、項目セットに条件を付けました。
これだけで、saveの時に項目を更新するか勝手に判断して、値がセットされた項目だけ更新してくれます。

#メッセージを日本語化してみる
validateは追加できたけど、エラーメッセージが英語で何言ってるかわかんない！って思う方もいるでしょう。
これからの時代、この程度の英語はフィーリングで理解できないとね、って言って済めばいいんだが、お仕事関係でこういうものを作っているとなかなかそんな言い訳は通じないからつらいよね。
なので、オリエンタルスマイルを浮かべながら余裕で日本語対応してやりましょう。

##日本語ファイルを作成する
resources/langフォルダーの下に各言語の対応ファイルを置いておけば、設定に合わせてローカライズしてくれるらしいよ。
langフォルダーはデフォルトこんな感じになっている。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/137858/5a636c8f-c0bc-aff8-59ab-dfb492bf6e60.png)

enフォルダー（英語のフォルダーね）の中に、以下のファイルが入っている。
・auth.php:ログイン認証エラー時に表示されるメッセージ
・pagination.php:ページネーションの時表示する文言
・passwords.php:パスワードリセットなどで表示されるメッセージ
・validation.php:validationで表示されるメッセージ
なんかあいろいろある。ローカライズするときは、この辺のファイルをいじるか自分で作ったりするんだろうな。

さて、日本語のメッセージファイルを格納するjaフォルダーを作成しよう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/137858/15cf492a-6785-3892-0c7a-64c444052d23.png)

設定を日本語にしたらメッセージはすべてjaフォルダーから出すことになるんだろうから、今enに入っているファイルはすべてjaフォルダーにもコピーしておくんだろうな、きっと。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/137858/4c2a2e38-92fb-9b15-522d-57d4d4f9ee1f.png)

ちなみに日本語化されたファイルはいろんなところに落ちているみたいだから、そこから拾ってきて入れてしまうのが手っ取り早い。
ちなみにこんな感じで日本語化する。

```php:validation.php
<?php
return [
    /*
    |--------------------------------------------------------------------------
    | Validation Language Lines
    |--------------------------------------------------------------------------
    |
    | The following language lines contain the default error messages used by
    | the validator class. Some of these rules have multiple versions such
    | as the size rules. Feel free to tweak each of these messages here.
    |
    */
    'accepted' => ':attribute は「許可」でなくてはなりません',
    'active_url' => ':attribute は有効なURLではありません',
    'after' => ':attribute は :date より後の日付にしてください',
    'after_or_equal' => ':attribute は :date 以降の日付にしてください',
    'alpha' => ':attribute にはアルファベットしか入力できません',
    'alpha_dash' => ':attribute には英数字、ハイフン、アンダースコアしか入力できません',
    'alpha_num' => ':attribute には英数字しか入力できません',
    'array' => ':attribute は配列で入力してください',
    'before' => ':attribute は :date より前の日付にしてください',
    'before_or_equal' => ':attribute は :date 以前の日付にしてください',
    'between' => [
        'numeric' => ':attribute は :min から :max の間の値にしてください',
        'file' => ':attribute は :min から :max kbの間のサイズにしてください',
        'string' => ':attribute は :min から :max の間の文字にしてください',
        'array' => ':attribute は :min から :max の間の項目にしてください',
    ],
    'boolean' => ':attribute は true か false を入力してください',
    //以下同様
```

:attributeとか:dateとかは変数になります。
メッセージを表示されてみる。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/137858/976e50f7-024e-acf5-fb09-e9dc8a6a12a3.png)


##項目名も日本語化する
validation.phpは、エラーメッセージ内に表示される項目名の日本語化も設定できるようになってます。

```php
/*
    |--------------------------------------------------------------------------
    | Custom Validation Attributes
    |--------------------------------------------------------------------------
    |
    | The following language lines are used to swap our attribute placeholder
    | with something more reader friendly such as "E-Mail Address" instead
    | of "email". This simply helps us make our message more expressive.
    |
    */

    'attributes' => [],
```

attributesの中に配列で設定します。こんな感じ。

```php
'attributes' => [
    'admin_code' => '管理者コード',
    'name' => '氏名',
    'role' => '権限',
    'password' => 'パスワード', 
],
```

そうすると、こんな風にメッセージ表示される。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/137858/21a6e330-d07a-b8b9-ffed-d66e8579a41d.png)

エラーメッセージに表示される項目名が、日本語になりました。
てか、画面の項目は英語じゃん。そっちはblade.phpで設定してね。