laravel5.5 会員の退会機能 論理削除(ソフトデリート)の実装

## はじめに
laravel5.5を使用しており、最新のバージョンではありません。

## 論理削除の流れ
退会したユーザのデータをDBから完全に削除せず、
復元が可能であるような方法を論理削除と言います。

ユーザが'退会する'というボタンをクリック
↓
ユーザは登録した情報でログインができなくなる
↓
DBには、ユーザが会員登録したデータは残っている状態

## 前提
- laravelの環境構築を終えている
- MAMPを使用
- DBの接続を終えている
- ユーザのログイン機能は実装済み

## 実装手順
ログイン機能が実装済みの方は1から読み進めてください。

[0.ログイン機能の実装](#0-ログイン機能の実装)
[1.データベースの編集](#1-データベースの編集)
[2.userモデルの編集](#2-userモデルの編集)
[3.seederでデータを入れてみる](#3-seederでデータを入れてみる)
[4.ルーティングの追加](#4-ルーティングの追加)
[5.viewの編集](#5-viewの編集)
[6.コントローラーの作成](#6-コントローラーの作成)
[7.動作確認](#7-動作確認)

#0. ログイン機能の実装
laravelのバージョンによってコマンドが異なります。

```php:ターミナル
//Larvel5.8まで
$php artisan make:auth

//Laravel6.x 以降
$composer require laravel/ui --dev
$php artisan ui bootstrap --auth
```
このコマンドのみでログイン機能は完了です。(便利すぎます...!)
本来は`$php artisan migrate`をターミナルで実行します。
今回はカラムの追加がありますのでそのまま次の作業に進みましょう。

#1. データベースの編集
今回は既存のcreate_users_tableを編集していきます。
`softDeletes()`と定義することで論理削除に必要なカラムが作成されます。
＊ xxxxには日時などが入ります。

```diff_php:database/migrations/xxxx_create_users_table.php
class CreateUsersTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('users', function (Blueprint $table) {
            $table->increments('id');
            $table->string('name');
            $table->string('name_kana');
            $table->string('address');
            $table->char('postal_code', 7);
            $table->string('email')->unique();
            $table->string('password');
            $table->rememberToken();
+           $table->softDeletes();
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('users');
    }
}
```
カラムが追記できたら下記を忘れずに実行しましょう。

```php:ターミナル
$php artisan migrate
```
DBに`deleted_at`というカラムが作成されているか確認してみて下さい。
[![Image from Gyazo](https://i.gyazo.com/08ecab6b0e94ae2896f54e6f6ecee34d.png)](https://gyazo.com/08ecab6b0e94ae2896f54e6f6ecee34d)

#2. userモデルの編集
use SoftDeletes でソフトデリートを使用できるようにしています。

```diff_php:app/User.php
<?php

namespace App;

use Illuminate\Notifications\Notifiable;
use Illuminate\Foundation\Auth\User as Authenticatable;
+ use Illuminate\Database\Eloquent\SoftDeletes;

class User extends Authenticatable
{
    use Notifiable;
+   use SoftDeletes;

    /**
     * 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',
    ];
}
```

#3. seederでデータを入れてみる
まずは、Userモデルのseedを作成します。

```php:ターミナル
php artisan make:seeder UsersTableSeeder
```

seedsディレクトリの中に
`UsersTableSeeder.php`が作成されますので、編集していきましょう。
name,email,passwordは何でも構いませんので自由に決めてください。

⚠️emailのドメインはなるべく`example.com`を使用した方が良いです。

```diff_php:database/seeds/UsersTableSeeder.php
<?php

use Illuminate\Database\Seeder;

class UsersTableSeeder extends Seeder
{
    /**
     * Run the database seeds.
     *
     * @return void
     */
    public function run()
    {
+       DB::table('users')->insert([
+           'name' => 'テスト',
+           'email' => 'test@example.com',
+           'password' => Hash::make('000000'),
+       ]);
    }
}
```
`DatabaseSeeder.php`に以下を追記します。

```diff_php:database/seeds/DatabaseSeeder.php
<?php

use Illuminate\Database\Seeder;

class DatabaseSeeder extends Seeder
{
    /**
     * Run the database seeds.
     *
     * @return void
     */
    public function run()
    {
+       $this->call(UsersTableSeeder::class);
    }
}

```

編集が終わったら、DBに反映させます。

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

データが入っているか、DBを確認してみましょう。
[![Image from Gyazo](https://i.gyazo.com/490ad727dd6b28cd3adeba7094e4f2d7.png)](https://gyazo.com/490ad727dd6b28cd3adeba7094e4f2d7)

#4. ルーティングの追加
退会処理を行うためのルーティングを追記します。

```diff_php:routes/web.php
<?php

Route::get('/', function () {
    return view('welcome');
});

Auth::routes();

Route::get('/home', 'HomeController@index')->name('home');

+ Route::post('/user', 'UsersController@withdrawal')->name('user.withdrawal');

```
#5. viewの編集
今回は、ヘッダーの中に”退会する”というボタンを作成したいと思います。
本来はフォームだけでもいいのですが、既存のheaderに合わせてドロップダウンの中に表示させたいため、
aタグとformを使って実装しています。

`confirm('本当に退会しますか？')`はアラートを表示させるために記述しています
以下のような確認のアラートが出てきます。

[![Image from Gyazo](https://i.gyazo.com/626673630ff35128cd0a0915170c3684.png)](https://gyazo.com/626673630ff35128cd0a0915170c3684)
                                                
`document.getElementById('withdrawal-form').submit()`は、
formの`id="withdrawal-form"`と指定している部分の要素を取得して
`.submit()`で送信処理を行っています。

```diff_php:resources/views/layouts/app.php
<body>
    <div id="app">
        <nav class="navbar navbar-default navbar-static-top">
            <div class="container">  
                <div class="collapse navbar-collapse" id="app-navbar-collapse">
                    ...省略
                    <!-- Right Side Of Navbar -->
                    <ul class="nav navbar-nav navbar-right">
                        <!-- Authentication Links -->
                        @guest
                            <li><a href="{{ route('login') }}">Login</a></li>
                            <li><a href="{{ route('register') }}">Register</a></li>
                        @else
                            <li class="dropdown">
                                <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-expanded="false" aria-haspopup="true" v-pre>
                                    {{ Auth::user()->name }} <span class="caret"></span>
                                </a>

                                <ul class="dropdown-menu">
                                    <li>
                                        <a href="{{ route('logout') }}"
                                            onclick="event.preventDefault();
                                                    document.getElementById('logout-form').submit();">
                                            Logout
                                        </a>

                                        <form id="logout-form" action="{{ route('logout') }}" method="POST" style="display: none;">
                                            {{ csrf_field() }}
                                        </form>
                                    </li>
+                                   <li>
+                                       <a href="{{ route('user.withdrawal') }}"
+                                           onclick="confirm('本当に退会しますか？');
+                                                   event.preventDefault();
+                                                   document.getElementById('withdrawal-form').submit();">
+                                           退会する
+                                       </a>

+                                       <form id="withdrawal-form" action="{{ route('user.withdrawal') }}" method="post" style="display: none;">
+                                           {{ csrf_field() }}
+                                       </form>
+                                   </li>
                                </ul>
                            </li>
                        @endguest
                    </ul>
                </div>
            </div>
        </nav>

        @yield('content')
    </div>

    <!-- Scripts -->
    <script src="{{ asset('js/app.js') }}"></script>
</body>
```

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

まずは、UsersControllerを作成するコマンドを打ちます。

```php:ターミナル
$php artisan make:controller UsersController
```
作成されたら、中身を編集していきます。
`Auth::user()`は、ログインしている人の情報が取得できます。
⚠️Authを使用するときはuseを書き忘れないように気をつけましょう。
`$user->delete()`で削除の処理を行います。
そして、`Auth::logout()`でログアウトさせています。

```diff_php:app/Http/Controllers/UserController.php
<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
+ use Illuminate\Support\Facades\Auth;

class UsersController extends Controller
{
+   public function withdrawal()
+   {
+       $user = Auth::user();
+       $user->delete();
+       Auth::logout();
+       return redirect(route('login'));
+   }
}
```
#7. 動作確認
ここまで作業ができましたら、動作の確認をしてみます。
①サーバーを立ち上げる
②seederで入れた情報でログインする
③ヘッダーの"退会する"ボタンを押す
④再度、seederで入れた情報でログインしてみる

ログインができなければ、きちんと退会機能ができています。

dbも確認してみましょう。
`deleted_at`の中に日時が入っていれば、OKです。
[![Image from Gyazo](https://i.gyazo.com/2e229a4831c3ea7f0a7984726d2a7a5b.png)](https://gyazo.com/2e229a4831c3ea7f0a7984726d2a7a5b)

## 最後に
今回はルーティングにidを持たせず実装を行いました。
softdeleteを使用すると、とても簡単に実装ができました。

## 参考文献

この記事は以下の情報を参考にして執筆しました。

- [[Laravel] ソフトデリートと取得、復元、完全削除](https://qiita.com/kuropp/items/b7c6c068a90ec7bdcd73)