Vue CLI × Laravel × VuetifyでCSSいらずの爆速開発でTodoリストを作る part6

#前回のパート
前回はログアウト機能の実装を行いました
前回で認証まわりの実装が終わったので、今パートからはTodo機能の実装に入っていきます
前回のパートはこちら[Vue CLI × Laravel × VuetifyでCSSいらずの爆速開発でTodoリストを作る part5](https://qiita.com/Kyu-Taro/items/693b9defdf66be3a5cb7)

#Todoリストの機能
まず、今回のTodoリストの機能をおさらいしておきます
Todoリストの実装する機能は下記の4点になります
削除や新規作成の際などにアニメーションは付けないシンプルなものになっていますので
アニメーションが欲しい方は、一通り実装が終わった際に自身で挑戦してみてください

- todoの一覧表示
- todoの新規追加
- todoの更新
- todoの削除(完了時)

それでは、上記の4点の実装を行っていきます
まず最初に新規Todoの追加機能の実装から入ります

#Laravel側の実装
まずはコントローラーの作成を行います
上記の機能で確認した通り、表示,追加,更新,削除の機能なので
Todo専用の一つのコントローラーである
リソースコントローラーを作成しそれを利用していきます

コマンドにて下記を実行しコントローラーの作成を行ってください
`$ php artisan make:controller TodoController --resource`
実行で作成されるのが下記のファイルになっているかと思います

```TodoController.php
<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Todo;
use Log;

class TodoController extends Controller
{
    public function index()
    {
        //
    }

    public function create()
    {
        //
    }

    public function store(Request $request)
    {
        //
    }

    public function show($id)
    {
        //
    }

    public function edit($id)
    {
        //
    }

    public function update(Request $request, $id)
    {
        //
    }

    public function destroy($id)
    {
        //
    }
}
```
リソースコントローラーについて、わからない方はこちらを参照ください→[こちら](https://readouble.com/laravel/5.7/ja/controllers.html)

これで、Todoに関する全ての処理を行うコントローラーの作成が終わりました
次に`api.php`に作成したリソースフルコントローラーのルートを定義します
`api.php`を開いて下記を追加してください

```api.php
<?php

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;

Route::post('/register', 'Auth\RegisterController@register')->name('register');
Route::post('/login', 'Auth\LoginController@login')->name('login');
Route::post('/logout', 'Auth\LoginController@logout')->name('logout');
Route::get('/user', function(){
    return Auth::user();
});
Route::resource('/todo', 'TodoController');    //追加
```

もう少しLaravel側での実装がありますが
一旦Vue側の実装に移ります

#Vue側の実装
それでは次に、Vue側で既に作成した`Todo.vue`を開きそちらを編集していきます
`Todo.vue`を開いて下記を追加してください
内容については、一つづ説明していきます

 ```Todo.vue
<template>
    <div>
        <Header />
        <div class="main-container">
            {{ user.name }}のTodoリスト    //・・・①

            <v-text-field v-model="text" label="todo" required></v-text-field>
            <v-btn class="btn" @click="create">登録</v-btn>    //・・・②

            <template v-for="item in items">
                <v-card max-width="450" class="mx-auto" style="marign-top: 10px" :key="item.id">
                    <v-list three-line>
                        <v-list-item :key="item.id">
                            <v-list-item-content>
                                <input type="text" v-model="item.text">    //・・・③
                                <v-btn small>完了</v-btn>
                            </v-list-item-content>
                        </v-list-item>
                    </v-list>
                </v-card>
            </template>
        </div>

    </div>
</template>

<script>
    import Header from './Header';
    import axios from 'axios';

    export default {
        components: {
            Header
        },
        metaInfo: {
            title: 'Todo',
            htmlAttrs: {
                lang: 'ja'
            }
        },
        created () {    //・・・④
            const user = this.$store.getters['auth/user'];
            if (user === null) {
                this.$router.push('/login');
            }
        },
        computed: {
            user() {    //・・・⑤
                return this.$store.getters['auth/user'];
            }
        },
        data () {
            return {
                items: [    //・・・⑥
                    { id: 1, text: 'テスト'},
                    { id: 2, text: 'テスト'}
                ],
                text: ''
            }
        },
        methods: {
            async create() {    //・・・⑦
                await axios.post('/api/todo', { text: this.text });

                axios.get('/api/todo/' + this.user.id)
                .then((res) => {
                    const newItem = res.data.slice(-1)[0];
                    this.items.push(newItem);
                })

                this.text = '';
            },
        }
    }
</script>

<style>
    .main-container {
        width: 500px;
        margin: auto;
    }
    .btn {
        margin-bottom: 20px;
    }
</style>
```

①は認証ユーザーの情報のVuexで保管してるデータを所得して、ユーザーの名前を表示しています
②クリックイベントでtodoの登録処理のメソッドを発火させます
③今後の機能実装でtodoの内容を表示し書き換えて変更など出来る様に`<input>`にv-modelで現在のダミーのデータを表示しています
④ログインしているかをチェックしています。ログインしていなければ`/login`にリダイレクトされる様にしています
⑤こちらは①でユーザー名を参照するためにcomputedを使ってauth.jsのgetterを利用してstateのuserの情報を所得しています
⑥現在はtodo内容の表示機能がないため、ダミーデータを配置してます
⑦実際のtodoの登録処理のメソッドになります。詳しくは下で話します

⑦のメソッドについて説明します
ここで行っている処理は、フォームに追加したいtodoの内容が入力され登録ボタンが押されると
Laravel側の先ほど定義した`/todo`に対してPOSTリクエストを送信します
そうすることでLaravelで作成した`TodoController.php`の`store()`アクションが呼び出されます
`store()`には登録したい内容であるtodoの内容を送ります
それがここの第二引数で指定しています
` await axios.post('/api/todo', { text: this.text });`
これを受け取ったLaravel側の`TodoController.php`の`store()`アクションがDBに登録処理を行います
その後`/todo`に対して最新のtodoの情報を所得し
`const newItem = res.dataslice(-1)[0]`こちらでそのデータの最後(今回登録したデータ)を所得し
`this.items.push(newItem)`としてitemsに追加してVue側に反映しています

上記で登録処理をするにあったって、Vue側で必要な実装は完了しましたので
残るは、`TodoController.php`の`store()`アクションの実装を行えば登録ができるようになります

#store()アクションの機能実装
それでは、VueからリクエストでPOSTされて送られてきたデータをLaravel側でDBに登録する処理を
store()に記述していきます
`TodoController.php`を開き`store()`に下記を追加してください

```TodoController.php
public function store(Request $request)
{
    $request->user()->tasks()->create($request->all());

    return response('', 200);
}
```

`$request->user()`で現在の認証されているユーザーを所得し`tasks()`はリレーションで
Userのidとtodoのuser_idを紐づけています
`tasks()->create($request->all())`ここで新規追加を行っています
リレーションの設定はこのあと行います

`User.php`を開いてリレーションを定義していきます

```User.php
<?php

namespace App;

use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use App\Todo;

class User extends Authenticatable
{
    use Notifiable;

    /**
     * The attributes that are mass assignable.
     *
     * @var array
     */
    protected $fillable = [
        'name', 'email', 'password',
    ];

    /**
     * The attributes that should be hidden for arrays.
     *
     * @var array
     */
    protected $hidden = [
        'password', 'remember_token',
    ];

    /**
     * The attributes that should be cast to native types.
     *
     * @var array
     */
    protected $casts = [
        'email_verified_at' => 'datetime',
    ];

    public function tasks() {    //追加
        return $this->hasMany(Todo::class);
    }
}
```


次に`Todo::create($request->all())`を実行するために`Todoモデル`の作成と編集を行います
コマンドにて下記を実行してください
`$ php artisan make:model Todo`
上記を実行することで、`app`ディレクトリ配下に`Todo.php`が作成されます
これが、todosテーブルと紐づいたTodoのモデルになります
それでは、`Todo.php`に下記を追加してください

```Todo.php
<?php

namespace App;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;    //追加

class Todo extends Model
{
    use SoftDeletes;    //追加

    protected $fillable = [    //追加
        'user_id','text'
    ];
}
```
ここではSoftDeletes(論理削除)を利用するための記述と
`$fillabel`を追加しました

論理削除は`Illuminate\Database\Eloquent\SoftDeletes`をuseで追加しモデル内で`use SoftDeletes`とすることで利用できます

`protected $fillabel`ここで`user_id`と`text`を指定してます
todosテーブルのuser_idとtextを一括で更新をすることを許可しています
これを行うことで、先ほど記述した`store()`内の処理で登録が行えます

これでtodo登録に必要な処理は一通り実装できました
一度フォームに入力して登録ボタンをクリックしてみてください
その後、DBのtodosテーブルに実際に登録できているかを確認してみてください
無事データがあれば完了です

確認方法が分からない方は、このまま一旦進んでください
次回のパートで表示機能を作りますので、そこで正常に登録が行えてるのかも確認できます

#終わりに
今回は、todoの登録機能を実装しました
残る機能は、表示,更新,削除です
次回、表示機能の実装を行っていきます

次回のパートはこちら→[Vue CLI × Laravel × VuetifyでCSSいらずの爆速開発でTodoリストを作る part7](https://qiita.com/Kyu-Taro/items/9559c047bd2e5612363b)