Laravel + Vue.js の知識をアウトプットしていく


次の記事でLaravelをアウトプットしていますが、今回はLaravel + Vueでまとめていきます。
[Laraveの知識をアウトプットして、資産化してます](https://qiita.com/gyu_outputs/items/eaff3072e04bc7cb44e6)

# 準備
```
$ composer create-project laravel/laravel sampleproject --prefer-dist "7.*"
```
プロジェクトの作成を実施

もろもろの初期設定はこちらの記事を参考にしてください
[Laraveの知識をアウトプットして、資産化してます](https://qiita.com/gyu_outputs/items/eaff3072e04bc7cb44e6)

```:認証機能をインストール
$ composer require laravel/ui "2.*" --dev
```

```:vueのインストール
$ php artisan ui vue --auth
$ npm install bootstrap-vue bootstrap
$ npm install && npm run dev
```
### vue-routerのインストール

```:vue-routerのインストール
npm install --save vue-router
```

下記を追加する。

```js:resources/app.js
import VueRouter from 'vue-router';

window.Vue = require("vue");
Vue.use(VueRouter);
const router = new VueRouter({
    mode: "history",
    routes: [
        {
            path: "/tasks",
            name: "task.list",
            component: TaskListComponent
        }
    ]
});

const app = new Vue({
    // (1) mountする要素。<div id="app">なので、#app
    el: "#app",
    router
});
```
app.blade.phpに`<router-view>`を追加します

```php:app.blade.phpにrouter-viewを追加
<body>
    <div id="app">
        <router-view></router-view>
    </div>
    <!-- Scripts -->
    <script src="{{ mix('js/app.js') }}"></script>
</body>
```

urlをつける場合は公式ドキュメントの[こちら](https://router.vuejs.org/ja/guide/essentials/named-routes.html)

### Vuexのインストール

stateで情報をやりとりするために利用する。
ドキュメントは[こちら](https://vuex.vuejs.org/ja/)


```
$ npm install --save-dev vuex
```

```
npm run dev
```
vue-routeをimportする



Laravel Mixで読み込み

```php:mixに変更
<!-- Styles -->
<link href="{{ mix('css/app.css') }}" rel="stylesheet">

<!-- Script -->
<script src="{{ mix('/js/app.js') }}" defer></script>
```
## デバッグのインストール

```コマンド
composer require itsgoingd/clockwork
```
ddのように変数をデバッグ可能

```
clock(User::all());
```

# 流れ
1. コンポーネントの作成
2. app.jsにimport
3. HTMLにコンポーメントを追加して表示。
3. vue-routerでURLと画面を切り替え

## コンポーネント（Component）の作成

```vue:components/HeaderComponent.vue
<template>
  <div class="container-fluid bg-dark mb-3">
    <div class="container">
      <nav class="navbar navbar-dark">
        <span class="navbar-brand mb-0 h1">Vue Laravel SPA</span>
        <div>
          <button class="btn btn-success">List</button>
          <button class="btn btn-success">ADD</button>
        </div>
      </nav>
    </div>
  </div>
</template>

<script>
export default {};
</script>
```

## app.jsにimport

```js:app.js
// import
import HeaderComponent from "./components/HeaderComponent";

// componentのタグ名を決める
Vue.component("header-component", HeaderComponent);

```

## HTMLにコンポーメントを追加して表示。

```vue:example-componentの読み込み
<div id="app">
  <header-component></header-component>
  <router-view></router-view>
</div>
```

## vue-routerでURLと画面を切り替え
直接componentを挿入する場合は、`Vue.component`で挿入するが、ページ遷移ごとに挿入させるcomponentを切り替えたい場合は、Vue-routerで切り替えていきます。

```js
Vue.use(VueRouter);
const router = new VueRouter({
    mode: "history",
    routes: [
        {
            path: "/tasks",
            name: "task.list",
            component: TaskListComponent
        },
        {
            path: "/tasks/:taskId",
            name: "task.show",
            component: TaskShowComponent,
            props: true
        },
        {
            path: "/tasks/create",
            name: "task.show",
            component: TaskShowComponent,
            props: true
        }
    ]
});

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

```
上記のVue-routerの記述で、pathごとのcomponentを定義している。
このcomponentは`<router-view>`に挿入される。それでpathごとに異なるcomponentが挿入されてページ遷移される。

```vuejs

<div id="app">
   <router-view></router-view>
</div>
```

#CRUD機能の実装

#ログイン機能の実装
[Laravel 7.x Laravel Sanctum](https://readouble.com/laravel/7.x/ja/sanctum.html)
[参考になるQiita記事](https://qiita.com/ntm718/items/ada07bad631a39ca30b9)

## sanctumインストール

```:コマンド
composer require laravel/sanctum
```

構成ファイルの公開を実施します

```:コマンド
php artisan vendor:publish --provider="Laravel\Sanctum\SanctumServiceProvider"
```

マイグレーションの実行

```:コマンド
php artisan migrate
```
`CreatePersonalAccessTokensTable`が実行され、`personal_access_tokens`テーブルが追加されます。
また、`config/sanctum.php`も追加されます

## Kernel.phpにsanctumのミドルウェアを追加

SPAの認証として利用できるように、Kernel.phpファイルのapiミドルウェアにSanctumのミドルウェアを追記します。これでAPIに対するリクエストでセッション・クッキーによる自動認証が可能となります。

```php:Http/Kernel.php
<?php

namespace App\Http;

use Illuminate\Foundation\Http\Kernel as HttpKernel;
// ↓追加
use Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful; 

class Kernel extends HttpKernel
{
    /**
     * The application's global HTTP middleware stack.
     *
     * These middleware are run during every request to your application.
     *
     * @var array
     */
    protected $middleware = [
        \App\Http\Middleware\TrustProxies::class,
        \App\Http\Middleware\CheckForMaintenanceMode::class,
        \Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
        \App\Http\Middleware\TrimStrings::class,
        \Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,
    ];

    /**
     * The application's route middleware groups.
     *
     * @var array
     */
    protected $middlewareGroups = [
        'web' => [
            \App\Http\Middleware\EncryptCookies::class,
            \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
            \Illuminate\Session\Middleware\StartSession::class,
            // \Illuminate\Session\Middleware\AuthenticateSession::class,
            \Illuminate\View\Middleware\ShareErrorsFromSession::class,
            \App\Http\Middleware\VerifyCsrfToken::class,
            \Illuminate\Routing\Middleware\SubstituteBindings::class,
        ],

        'api' => [
            EnsureFrontendRequestsAreStateful::class, //追加
            'throttle:60,1',
            'bindings',
        ],
    ];
    ~略~
}

```

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

```:ログイン用のコントローラーを作成
php artisan make:controller LoginController
```

自前のログイン処理を作成するために、[Auth::attempt](https://readouble.com/laravel/7.x/ja/authentication.html)を記述していく。

```php:LoginController.php

<?php
 
namespace App\Http\Controllers;
 
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Validation\ValidationException;
 
class LoginController extends Controller
{
    public function login(Request $request)
    {
        //validation
        $credentials = $request->validate([
            'email' => 'required|email',
            'password' => 'required'
        ]);
 
        //認証処理
        if (Auth::attempt($credentials)) {
            //認証に成功した場合
            return response()->json(['message' => 'Login successful'], 200);
        }

        //エラーメッセージの作成
        throw ValidationException::withMessages([
            'email' => ['The provided credentials are incorrect'],
        ]);
    }
    
    //logout処理を追加 
    public function logout()
    {
        //ログアウトの実行
        Auth::logout();
        //ログアウト成功したレスポンスをreturnする。
        return response()->json(['message' => 'Logged out'], 200);
    }
}
```


自前のエラー文を作成するために、[`use Illuminate\Validation\ValidationException;`](https://qiita.com/kiyc/items/84068240bd3eb55ee3b5)
`$validator->errors()->add($key, $message)`することで、自由にメッセージを追加することができます。
[こちらの記事も参考になります](https://qiita.com/mikakane/items/549095f022e5728c3670)
[GitHubはこちら](https://github.com/illuminate/validation/blob/master/ValidationException.php)


### throwについて


```php:ValidationExceptionの記述
$validator = Validator::make([], []);
$validator->errors()->add('title', 'タイトルのエラーです。');
throw new ValidationException($validator);

// もしくは

throw ValidationException::withMessages(['title' => 'タイトルのエラーです。']);
```

```php:例外処理の基本
<?php
 
try {
    // 例外が発生する可能性のあるコード
} catch (Exception $e) {
    // 例外が発生した場合に行う処理
}
 
?>
```

## ルーティングの記述
APIでの認証を実施するため、api.phpでルーティングを記述する。

```php:api.php

<?php
 
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;
 
Route::middleware('auth:sanctum')->get('/user', function (Request $request) {
    return $request->user();
});
 
Route::post('/login', 'LoginController@login');
Route::post('/logout', 'LoginController@logout');
```

#その他
## リダイレクト
`this.$router.push({name: 'task.list'});`でnameを指定してリダイレクトすることが可能