PHP
laravel
laravel5

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

前回は、既存記事の編集処理を実装しました。今回はブログ記事を削除する処理を実装していきます。

ルーティングの追加

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 カラムに、削除日時が入り、論理削除となります。詳しくは日本語ドキュメントを参照してください。

View テンプレートの編集

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

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通り紹介しました。詳しくは日本語ドキュメントを参照してください。
ここまでできたら、実際に削除ボタンを押してみて、対象レコードの deleted_at カラムに削除日が入り、論理削除になるかどうかを確認してください。

今回は短いですが以上です。次回は、記事一覧画面を実装していきます。

参考資料

Laravel 日本語ドキュメント

プログラムソース(github)