Laravel5 チュートリアル ブログもどきを作る(5) ブログ記事を削除する

[前回](https://qiita.com/yumgoo17/items/57d3c1e4f56e15ec82f0)は、既存記事の編集処理を実装しました。今回はブログ記事を削除する処理を実装していきます。



## ルーティングの追加
`routes/web.php` を開き、下記1行追加して、削除用のルーティングを追加します。

```routes/web.php
Route::post('admin/delete', 'AdminBlogController@delete')->name('admin_delete');
```



## モデルの編集
ソフトデリート（論理削除）をしたいので、その設定をします。`app/Models/Article.php` を開いて、下記のように編集します。

```app/Models/Article.php
<?php

namespace App\Models;

use Carbon\Carbon;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;

class Article extends Model
{
    // SoftDeletes トレイトを使う
    use SoftDeletes;

    ...（中略）...

    // $dates プロパティには、日時が入るカラムを設定する（日付ミューテタ）
    // そうすると、その値が自動的に Carbon インスタンスに変換される
    protected $dates = ['post_date', 'created_at', 'updated_at', 'deleted_at'];

    ...（中略）...
}
```

このように `use SoftDeletes;` と書き、`$dates` プロパティに `deleted_at` カラムを指定するだけで、削除実行時 deleted_at カラムに、削除日時が入り、論理削除となります。詳しくは[日本語ドキュメント](https://readouble.com/laravel/5.5/ja/eloquent.html)を参照してください。



## View テンプレートの編集
`resources/views/admin_blog/form.blade.php` を開いて、元々のフォームに下に、新たなフォームを作成して、そこに削除ボタンを追加します。

```html:resources/views/admin_blog/form.blade.php
			{{-- 元々のフォーム --}}
            <form method="POST" action="{{ route('admin_post') }}">
			... （中略） ...
            </form>

            @if ($article_id)
                <br>
                <form action="{{ route('admin_delete') }}" method="POST">
                    <input type="submit" class="btn btn-primary btn-sm" value="削除">
                    <input type="hidden" name="article_id" value="{{ $article_id }}">
                    {{ csrf_field() }}
                </form>
            @endif
```

新たにフォームを作成しているため「送信」ボタンと「削除」ボタンが横並びにならず、少し気持ち悪いですが、とりあえず目をつぶってください。



## リクエストクラスの編集
削除のときも、パラメータとして article_id を渡すので、そのバリデートを追加します。 `app/Http/Requests/AdminBlogRequest.php` を開いて下記のように編集します。

```app/Http/Requests/AdminBlogRequest.php
<?php

namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Support\Facades\Route;

class AdminBlogRequest extends FormRequest
{
    ... （中略）...

    /**
     * Get the validation rules that apply to the request.
     *
     * @return array
     */
    public function rules()
    {
        // 現在実行しているアクション名を取得
        // アクション名により、どのルールを使うのか場合分けをしておく
        $action = $this->getCurrentAction();

        $rules['post'] = [
            'article_id' => 'integer|nullable',              // 整数・null でもOK
            'post_date'  => 'required|date',                 // 必須・日付
            'title'      => 'required|string|max:255',       // 必須・文字列・最大値（255文字まで）
            'body'       => 'required|string|max:10000',     // 必須・文字列・最大値（10000文字まで）
        ];

        $rules['delete'] = [
            'article_id' => 'required|integer'     // 必須・整数
        ];

        return array_get($rules, $action, []);
    }

    ... （中略）...

    /**
     * 現在実行中のアクション名を返す
     *
     * @return mixed
     */
    public function getCurrentAction()
    {
        // 実行中のアクション名を取得
        // App\Http\Controllers\AdminBlogController@post のような返り値が返ってくるので @ で分割
        $route_action = Route::currentRouteAction();
        list(, $action) = explode('@', $route_action);
        return $action;
    }
}
```

コントローラーの `post()` と `delete()` の各メソッドでリクエストクラスを共用するので、それぞれどのアクション（メソッド）が実行されたとき、どのルールを使うのかを区別するために、条件分岐する必要があります。
そこで `getCurrentAction()` という実行中のアクション（メソッド）名を返す関数を新しく作成して、それを利用しています。実行中のアクション（メソッド）名により、`rules()` の返す値を変えています。`messages()` は変更ありません。`getCurrentAction()` は他のところでも汎用的に使えるメソッドなので、ヘルパー関数として定義するのが良いでしょう（今回は割愛します）。
もちろん、こんな面倒なことをしなくても、最初から、アクション（メソッド）毎に、リクエストクラスを分けるという方法もあります。



## コントローラーの編集
続いて削除処理を実装します。`app/Http/Controllers/AdminBlogController.php` を開いて、下記のように delete メソッドを追加します。

```app/Http/Controllers/AdminBlogController.php
    /**
     * ブログ記事削除処理
     *
     * @param AdminBlogRequest $request
     * @return \Illuminate\Http\RedirectResponse
     */
    public function delete(AdminBlogRequest $request)
    {
        // 記事IDの取得
        $article_id = $request->input('article_id');

        // Article モデルを取得して delete メソッドを実行することで削除できる
        // このとき万が一 $article が null になる場合も想定して実装するのが良い（今回は紹介のみで使わないので割愛）
//        $article = $this->article->find($article_id);
//        $article->delete();

        // 主キーの値があるなら destroy メソッドで削除することができる
        // 引数は配列でも可。返り値は削除したレコード数
        $result = $this->article->destroy($article_id);
        $message = ($result) ? '記事を削除しました' : '記事の削除に失敗しました。';

        // フォーム画面へリダイレクト
        return redirect()->route('admin_form')->with('message', $message);
    }
```

削除方法を2通り紹介しました。詳しくは[日本語ドキュメント](https://readouble.com/laravel/5.5/ja/eloquent.html)を参照してください。
ここまでできたら、実際に削除ボタンを押してみて、対象レコードの `deleted_at` カラムに削除日が入り、論理削除になるかどうかを確認してください。

今回は短いですが以上です。[次回は、記事一覧画面を実装していきます。](https://qiita.com/yumgoo17/items/250b5079ee5b2f2526f4)



## 参考資料
### Laravel 日本語ドキュメント
* [ルーティング](https://readouble.com/laravel/5.5/ja/routing.html)
* [Eloquentの準備](https://readouble.com/laravel/5.5/ja/eloquent.html)
* [Bladeテンプレート](https://readouble.com/laravel/5.5/ja/blade.html)
* [バリデーション](https://readouble.com/laravel/5.5/ja/validation.html)
* [コントローラ](https://readouble.com/laravel/5.5/ja/controllers.html)

### プログラムソース（github）
* [github yumgoo17/like_blog](https://github.com/yumgoo17/like_blog)