【Laravel】Web開発初心者が1週間で入門チュートリアルを実施した記録(5), (6)



以下の続き。

https://qiita.com/yotty19911207/items/c4dc76d8c4146899a364

フォルダに続き、タスク一覧の作成もできた。
■(4)の復習：
・外部キー制約の設定

      // 外部キーを設定する
      $table->foreign('folder_id')->references('id')->on('folders');

・Laravel が提供するクエリビルダの機能を使用したデータ操作

      // 選ばれたフォルダに紐づくタスクを取得する
      $tasks = Task::where('folder_id', $current_folder->id)->get();

・モデルクラスにおけるリレーションを意識した記載
上記はリレーションを意識してモデルクラスを記載することで以下のように表現できる。

      $tasks = $current_folder->tasks()->get();

リレーションを意識したモデルクラスの記載

      class Folder extends Model
      {
          public function tasks()
          {
              return $this->hasMany('App\Task');
          }
      }

・アクセサ
モデルクラスでgetStatusLabelAttribute()と定義した関数の戻り値を、コントローラーやテンプレートで以下のように取得できる。

    <span class="label">{{ $task->status_label }}</span>

ここまでが(4)の復習。

<h1>入門Laravelチュートリアル (5) ToDoアプリのフォルダ作成機能を作る</h1>

一覧画面を作成した後は、フォルダ作成機能をつくった。
開発の流れをおさらい。

①ルーティング設定(web.php)
②コントローラーの作成・記載
③マイグレーションファイルの作成・記載
④マイグレーションの実行
⑤モデルクラスの作成
⑥テストデータの挿入
⑦コントローラーの追記・修正
⑧テンプレートの作成


①ルーティング設定(web.php)

      Route::get('/folders/create', 'FolderController@showCreateForm')->name('folders.create');
      Route::post('/folders/create', 'FolderController@create');

name メソッドによるルートの命名は get だけに定義しています。名前をつけてあとで呼び出せるのは URL だけなので、同じ URL で HTTP メソッド違いのルートがいくつかある場合はどれか一つに名前をつければ OK 

※
getは一覧画面の「フォルダを追加」ボタンを押して、フォルダ追加画面に遷移してきた時。
postはフォルダ追加画面でフォルダ名を入力し「送信」ボタンを押した時。

まずはget時のshowCreateFormメソッドに関して実装していく。

②コントローラーの作成・記載(showCreateForm)
フォルダについての処理を受け持つ FolderController を作成。
ルーテイング設定時に記載した、showCreateFormとcreateメソッドを後ほど記載する。
まずは一覧画面からフォルダ追加画面に飛ばすshowCreateFormメソッドについて、テンプレート（view）に飛ばす処理を記載。

    public function showCreateForm()
    {
        return view('folders/create');
    }



showCreateFormについては、③〜⑦は特にないため、⑧テンプレートの作成にうつる。

⑧テンプレートの作成(showCreateForm)

「/resources/views/folders/create.blade.php」を作成して中身を書いていく。
フォルダ名を入れる入力フォームと「送信」ボタンがあるだけのシンプルな画面なので、基本的なHTML。
途中にある@csrfはCSRF トークンを含んだ input 要素を出力する。Web アプリケーションの脆弱性に対処するために用いられる文字列で、悪意のあるサイトからの POST リクエストを受け付けてしまうことを防ぐ。（この例だと、他のサイトから /folders/create に POST リクエストが送信されることを防ぐ。）

Laravel では CSRF トークンのチェックは最初から組み込まれている。すべての POST リクエストに対して CSRF トークンが要求されるため、@csrf を書き忘れるとリクエスト送信時にエラーが発生する。


続いてput時のcreateメソッドに関して実装していく。


②コントローラーの作成・記載(create)

    public function create(Request $request)
    {
        // フォルダモデルのインスタンスを作成する
        $folder = new Folder();
        // タイトルに入力値を代入する
        $folder->title = $request->title;
        // インスタンスの状態をデータベースに書き込む
        $folder->save();

        return redirect()->route('tasks.index', [
            'id' => $folder->id,
        ]);
    }

フォルダ名を入力して「送信」ボタンを押した時の処理なので、新しいフォルダのタイトル（フォルダ名）をDBに保存して、view関数で一覧画面にリダイレクトしている。

なぜリダイレクトか？
画面遷移としては、一覧画面→フォルダ作成画面→一覧画面に戻るという流れになり、画面を作る必要はないので view メソッドは呼ばず、リダイレクトする。

