Laravel 6 基本のタスクリスト

Laravel公式で用意されている[Laravel 5.2 基本のタスクリスト](https://readouble.com/laravel/5.2/ja/quickstart.html)はLaravel5.2とかなり古く、ディレクトリ構成も異なるし、ルーティングファイルの配置も変わってますし、HTMLタグの`tr`が抜けてたり、`id`の指定が異なっていたり、インデントが崩れていたり、`old`関数が抜けてたり、そのままチュートリアル通りに進めてもハマりどころが多く、初心者の挫折ポイントになってました。

そこで今回の記事では、Laravelに入門する方を対象に基本のタスクリストのチュートリアルを`Laravel 6.0`で行う手順に補足を追加しつつ紹介します。

特に問題なさそうな箇所はそのまま引用して紹介します。

## アジェンダ

- 1. 前準備
- 2. Laravelをインストール
- 3. データベースの準備
- 4. Eloquentモデル
- 5. Tinker（REPL）
- 6. ルート定義
  - 6.1. 全タスクをリスト表示するルート
  - 6.2. 新しいタスクを追加するルート
  - 6.3. 既存のタスクを削除するルート
- 7. レイアウトとビューの作成
  - 7.1. 親レイアウトビューの作成
  - 7.2. 共通エラービューの作成
  - 7.3. 子タスクビューの作成
- 8. タスク追加機能
  - 8.1. バリデーション
  - 8.2. エラー表示
  - 8.3. タスク作成
- 9. 既存タスクの表示機能
- 10. タスク削除機能
  - 10.1 削除ボタンの追加
  - 10.2 タスク削除

### 作成するもの

Laravelの持つ機能の基本的な部分を試せるように、
完了したいタスク全てを管理できるシンプルなタスクリストを構築してみます。
言い換えれば、典型的なToDoリストのサンプルです。

### ソースコード

このプロジェクトの最終の完全なソースコードはGitHubから取得可能です。

https://github.com/ucan-lab/laravel60-quickstart-basic

```
$ git clone git@github.com:ucan-lab/laravel60-quickstart-basic
$ cd laravel60-quickstart-basic
$ docker-compose up -d --build
$ docker-compose exec app composer install
$ docker-compose exec app cp .env.example .env
$ docker-compose exec app php artisan key:generate
$ docker-compose exec app php artisan migrate
```

http://127.0.0.1:10080

## 前準備

Laravelの環境を用意していない人はこちらの記事を元に開発環境を構築してください。
[DockerでLaravel開発環境構築](https://qiita.com/ucan-lab/items/56c9dc3cf2e6762672f4)

Laravelさえ動作すれば問題ないですのでお好みで環境構築してください。

### Laravelインストール

```shell-session
$ git clone git@github.com:ucan-lab/docker-laravel-handson.git laravel60-quickstart-basic
$ cd laravel60-quickstart-basic
```

記事の通り、環境構築した場合は既にLaravelインストール済みなので、一度Laravel削除してから進めます。

```shell-session
$ rm -rf src
```

`.env` を修正します。

```
COMPOSE_PROJECT_NAME=laravel60-quickstart-basic
DB_NAME=homestead
DB_USER=homestead
DB_PASS=secret
TZ=Asia/Tokyo
```

Docker環境のビルドとLaravel6.0のインストール

```shell-session
# Docker環境構築
$ docker-compose up -d --build
```

### GitHubのリポジトリを作成する

https://github.com/new

`laravel60-quickstart-basic` リモートリポジトリを作成します。

<img width="801" alt="スクリーンショット 2019-09-11 16.15.36.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/52879/6c6d69b2-46ba-c748-0303-54ec47a2e652.png">

<img width="1101" alt="スクリーンショット 2019-09-11 16.16.22.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/52879/f70e1ca3-f099-6221-34bd-aa46072b4828.png">

リモートリポジトリを作成します。

### Gitの初期化

`laravel60-quickstart-basic`ディレクトリ内はDocker環境を構築した際のGit設定が残っているので今回はクリアしてから進めたいと思います。

```shell-session
$ rm -rf .git
$ git init
$ git add .
$ git commit -m "first commit"
$ git remote add origin git@github.com:ucan-lab/laravel60-quickstart-basic.git
$ git push -u origin master
```

### Dockerコンテナ内の作業ディレクトリへ移動

```shell-session
$ docker-compose exec app ash
/work #
```

以降はDockerのappコンテナ内に入り、 `/work` ディレクトリで作業します。
Gitコマンドはコンテナ内ではなくホスト側の`laravel60-quickstart-basic`ディレクトリ内で実行してください。

### Laravelインストール

```
# Laravelプロジェクトのインストール
$ composer create-project --prefer-dist "laravel/laravel=6.0.*" .

# マイグレーション実行
$ php artisan migrate
Migrating: 2014_10_12_000000_create_users_table
Migrated:  2014_10_12_000000_create_users_table (0.08 seconds)
Migrating: 2014_10_12_100000_create_password_resets_table
Migrated:  2014_10_12_100000_create_password_resets_table (0.03 seconds)
Migrating: 2019_08_19_000000_create_failed_jobs_table
Migrated:  2019_08_19_000000_create_failed_jobs_table (0.01 seconds)

# Laravelバージョン確認
$ php artisan -V
Laravel Framework 6.0.3
```

http://127.0.0.1:10080

<img width="889" alt="スクリーンショット 2019-09-11 13.43.46.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/52879/069a88f2-a9c7-552a-bddb-2bcd9f7f99c5.png">

Laravelインストール、マイグレーションの実行ができ、welcome画面が表示されればokです。

### SQLSTATE[HY000] [2054] The server requested authentication method unknownto the client

MySQL8系のデータベースを使っててこのエラーが発生する場合は、[MySQL8.0 認証方式を変更する(Laravel5)](https://qiita.com/ucan-lab/items/3ae911b7e13287a5b917)の記事を参照ください。

## データベースの準備

### データベースマイグレーション

> 最初に全タスクを保持しておくためのデータベーステーブルを定義する、マイグレーション(migration:移行)を使ってみましょう。Laravelのデータベースマイグレーションはスラスラ書ける記述的なPHPコードを用いて、データベーステーブルの構造を定義し修正するための簡単な方法を提供しています。チームメンバーへ個別で用意しているデータベースのコピーへカラムを各自自分で追加するように伝える代わりに、あなたがソース管理にPushしたマイグレーションを実行してもらえます。

> では、全タスクを保持するデータベーステーブルを構築しましょう。[Artisan CLI](https://readouble.com/laravel/6.0/ja/artisan.html)は様々なクラスの生成に利用でき、Laravelプロジェクトを構築するためにたくさんタイプする手間を省いてくれます。今回は`tasks`テーブルのために、新しいデータベースマイグレーションを`make:migration`コマンドを使って生成します。

```shell-session
$ php artisan make:migration create_tasks_table --create=tasks
```

> マイグレーションはプロジェクトの`database/migrations`ディレクトリの中に設置されます。お分かりでしょうが、`make:migration`コマンドは、マイグレーションファイルへ自動増分IDとタイムスタンプの追加を始めに定義しています。このファイルを編集し、タスクの名前を保存する`string`カラムを追加しましょう。

```php
<?php

use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class CreateTasksTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('tasks', function (Blueprint $table) {
            $table->bigIncrements('id');
            $table->string('name');
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('tasks');
    }
}
```

> マイグレーションを実行するには、migrate Artisanコマンドを使います。

```php
$ php artisan migrate
```

> このコマンドは全データベーステーブルを生成します。お好きなクライアントを使用し、データベーステーブルを調べてもらえば、マイグレーションで定義したカラムを含んだ新しい`tasks`テーブルを見つけることができるでしょう。次に、タスクを表すEloquent ORMモデルを定義しましょう！

## Eloquentモデル

> [Eloquent](https://readouble.com/laravel/6.0/ja/eloquent.html)はLaravelのデフォルトORM(object-relational mapper)です。Eloquentは明確に定義された「モデル」を用いることで、苦労せずにデータベースへのデータ保存／取得を行わせてくれます。通常各Eloquentモデルは、一つのデータベーステーブルに対応します。

> では、作ったばかりの`tasks`データベーステーブルに対応する`Task`モデルを定義してみましょう。このモデルを生成するために、再度Artisanコマンドを使用します。この場合は`make:model`コマンドを使用します。

```shell-session
$ php artisan make:model Task
```

> このモデルはアプリケーションの`app`ディレクトリに設置されます。デフォルトではこのクラスは空です。データベーステーブルはモデルの複数形の名前だと想定されているため、Eloquentモデルがどのテーブルに対応するかを明確に宣言する必要はありません。ですから、この場合`Task`モデルは`tasks`データベーステーブルと対応していると想定しています。

- Eloquentモデルクラス
  - 各単語の最初の文字を大文字にした単数形
  - パスカルケース
  - 例: `Book`
- データベーステーブル
  - 各単語をアンダースコアで区切った複数形
  - スネークケース
  - 例: `books`

| モデルクラス | テーブルスキーマ |
|:--|:--|
| Article | articles |
| LineItem | line_items |
| Deer | deers |
| Mouse | mice |
| Person | people |

> 空のモデルは次のようになっています。

```php
<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Task extends Model
{
    //
}
```

## Tinker（[REPL](https://ja.wikipedia.org/wiki/REPL)）

> 全てのLaravelアプリケーションには、[PsySH](https://github.com/bobthecow/psysh)パッケージによるREPLである、Tinkerが含まれています。Tinkerにより、Laravel全体のEloquent ORM、ジョブ、イベントなどをコマンドラインから操作できます。Tinker環境に入るには、`tinker` Artisanコマンドを実行します。

```shell-session
$ php artisan tinker
Psy Shell v0.9.9 (PHP 7.3.8 — cli) by Justin Hileman
>>>
```

- [REPL(Read Eval Print Loop)](https://ja.wikipedia.org/wiki/REPL)
- [tinker](https://readouble.com/laravel/6.0/ja/artisan.html#tinker)

### Eloquentで遊ぶ

```php
use App\Task;

// タスク1 登録
$task1 = new Task();
$task1->name = 'task1';
$task1->save();

// タスク2 登録
$task2 = new Task();
$task2->name = 'task2';
$task2->save();

// タスク3 登録
$task3 = new Task();
$task3->name = 'task3';
$task3->save();

// 全件取得
Task::all();

// IDを指定して1件取得
Task::find(3);
// 戻り値がCollection型で返る
Task::where('name', 'task2')->get();
// 戻り値がTask型で返る
Task::where('name', 'task2')->first();

// 更新
$task = Task::find(1);
$task->name = 'update task1';
$task->save();
Task::find(1);

// 削除
$task = Task::find(1);
$task->delete();
Task::all();

Task::destroy(2);
Task::all();

Task::where('name', 'task3')->delete();
Task::all();
```

## ルート定義

Laravelの全ルートは、routesディレクトリ下に設置されている、ルートファイルで定義されます。
これらのファイルはフレームワークにより、自動的に読み込まれます。

- [Laravel 6.0 ルーティング](https://readouble.com/laravel/6.0/ja/routing.html)

### ルートのスタブを定義

定義されたルートは`web`ミドルウェアグループにアサインされ、セッション状態やCSRF保護などの機能が提供されます。
それでは、アプリケーションにいくつかルートを追加します。

ルートはユーザがページにアクセスするために指定するURLを実行するコントローラーか無名関数を指定するために使用します。
Webインターフェイスのルートを定義します。

このアプリケーションでは、最低３つのルートが必要になることがわかっています。

- 全タスクをリスト表示するルート
- 新しいタスクを追加するルート
- 既存のタスクを削除するルート

では、`routes/web.php`ファイルでこれらのルートを全部スタブ（空の代用コード）で定義しましょう。

```php
<?php

/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| contains the "web" middleware group. Now create something great!
|
*/

use App\Task;
use Illuminate\Http\Request;

/**
 * タスクダッシュボード表示
 */
Route::get('/', function () {
    //
});

/**
 * 新タスク追加
 */
Route::post('/task', function (Request $request) {
    //
});

/**
 * タスク削除
 */
Route::delete('/task/{task}', function (Task $task) {
    //
});
```

- http://127.0.0.1:10080
  - この状態だと真っ白な画面が表示されます。

### ビューの表示

> 次に`/`ルートを完成させましょう。このルートでは、新しいタスクを追加するフォームを含み、同時に現在の全タスクをリストするHTMLテンプレートを表示しましょう。

> Laravelの全HTMLテンプレートは`resources/views`ディレクトリに設置されます。ルートからこれらのテンプレートの一つを返すために`view`ヘルパが使えます。

```php
Route::get('/', function () {
    return view('tasks');
});
```

> `view`関数に渡した`tasks`は、`resources/views/tasks.blade.php`テンプレートに対応するビューオブジェクトインスタンを生成します。もちろん、このビューは実際に定義する必要がありますので、早速とりかかりましょう！

## レイアウトとビューの作成

> このアプリケーションは新しいタスクを追加するためのフォームを含み、同時に現在のタスクをリストするビューを一つだけ持ちます。ビューを想像するために役立つように、基本的なBootstrapのCSSスタイルを適用した、最終段階のアプリケーションのスナップショットをご覧ください。

<img width="609" alt="スクリーンショット 2019-09-11 13.52.30.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/52879/07006f53-dfda-a828-b1ab-22bd20f6bc4e.png">

### レイアウト定義

> ほとんど全てのアプリケーションでは同じレイアウトをページに渡り共有します。たとえばこのアプリケーションは全ページ（一つ以上のページが存在する場合）で表示する、典型的なトップナビバーがあります。LaravelはBladeテンプレートを使い、こうしたページ間共通のフューチャーを簡単に共有できるようになっています。

> 前に説明したように、Laravelの全ビューは`resources/views`に設置されます。ですから新しいレイアウトビューも`resources/views/layouts/app.blade.php`として定義します。`.blade.php`拡張子はビューを表示するときに[Bladeテンプレートエンジン](https://readouble.com/laravel/6.0/ja/blade.html)を使用することをフレームワークへ指示します。もちろん、Laravelでも普通のPHPテンプレートが使用できます。しかし、Bladeなら簡潔できれいなテンプレートを書くための便利なショートカットが利用できます。

> `app.blade.php`ビューは以下のような構成になるでしょう。

```shell-session
$ mkdir resources/views/layouts
$ touch resources/views/layouts/app.blade.php
```

#### resources/views/layouts/app.blade.php

```html
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Laravel Quickstart - Basic</title>
    <!-- Fonts -->
    <link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.4.0/css/font-awesome.min.css" rel='stylesheet' type='text/css'>
    <link href="https://fonts.googleapis.com/css?family=Lato:100,300,400,700" rel='stylesheet' type='text/css'>
    <!-- Styles -->
    <link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" rel="stylesheet">
    <style>
        body {
            font-family: 'Lato';
        }

        .fa-btn {
            margin-right: 6px;
        }
    </style>
</head>
<body id="app-layout">

<nav class="navbar navbar-default">
    <div class="container">
        <div class="navbar-header">
            <!-- Branding Image -->
            <a class="navbar-brand" href="{{ url('/') }}">
                タスクリスト
            </a>
        </div>
    </div>
</nav>

@yield('content')

<!-- JavaScripts -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js"></script>
</body>
</html>
```

> レイアウトの`@yield('content')`の部分に注目です。これはレイアウトを拡張する全部の子ページが、自身のコンテンツを親へ注入できる場所を指定するための特別なBladeディレクティブ（指定子）です。

### 共通エラーメッセージビューの定義

```shell-session
$ mkdir resources/views/common
$ touch resources/views/common/errors.blade.php
```

#### resources/views/common/errors.blade.php

```html
@if (count($errors) > 0)
    <!-- Form Error List -->
    <div class="alert alert-danger">
        <strong>おや？ 何かがおかしいようです！</strong>

        <br><br>

        <ul>
            @foreach ($errors->all() as $error)
                <li>{{ $error }}</li>
            @endforeach
        </ul>
    </div>
@endif
```

### 子ビューの定義

> 次に、新しいタスクを作成するためのフォームと、存在する全タスクを同時に表示するビューを定義する必要があります。`resources/views/tasks.blade.php`を定義しましょう。

```shell-session
$ touch resources/views/tasks.blade.php
```

#### resources/views/tasks.blade.php

```html
@extends('layouts.app')

@section('content')
    <div class="container">
        <div class="col-sm-offset-2 col-sm-8">
            <div class="panel panel-default">
                <div class="panel-heading">
                    新しいタスク
                </div>

                <div class="panel-body">
                    <!-- バリデーションエラーの表示 -->
                    @include('common.errors')

                    <!-- 新タスクフォーム -->
                    <form action="{{ url('task')}}" method="POST" class="form-horizontal">
                        @csrf

                        <!-- タスク名 -->
                        <div class="form-group">
                            <label for="task-name" class="col-sm-3 control-label">タスク</label>

                            <div class="col-sm-6">
                                <input type="text" name="name" id="task-name" class="form-control" value="{{ old('task') }}">
                            </div>
                        </div>

                        <!-- タスク追加ボタン -->
                        <div class="form-group">
                            <div class="col-sm-offset-3 col-sm-6">
                                <button type="submit" class="btn btn-default">
                                    <i class="fa fa-btn fa-plus"></i> タスク追加
                                </button>
                            </div>
                        </div>
                    </form>
                </div>
            </div>

            <!-- TODO: 現在のタスク -->
        </div>
    </div>
@endsection
```

http://127.0.0.1:10080

<img width="755" alt="スクリーンショット 2019-09-11 13.34.18.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/52879/e48bb45c-29b1-bf1f-4add-06fef79fd27a.png">

### 簡単な説明

> 先に進む前に、このテンプレートについて多少説明しましょう。最初に`@extends`ディレクティブにより、`resources/views/layouts/app.blade.php`に定義したレイアウトを使用することをBladeに指示しています。`@section('content')`から`@endsection`の間のコンテンツが、`app.blade.php`レイアウトの中の`@yield('content')`ディレクティブの場所に挿入されます。

> `@include('common.errors')`ディレクティブは`resources/views/common/errors.blade.php`に設置されているテンプレートをロードします。このテンプレートはまだ定義していませんが、すぐに行います。

## タスク追加

### バリデーション

> これでビューにフォームが用意できましたので、フォームの入力の正当性を確認し（バリデーション）、新しいタスクを作成する`POST /task`ルートのコードを`routes/web.php`へ追加しましょう。最初に、入力のバリデーションです。

> このフォームでは、`name`フィールドの入力が必須で、内容が`255`文字以下であることを確認しましょう。バリデーションに失敗したら、ユーザーを`/`のURLへリダイレクトし、同時に以前の入力とエラーをセッションへフラッシュデータとして保存します。フラッシュデータとしてセッションに入力を保存することで、バリデーションエラー時にユーザの入力を再表示できるようになります。

```php
Route::post('/task', function (Request $request) {
    $validator = Validator::make($request->all(), [
        'name' => 'required|max:255',
    ]);

    if ($validator->fails()) {
        return redirect('/')
            ->withInput()
            ->withErrors($validator);
    }

    // タスク作成処理…
});
```

### $errors変数

> 一休みして、この例の`->withErrors($validator)`の部分について解説しましょう。`->withErrors($validator)`の呼び出しは、指定されたバリデター(validator)インスタンスのエラーをフラッシュデータとしてセッションへ保存し、ビューの中で`$errors`変数としてアクセスできるようにしてくれます。

> フォームのバリデーションエラーを表示するために`@include('common.errors')`ディレクティブをビューで使用したことを思い出してください。`common.errors`によりバリデーションエラーを同じ形式で、全ページに渡り簡単に表示できるようにしています。このビューの内容を定義しましょう。

> **注意：** `$errors`変数は全てのLaravelビューの中で参照できます。バリデーションエラーが存在しない場合は、`ViewErrorBag`の空のインスタンスです。


<img width="754" alt="スクリーンショット 2019-09-11 13.36.10.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/52879/8b57ffc7-1987-6397-a682-09ac131892a5.png">

## タスク作成

> これで入力のバリデーションは処理できました。新しいタスクを実際に作成するためにルート処理の定義を続けましょう。新しくタスクを生成したら、ユーザを`/`のURLへリダイレクトします。タスクを作成するには、新しいEloquentモデルに対しプロパティーを生成し、値を設定した後に、`save`メソッドを使用します。

```php
Route::post('/task', function (Request $request) {
    $validator = Validator::make($request->all(), [
        'name' => 'required|max:255',
    ]);

    if ($validator->fails()) {
        return redirect('/')
            ->withInput()
            ->withErrors($validator);
    }

    $task = new Task();
    $task->name = $request->name;
    $task->save();

    return redirect('/');
});
```

http://127.0.0.1:10080
タスク追加してみましょう。

<img width="755" alt="スクリーンショット 2019-09-11 13.34.18.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/52879/909ac0af-52c4-564e-cb2f-5e9d7302f64a.png">

タスク追加してもタスクの一覧が表示されないのは現時点では正しい動作です。

データベースに値が登録されているかは、tinkerを使って確認します。

```shell-session
$ php artisan tinker

App\Task::all();
=> Illuminate\Database\Eloquent\Collection {#3012
     all: [
       App\Task {#3013
         id: 4,
         name: "ゆうきゃん",
         created_at: "2019-09-10 15:16:03",
         updated_at: "2019-09-10 15:16:03",
       },
     ],
   }
```

> いいですね！これでタスクを作成できるようになりました。次に存在する全タスクをリストするビューを追加していきましょう。

## 既存タスクの表示

> 最初に、`/`ルートを編集し、既存の全タスクをビューに渡しましょう。`view`関数は第２引数に、ビューで使用するデータを配列で受け付けます。配列のキーはビューの中で変数となります。

```php
Route::get('/', function () {
    $tasks = Task::orderBy('created_at', 'asc')->get();

    return view('tasks', [
        'tasks' => $tasks
    ]);
});
```

> データを渡したら、`tasks.blade.php`ビューの中でタスクを反復処理し、テーブルとして表示します。とても早く通常のPHPコードにコンパイルできる`@foreach` Blade構造文で簡単にループが記述できます。

### resources/views/tasks.blade.php

```html
<!-- TODO: 現在のタスク -->
```

ここのコードを下記のコードに差し替えます。
(インデントは揃えて貼り付けましょう)

```html
<!-- 現在のタスク -->
@if (count($tasks) > 0)
    <div class="panel panel-default">
        <div class="panel-heading">
            現在のタスク
        </div>
        <div class="panel-body">
            <table class="table table-striped task-table">
                <!-- テーブルヘッダ -->
                <thead>
                    <tr>
                        <th>タスク</th>
                        <th>&nbsp;</th>
                    </tr>
                </thead>
                <!-- テーブル本体 -->
                <tbody>
                    @foreach ($tasks as $task)
                        <tr>
                            <td class="table-text">
                                <div>{{ $task->name }}</div>
                            </td>
                            <!-- TODO: 削除ボタン -->
                            <td>
                            </td>
                        </tr>
                    @endforeach
                </tbody>
            </table>
        </div>
    </div>
@endif
```

http://127.0.0.1:10080

<img width="755" alt="スクリーンショット 2019-09-11 13.33.39.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/52879/80339ae5-b5ea-b172-5d99-1242665fa2d6.png">

> タスクアプリケーションは、もうほとんど完成です。しかし、終了した既存タスクを削除する手段がありません。次に実装しましょう。

## タスク削除

### 削除ボタンの追加

> コード中、削除ボタンを設置する場所に"TODO"を残してあります。では、`tasks.blade.php`ビューのタスクリストの各行に、削除ボタンを追加しましょう。小さなボタンひとつのフォームをリストの各タスクごとに作成します。ボタンがクリックされると、`DELETE /task`リクエストがアプリケーションに送信されます。

#### resources/views/tasks.blade.php

```html
<!-- TODO: 削除ボタン -->
```

ここのコードを下記のコードに差し替えます。
(インデントは揃えて貼り付けましょう)

```html
<!-- 削除ボタン -->
<td>
    <form action="{{ url('task/' . $task->id) }}" method="POST">
        @csrf
        @method('DELETE')

        <button type="submit" class="btn btn-danger">
            <i class="fa fa-btn fa-trash"></i> 削除
        </button>
    </form>
</td>
```

### 見せかけのメソッドの説明

> 削除ボタンフォームの`method`が`POST`を使用しているのにかかわらず、定義しているルートは`Route::delete`である点に注目です。HTMLフォームは`GET`と`POST` HTTP動詞のみを許しています。そのため、フォームの`DELETE`リクエストを見せかける手段が必要になります。

フォームの中で`@method('DELETE')`関数の結果を出力することにより、`DELETE`リクエストへ見せかけることができます。Laravelはこれを認識し、実際のHTTPリクエストメソッドをオーバーライドします。生成されるフィールドは次の内容です。

```html
<input type="hidden" name="_method" value="DELETE">
```

### タスク削除

> 最後に、指定したタスクを実際に削除するロジックをルートへ追加しましょう。`{task}`ルートパラメータに対応する`Task`モデルを自動的に取得するため、[暗黙のモデル結合](https://readouble.com/laravel/6.0/ja/routing.html#route-model-binding)が使えます。

> ルートのコールバックの中で、レコードを削除するために`delete`メソッドを使いましょう。レコードが削除された後は、ユーザを`/` URLへリダイレクトします。

#### routes/web.php

```php
Route::delete('/task/{task}', function (Task $task) {
    $task->delete();

    return redirect('/');
});
```

<img width="756" alt="スクリーンショット 2019-09-11 13.32.13.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/52879/b766d132-5528-fa12-6684-6c465a74037d.png">

## さいごに

以上でLaravel6.0の基本のタスクリストチュートリアルは完了です。
もしうまくいかなかった場合は下記のコメント欄より気軽にご質問ください。
またうまくいった場合も完成報告もらえると嬉しいです☺️