Laravel CRUD処理を使った投稿アプリを作成する その8 バリデーションを実装する

# 目的

- アプリを作成する上で基本となるCRUD処理を有したLaravelアプリをチュートリアル的に作成する方法をまとめる

# 実施環境

- ハードウェア環境

| 項目 | 情報 |
| --- | --- |
| OS | macOS Catalina(10.15.5) |
| ハードウェア | MacBook Pro (13-inch, 2020, Four Thunderbolt 3 ports) |
| プロセッサ | 2 GHz クアッドコアIntel Core i5 |
| メモリ | 32 GB 3733 MHz LPDDR4 |
| グラフィックス | Intel Iris Plus Graphics 1536 MB |

- ソフトウェア環境

| 項目 | 情報 | 備考 |
| --- | --- | --- |
| PHP バージョン | 7.4.3 | Homwbrewを用いて導入 |
| Laravel バージョン | 7.0.8 | commposerを用いてこちらの方法で導入→[Mac Laravelの環境構築を行う](https://qiita.com/miriwo/items/adaaaeecae69d6392e08) |
| MySQLバージョン | 8.0.19 for osx10.13 on x86_64 | Homwbrewを用いてこちらの方法で導入→[Mac HomebrewでMySQLをインストールする](https://qiita.com/miriwo/items/ef6a064bc545fbea29d9) |

# 前提条件

- 実施環境に近い環境が構築されていること。
- 筆者は下記の方法で環境構築を行った。
    - [Mac Laravelの環境構築を行う](https://qiita.com/miriwo/items/adaaaeecae69d6392e08)
    - [Mac HomebrewでMySQLをインストールする](https://qiita.com/miriwo/items/ef6a064bc545fbea29d9)

# 前提情報

- ソースコードはこちら→[https://github.com/miriwo0104/laravel_crud/tree/master](https://github.com/miriwo0104/laravel_crud/tree/master)
- DockerやAWSなどは使用せずにMacのローカルに実施環境と同じLaravel開発環境を構築して実施する。
- チュートリアルで実際に筆者が作成したソースコードをGitHubにて公開予定である。
- CRUD処理の作成完了を最短目標にしてバリデーションなどは後々設定することとする。
- 実施環境と同じ環境がDockerやAWSで用意できるなら都度読み替えていただければ実施が可能だと思う。
- 公式ドキュメントと一冊の技術書を元に本記事を記載する。
    - [Laravel 7.x](https://readouble.com/laravel/7.x/ja/installation.html)
    - [PHPフレームワーク Laravel Webアプリケーション開発 バージョン5.5 LTS対応](https://www.amazon.co.jp/PHP%E3%83%95%E3%83%AC%E3%83%BC%E3%83%A0%E3%83%AF%E3%83%BC%E3%82%AF-Laravel-Web%E3%82%A2%E3%83%97%E3%83%AA%E3%82%B1%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3%E9%96%8B%E7%99%BA-%E3%83%90%E3%83%BC%E3%82%B8%E3%83%A7%E3%83%B35-5-LTS%E5%AF%BE%E5%BF%9C/dp/4802611846/ref=sr_1_5?__mk_ja_JP=%E3%82%AB%E3%82%BF%E3%82%AB%E3%83%8A&dchild=1&keywords=laravel&qid=1594858533&sr=8-5)
    - 本記事はシリーズとして内容を分割する予定である。記事のタグ「miriwo_laravelチュートリアル」を本シリーズの記事に付与するのでそのほかの記事がみたい方は活用していただきたい。
- DBへの意図しないデータの流入を防ぐためバリデーションを実装する。
- 問い合わせの内容は「入力がされていること」のバリデーションルールを、新規投稿と投稿編集は「入力されており、かつ140文字以内であること」定義してバリデートする。
- バリデーションで弾かれた時にエラーが出力される様にする。
- 下記に目を通しておくと理解が早いかもしれない。
    - [Laravel バリデーションを設定する ~コントローラ編~](https://qiita.com/miriwo/items/e7521e61522b81881417)
- バリデーションルールは下記の公式ドキュメントに数多く記載されているので実装できたら遊んでみるのもいいかもしれない。
    - [Laravel 7.x バリデーション](https://readouble.com/laravel/7.x/ja/validation.html)

# この記事の読後感

- ユーザが入力する部分にバリデーションを実装することができる。

# 概要

1. バリデーションの実装
1. エラー出力部分とデフォルト値の設定
1. 確認

# 詳細

1. バリデーションの実装
    1. laravel_crudディレクトリで下記コマンドを実行してコントローラファイルを開く。

        ```terminal
        $ vi app/Http/Controllers/ContentController.php
        ```
    1. 先に開いたコントローラファイルのsaveアクションを下記の様に修正する。

        ```laravel_crud/app/Http/Controllers/ContentController.php
        public function save(Request $request)
        {
            // 下記を追記する
            $rules = [
                'content' => ['required', 'max: 140'],
            ];
    
            $this->validate($request, $rules);
            // 上記までを追記する
            $input_content = new Content();
            $input_content->content = $request['content'];
            $input_content->save();
            
            return redirect('/output');
        }
        ```
    1. 先に開いたコントローラファイルのupdateアクションを下記の様に修正する。

        ```laravel_crud/app/Http/Controllers/ContentController.php
        public function update(Request $request)
        {
            // 下記を追記する
            $rules = [
                'content' => ['required', 'max: 140'],
            ];
    
            $this->validate($request, $rules);
            // 上記までを追記する
            $contents_update_query = Content::select('*');
            $contents_update_query->where('id', $request['content_id']);
            $update_contents = $contents_update_query->get();
    
            $update_content = $update_contents[0];
            $update_content->content = $request['content'];
            $update_content->save();
    
            return redirect('/output');
        }
        ```
    1. ContentController.phpの全体像を下記に記載する。

        ```laravel_crud/app/Http/Controllers/ContentController.php
        <?php
        
        namespace App\Http\Controllers;
        
        use Illuminate\Http\Request;
        use App\Models\Content;
        
        class ContentController extends Controller
        {
            public function input()
            {
                return view('contents.input');
            }
        
            public function save(Request $request)
            {
                // 下記を追記する
                $rules = [
                    'content' => ['required', 'max: 140'],
                ];
        
                $this->validate($request, $rules);
                // 上記までを追記する
                $input_content = new Content();
                $input_content->content = $request['content'];
                $input_content->save();
                
                return redirect('/output');
            }
        
            public function output()
            {
                $contents_get_query = Content::select('*');
                $all_contents = $contents_get_query->get();
                
                return view('contents.output', [
                    'all_contents' => $all_contents,
                ]);
            }
        
            public function delete(Request $request)
            {
                $contents_delete_query = Content::select('*');
                $contents_delete_query->where('id', $request['content_id']);
                $contents_delete_query->delete();
        
                return redirect('/output');
            }
        
            public function edit($content_id)
            {
                $contents_edit_query = Content::select('*');
                $contents_edit_query->where('id', $content_id);
                $edit_contents = $contents_edit_query->get();
                $edit_content = $edit_contents[0];
        
                return view('contents.edit', [
                    'edit_content' => $edit_content,
                ]);
            }
        
            public function update(Request $request)
            {
                // 下記を追記する
                $rules = [
                    'content' => ['required', 'max: 140'],
                ];
        
                $this->validate($request, $rules);
                // 上記までを追記する
                $contents_update_query = Content::select('*');
                $contents_update_query->where('id', $request['content_id']);
                $update_contents = $contents_update_query->get();
        
                $update_content = $update_contents[0];
                $update_content->content = $request['content'];
                $update_content->save();
        
                return redirect('/output');
            }
        }

        ```
    1. laravel_crudディレクトリで下記コマンドを実行してコントローラファイルを開く。

        ```terminal
        $ vi app/Http/Controllers/InquiryController.php
        ```
    1. 先に開いたコントローラファイルのsendアクションを下記の様に修正する。

        ```laravel_crud/app/Http/Controllers/InquiryController.php
        public function send(Request $request)
        {
            // 下記を追記する
            $rules = [
                'content' => ['required'],
                'name' => ['required'],
            ];
    
            $this->validate($request, $rules);
            // 上記までを追記する
            $inquiry_content = $request->all();
            Mail::to('admin@example')->send(new SendMail($inquiry_content));
            return redirect(route('home'));
        }
        ```
    1. InquiryController.phpの全体像を下記に記載する。

        ```laravel_crud/app/Http/Controllers/InquiryController.php
        <?php
        
        namespace App\Http\Controllers;
        
        use Illuminate\Http\Request;
        use Illuminate\Support\Facades\Mail;
        use Illuminate\Support\Facades\Auth;
        use App\Mail\SendMail;
        
        class InquiryController extends Controller
        {
            public function input()
            {
                $user_infos = Auth::user();
                return view('inquiries.input', [
                    'user_infos' => $user_infos,
                ]);
            }
        
            public function send(Request $request)
            {
                // 下記を追記する
                $rules = [
                    'content' => ['required'],
                    'name' => ['required'],
                ];
        
                $this->validate($request, $rules);
                // 上記までを追記する
                $inquiry_content = $request->all();
                Mail::to('admin@example')->send(new SendMail($inquiry_content));
                return redirect(route('home'));
            }
        }
        ```
    1. laravel_crudディレクトリで下記コマンドを実行しローカルサーバを起動する。

        ```terminal
        $ php artisan serve
        ```
    1. 下記にユーザ認証後、下記にそれぞれアクセスし内容を入力せずに送信ボタンをクリックし、ページ遷移せず同じページが再度読み込まれることを確認する。編集画面での確認はidが1以外のものでも良い。
        - [http://127.0.0.1:8000/input](http://127.0.0.1:8000/input)
        - [http://127.0.0.1:8000/edit/1](http://127.0.0.1:8000/edit/1)
        - [http://127.0.0.1:8000/inquiry/input](http://127.0.0.1:8000/inquiry/input)

1. エラー出力部分とデフォルト値の設定
    1. laravel_crudディレクトリで下記コマンドを実行して新規投稿画面のビューファイルを開く。

        ```terminal
        $ vi resources/views/contents/input.blade.php
        ```
    1. 開いたファイルを下記の様に修正する。

        ```laravel_crud/resources/views/contents/input.blade.php
        <h1>input</h1>
        {{-- 下記を追記する --}}
        @error('content')
            {{ $message }}
        @enderror
        {{-- 上記までを追記する --}}
        <form action="{{route('save')}}" method="post">
            @csrf
            {{-- 下記を修正する --}}
            <textarea name="content" cols="30" rows="10">{{ old('content') }}</textarea>
            <input type="submit" value="送信">
        </form>
        ```
    1. laravel_crudディレクトリで下記コマンドを実行して投稿編集画面のビューファイルを開く。

        ```terminal
        $ vi resources/views/contents/edit.blade.php
        ```
    1. 開いたファイルを下記の様に修正する。

        ```laravel_crud/resources/views/contents/edit.blade.php
        <h1>edit</h1>
        {{-- 下記を追記する --}}
        @error('content')
            {{ $message }}
        @enderror
        {{-- 上記までを追記する --}}
        <form action="{{route('update')}}" method="post">
            @csrf
            <textarea name="content" cols="30" rows="10">{{$edit_content['content']}}</textarea>
            <input type="hidden" name="content_id" value="{{$edit_content['id']}}">
            <input type="submit" value="送信">
        </form>
        ```
    1. laravel_crudディレクトリで下記コマンドを実行して投稿編集画面のビューファイルを開く。

        ```terminal
        $ vi resources/views/contents/edit.blade.php
        ```
    1. 開いたファイルを下記の様に修正する。

        ```laravel_crud/resources/views/contents/edit.blade.php
        <h1>edit</h1>
        {{-- 下記を追記する --}}
        @error('content')
            {{ $message }}
        @enderror
        {{-- 上記までを追記する --}}
        <form action="{{route('update')}}" method="post">
            @csrf
            <textarea name="content" cols="30" rows="10">{{$edit_content['content']}}</textarea>
            <input type="hidden" name="content_id" value="{{$edit_content['id']}}">
            <input type="submit" value="送信">
        </form>
        ```
    1. laravel_crudディレクトリで下記コマンドを実行して問い合わせ送信画面のビューファイルを開く。

        ```terminal
        $ vi resources/views/inquiries/input.blade.php
        ```
    1. 開いたファイルを下記の様に修正する。

        ```laravel_crud/resources/views/inquiries/input.blade.php
        <form action="{{ route('inquiry.send') }}" method="POST">
            @csrf
            <p>お問い合わせ内容</p>
            <textarea name="content" cols="30" rows="10"></textarea>
            {{-- 下記を追記する --}}
            @error('content')
            {{ $message }}
            @enderror
            {{-- 上記までを追記する --}}
        
            <p>お客様のお名前</p>
            <input type="text" name="name" value="{{ $user_infos['name'] }}">
            {{-- 下記を追記する --}}
                @error('name')
                {{ $message }}
            @enderror
            {{-- 上記までを追記する --}}
        
            <p>お客様のメールアドレス</p>
            <p>{{ $user_infos['email'] }}</p>
            <input type="hidden" name="email" value="{{ $user_infos['email'] }}">
            <br>
            <input type="submit" value="送信">
        </form>
        ```
1. 確認
    1. laravel_crudディレクトリで下記コマンドを実行しローカルサーバを起動する。

        ```terminal
        $ php artisan serve
        ```
    1. 下記にユーザ認証後、下記にアクセスする。
        - [http://127.0.0.1:8000/input](http://127.0.0.1:8000/input)
    1. 何も入力せず「送信」をクリックし下記のようにエラーが出ることを確認する。

        ![127_0_0_1_8000_input.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306417/a7b8ac2f-4e2f-1df3-2650-3d7c717424d2.png)

    1. 下記にユーザ認証後、下記にアクセスする。（コンテンツのidは1以外でも構わない）
        - [http://127.0.0.1:8000/edit/1](http://127.0.0.1:8000/edit/1)
    1. 何も入力せず「送信」をクリックし下記のようにエラーが出ることを確認する。

        ![127_0_0_1_8000_edit_5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306417/847e8ed9-9954-0f13-b65d-b98bbcd229f0.png)

    1. 下記にユーザ認証後、下記にアクセスする。（コンテンツのidは1以外でも構わない）
        - [http://127.0.0.1:8000/inquiry/input](http://127.0.0.1:8000/inquiry/input)
    1. 何も入力せず「送信」をクリックし下記のようにエラーが出ることを確認する。

        ![127_0_0_1_8000_inquiry_input.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306417/41fc2a18-143e-9079-ee9f-bb76c1916137.png)

# 参考文献

- [Laravel バリデーションを設定する ~コントローラ編~](https://qiita.com/miriwo/items/e7521e61522b81881417)
- [Laravel 7.x バリデーション](https://readouble.com/laravel/7.x/ja/validation.html)