③〜⑦は特になく、リダイレクトするだけなので⑧テンプレートの作成もないため、一旦ここまでで単純なフォルダ作成まではできるようになっている。

以下で、入力値バリデーションを実装。

Laravel では FormRequest クラスがバリデーションを司ります。まずは artisan コマンドでクラスを作成します。

    php artisan make:request CreateFolder

→app/Http/Requests フォルダに CreateFolder.php が作成される。

この中のrule関数が重要。

    public function rules()
    {
        return [
            'title' => 'required', // ★
        ];
    }

'title'はHTML 側での input 要素の name 属性に対応。必須入力を意味する required を指定しています。

テンプレートに、エラーメッセージを出力するための処理を実装する。


(5)の内容は以上。続いて(6)。


<h1>入門Laravelチュートリアル (6) ToDoアプリのタスク作成機能を作る</h1>

(6)ではタスク作成機能を作った。
フォルダを作るかタスクを作るかの違いなので、基本的な流れは(5)と同様。

①ルーティング設定

    Route::get('/folders/{id}/tasks/create', 'TaskController@showCreateForm')->name('tasks.create');
    Route::post('/folders/{id}/tasks/create', 'TaskController@create');

※
getは一覧画面の「タスクを追加」ボタンを押して、タスク追加画面に遷移してきた時。
postはタスク追加画面でタイトルと期限を入力し「送信」ボタンを押した時。

まずはget時のshowCreateFormメソッドに関して実装していく。

②コントローラーの作成・記載(showCreateForm)
TaskControllerにshowCreateFormメソッドを追加。

    public function showCreateForm(int $id)
    {
        return view('tasks/create', [
            'folder_id' => $id
        ]);
    }

テンプレートで form 要素の action 属性としてタスク作成 URL（/folders/{id}/tasks/create）を作るためにフォルダの ID が必要なので、コントローラーメソッドの引数で受け取って view 関数でテンプレートに渡している。

showCreateFormについては、③〜⑦は特にないため、⑧テンプレートの作成にうつる。

⑧テンプレートの作成(showCreateForm)

「/resources/views/tasks/create.blade.php」を作成して中身を書いていく。

タイトルと期限を入力し「送信」ボタンを押すだけなので基本的なHTML。
ただし、期限を入力する際にカレンダーから日付を選ぶようにしたいので「flatpickr」というJavascriptライブラリを使用する。


・レイアウトの整理

ここで、フォルダとタスクのテンプレートで共通的に記載している箇所が多くあるので、レイアウトファイルを使用してコードをシンプルにする。
まずはレイアウト resources/views/layout.blade.php を作成。
レイアウトにはページごとに変わらない部分だけを記述。ページごとに変化する部分は @yield で穴埋めにする。

テンプレート「/resources/views/tasks/create.blade.php」の内容をレイアウトを読み込むかたちに修正。

@extends('layout')でレイアウトを読み込むことを宣言。
レイアウトで@yield('styles')などとしていた部分には、@section('styles')〜@endsectionなどで挟んだ内容が入る。

他のテンプレートについても同様に修正を加える。

フォルダ同様、バリデーションチェックを加えてshowCreateFormは終了。

続いてcreateですが、フォルダの時と同様、コントローラーにcreateメソッドを追加してテンプレートを修正するのみ。


■バリデーションテスト

最後に期限日のバリデーションテストを実施。

開発用のデータベースとは別に、メモリ上の（つまりテストコードが実行し終わると消える）データベースを使う。これによりテストを実行する間だけ存在すればいいデータが開発の邪魔にならない。

config/database.php の connections に以下の設定を追加。
テストはsqliteで行う。

    'connections' => [

        // ★ この設定を追加
        'sqlite_testing' => [
            'driver' => 'sqlite',
            'database' => ':memory:',
            'prefix' => '',
        ],
    
        // 中略
    ]



Laravel ではテスティングライブラリとして PHPUnit をサポートしている。設定ファイル phpunit.xml に DB_CONNECTION の設定を追加。

    <php>
        <env name="APP_ENV" value="testing"/>
        <env name="DB_CONNECTION" value="sqlite_testing"/> <!-- ★ この行を追加-->
        <!-- 中略 -->
    </php>



テストコードの雛形を生成

    php artisan make:test TaskTest

→tests/Feature/TaskTest.php が作成された。

テストコードを更新し、以下コマンドでテストを実施。


    ./vendor/bin/phpunit ./tests/Feature/TaskTest.php --testdox


　結果が緑のチェックマークが表示されれば OK 。

これにて(6)も完了