環境構築から始めてLaravel 6 + Vue.jsでタスク一覧を作るチュートリアル

LaravelとVue.jsの学習用に簡単なプログラムを作ってみました。

## 完成品

このような画面を作ります。

![laravel-vue-task-list.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/33324/bc8d4ab7-5643-20ab-1373-98a62b1a44fb.gif)
urlを開くとタスクの一覧が表示されます。
filterに値を入力すると合致するタイトルの絞り込みができます。
これだけです。簡単ですね。
開発時間として60-90分くらいで完成させることができると思います。

それでは作っていきます。

## Laravel開発環境の構築

今回は[Homestad](https://readouble.com/laravel/6.0/ja/homestead.html)で開発環境を構築します。
※開発PCはMacを前提としますが、virtualboxとvagrantのインストール以外はほぼ同じだと思います。

```sh
# 必要ソフトのインストール
$ brew cask install virtualbox
$ brew cask install vagrant

# homesteadのセットアップ
$ vagrant box add laravel/homestead
$ git clone https://github.com/laravel/homestead.git
$ cd homestead
$ bash init.sh

# Homestead.ymlの編集とローカルのhotsファイルの編集
# ipはローカルpcのネットワークセグメントとは異なる値にする
$ vi Homestead.yml　
# Homestead.ymlのipとsites_mapの対応を追記する
$ vi /etc/hots
```
### Homesteadの起動と接続

```sh
# 起動
$ vagrant up
# 接続
$ vagrant ssh
```
※以降のコマンドはHomested上で実行します。

## Laravelのプロジェクト作成
```
$ cd ~/code
$ laravel new
```

[http://homestead.test](http://homestead.test)をブラウザで開くと以下のような画面が表示されます。
<img width="952" alt="スクリーンショット 2019-10-07 22.58.08.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/33324/36135149-66bf-f140-47f3-a35fa90ac11f.png">

## Vue.jsのセットアップ

LaravelのプロジェクトでVue.jsを扱えるようにします。

```sh
# UIのscaffoldingなどに必要な公式パッケージのインストール
$ composer require laravel/ui

# ログイン機能の生成
# package.jsonにvueとvue-template-compilerが追加される
$ php artisan ui vue --auth

$ npm install
$ npm run dev
```

`$php artisan ui vue --auth`により[ログイン画面(/login)](http://homestead.test/login)や[ユーザ登録画面(/register)](http://homestead.test/login)が生成されます。

<img width="1200" alt="スクリーンショット 2019-10-07 23.02.04.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/33324/07dc8566-d73c-a70b-13c3-245f38e1988f.png">

同時にログイン後の[初期画面(/home)](http://homestead.test/login)用の以下ファイルが生成されます。

* app/Http/Controllers/HomeController.php
* resources/views/home.blade.php

更に、web.phpにルーティングが追加されます。

```php
# /homeのルーティングが追加される
# /homeへのgetリクエスト時にHomeController::index()を実行する。
Route::get('/home', 'HomeController@index')->name('home');
```
以降で/homeにアクセスするとタスクの一覧が表示されるようにしていきますが、一旦置いておきます。

## モデルとマイグレートファイルの作成

DBにタスクテーブルを作成しLaravelで扱えるようにするためモデルとマイグレーションファイルを作成します。

```sh
# --migrationでモデルとマイグレーションファイルを同時に作成する
$ php artisan make:model Models/Task --migration
```

以下のファイルが生成されます。

* app/Models/Task.php
* database/migrations/YYYY_MM_DD_hhmmss_create_tasks_table.php


### マイグレートファイルの編集

YYYY_MM_DD_hhmmss_create_tasks_table.phpに追記してタイトルと内容のカラムを追加します。

```php
class CreateTasksTable extends Migration
{
    public function up()
    {
        Schema::create('tasks', function (Blueprint $table) {
            $table->bigIncrements('id');
            //2カラム追加
            $table->string('title');
            $table->text('content')->nullable();//nullを許可

            $table->timestamps();
        });
    }
```

### マイグレートの実行

以下のコマンドを実行するとDBにTasksテーブルが作成されます。

```sh
$ php artisan migrate
```

## ルーティングの追加

Laravelではページ用のルーティングとAPI用のルーティングが別のファイルになっています。
今はAPIのルーティングを追加するため以下のファイルに追記します。

* routes/api.php

```php
# パスはapi/taskになる
# getリクエスト時にTaskControllerのindexメソッドを実行する
Route::get('/task', 'TaskController@index');
```


## コントローラーの作成

タスクを扱うコントローラを作成します。後ほどこれにタスクの一覧をjsonで返すindex()という名前のメソッドを実装します。

```sh
# app/Http/Controllers/TaskController.phpが生成される
$ php artisan make:controller TaskController
```

### APIの処理実装

index()メソッドを実装します。
今回はシンプルにTasksテーブルの全データをjsonで返すようにしました。
`Task::all()`はCollectionという配列のラッパークラスにtasksテーブルの全データを
詰め込んだ状態で返します。
CollectionクラスのインスタンスをControllerのメソッドでreturnすると、Laravelが自動的にjsonに
変換してくれます。便利ですね。

```php
<?php
namespace App\Http\Controllers;

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

class TaskController extends Controller
{
    //indexメソッドを実装する
    public function index()
    {
        //Tasksテーブルの全レコード取得
        //Collectionクラスをreturnすると自動的にjsonにしてくれる
        return Task::all();
    }
}
```

これでタスクの一覧をjsonで取得する[api](http://homestead.test/api/task)完成しました。

## テストデータの自動作成

次にテスト用のTasksテーブルのデータを自動作成できるようにしていきます。
今回はやりませんがテスト自動化をする場合に便利です。
とりあえず手動でデータ追加するという人はここを飛ばしても問題ありません。

### ファクトリーの作成

ファクトリーは自動作成するデータの値(範囲や形式)を定義することができます。

```sh
# ファクトリーファイルの作成
$ php artisan make:factory TaskFactory
```

フェイクデータを簡単に作成できるFakerを使用します。
様々な種類のデータを作成するためのメソッドが用意されています。
参考 [[Laravel5.1]Fakerチートシート](https://qiita.com/tosite0345/items/1d47961947a6770053af)

```php
use App\Models\Task;
use Faker\Generator as Faker;


// 作成データの定義
$factory->define(Task::class, function (Faker $faker) {
    return [
        'title' => $faker->word, //言葉
        'content' => $faker->sentence, //文章
        'user_id' => $faker->numberBetween(1, 5)//1-5の数値
    ];
});
```

### シーダーの作成

次にデータ作成を実行するシーダーを作ります。

```sh
# シーダーファイルを作成
$ php artisan make:seeder TasksTableSeeder
```

以下のように記述すると先程作成したファクトリーが呼び出され、その定義に従ってデータが作成されます。

```php
use Illuminate\Database\Seeder;
use App\Models\Task;

class TasksTableSeeder extends Seeder
{
    public function run()
    {
        //ファクトリーの定義に従って20件のデータを作成
        factory(Task::class, 20)->create();
    }
}
```

次に`$ php artisan db:seed`を実行すると`TasksTableSeeder`が実行されるように`DatabaseSeeder`に追記します。

```php
use Illuminate\Database\Seeder;

class DatabaseSeeder extends Seeder
{
    public function run()
    {
        //追記
        $this->call(TasksTableSeeder::class);
    }
}
```

ここまでできたら以下のコマンドを実行するとシーダーが実行されてデータが自動作成されます。
[ドキュメント](https://readouble.com/laravel/6.0/ja/seeding.html)には以下のような記載があり、実際にこれをしないとシーダー実行時にエラーになります。なぜ必要になるのかまだ私はしっかりと理解できていないので、知っている方教えていただけると幸いです。

>シーダクラスを書き上げたら、Composerのオートローダを再生成するために、dump-autoloadコマンドを実行する必要があります。

```sh
$ composer dump-autoload
```

シーダーを実行します。これでデータが自動作成されます。

```sh
$ php artisan db:seed
```

## タスク一覧画面の作成

### Vueコンポーネントの作成

タスクの一覧を表示するコンポーネントを作ります。

```sh
# ファイル作成
$ touch resources/js/components/TasksComponents.vue
```

以下の通りに記述します。やっていることは大きく以下の3つです。

* apiからタスクの一覧を取得しtasksに格納 
* input textの入力値をタイトルに含むタスクだけを抽出
* 抽出したタスクを一覧表示

```html
<template>
    <div class="container">
　　　　　<!-- v-modelで変数と入力値を同期させる -->
        <input v-model="condition" class="form-control filter" type="text" placeholder="filter">
        <div class="list-group">
            <!-- v-forで条件に合致したタスクを繰り返し表示する -->
            <div v-for="task in matched" :key="task.id"
                 class="list-group-item list-group-item-action flex-column align-items-start">
                <div class="d-flex w-100 justify-content-between">
                    <h5 class="mb-1">{{ task.title }}</h5>
                    <small class="text-muted">{{ task.created_at }}</small>
                </div>
                <p class="mb-1">{{ task.content }}</p>
            </div>
        </div>
    </div>
</template>

<script>
    export default {
        name: "TasksComponents.vue",
        data: function () {
            return {
                condition: null, //フィルタ条件
                tasks: [] //タスクの配列
            }
        },
        created() {
            //インスタンス生成時にapiからタスク一覧を取得して変数に格納
            axios.get('/api/task').then(response => {
                this.tasks = response.data
            })
        },
        computed: {
            matched: function () {
                //conditionの値が変更されると自動的に呼び出される
                return this.tasks.filter(function (element) {
                    //タイトルにcondionの値を含むものでフィルタ
                    return !this.condition || element.title.indexOf(this.condition) !== -1
                }, this)
            }
        }
    }
</script>

<style scoped>
    .filter {
        margin: 1em 0em;
    }
</style>

```

### コンポーネントの登録

先程作成したコンポーネントを`resources/js/app.js`に登録します。

```js
require('./bootstrap');

window.Vue = require('vue');

//ここを追記 コンポーネントの登録
Vue.component('tasks-component', require('./components/TasksComponents.vue').default);

const app = new Vue({
    el: '#app',
});

```

### コンポーネントの呼び出し

コンポーネントを登録したので呼び出せるようになりました。
`resources/views/home.blade.php`を以下のように編集します。

```html
{{ --@からはじまるのはbladeの構文 --}}
@extends('layouts.app')

@section('content')
    {{-- コンポーネントを呼び出す --}}
    <tasks-component></tasks-component>
@endsection
```

以上でコーディングは完了です。

## 実行

開発環境で実行するには以下のコマンドを実行します。
アセットの関連ファイル変更時に自動的にコンパイルしてくれます。

```sh
# ファイルの変更時にアセットを自動的にコンパイルする
$ npm run watch
```

http://homestead.test/home
にアクセスするとタスクの一覧が表示されます。


以上