Laravelでデータ復活できる「ゴミ箱」機能をつくる

こんにちは❗フリーランス・エンジニアの 九保すこひ です。

さてさて、数日前Togetterでこのページが話題になっているのを発見しました。

ぼく「嫌な予感がするから警告いっぱい出したれ」データ削除は三重確認設計に→??「なんかデータ消えたんですけど?」

開発者にとっては「あるある」ネタだと思うのですが、この中で衝撃だったのは、「削除したらほんとに消えたんですけど?」の部分です😂

(うーん、逆に削除できなくても苦情になりますし・・・💦)

そして、この投稿者さんもおっしゃっているとおり論理削除(ソフトデリート)というのはとても重要なんだな、と再認識しました。

※ソフトデリートとは、実際にデータは削除せず「削除したものとする」というテクニックです。Laravelではdeleted_atで判別をします。

そこで!

今回は、間違ってデータ削除しても復活できるように、「ゴミ箱」ページをLaravelで作ってみることにしました。

ぜひ皆さんのお役に立てると嬉しいです😊✨

開発環境: Laravel 7.x

やりたいこと

テストとして以下2つのテーブルを用意し、ソフトデリートされたデータを復活させる「ゴミ箱」ページをつくります。

  • posts
  • products

※今回は2つですが、応用すればいくつでも復活ができるようになります。

では、実際にやってみましょう!

ソフトデリート設定する

ソフトデリートを設定する方法は、Laravel・データベースのデータ操作をご覧ください。

また、データベースは次のような形で用意してください。

データ復活する「ゴミ箱」ページをつくる

ルートをつくる

/routes/web.php

Route::get('/trash_box', 'TrashBoxController@index');
Route::get('/trash_box/restore/{table}/{id}', 'TrashBoxController@restore')->name('trash_box.restore');

内容としては上の行が「ゴミ箱」ページで、ここで削除済データをリスト表示します。そして、下の行が実際にデータを復活させるルートです。

コントローラーをつくる

次のコマンドで専用のコントローラーをつくりましょう。

php artisan make:controller TrashBoxController

そして中身を変更してください。

/app/Http/Controllers/TrashBoxController.php

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class TrashBoxController extends Controller
{
    public function index() { // 一覧ページ ・・・ ①

        $query_1 = \DB::table('posts')
            ->select(
                'id',
                \DB::raw("title as label"),
                \DB::raw("'posts' as table_name"),
                'deleted_at'
            )
            ->whereNotNull('deleted_at');
        $query_2 = \DB::table('products')
            ->select(
                'id',
                \DB::raw("name as label"),
                \DB::raw("'products' as table_name"),
                'deleted_at'
            )
            ->whereNotNull('deleted_at');
        $trash_boxes = $query_2->union($query_1)
            ->orderBy('deleted_at', 'desc')
            ->orderBy('id', 'desc')
            ->paginate();
        return view('trash_box')->with('trash_boxes', $trash_boxes);

    }

    public function restore($table, $id) { // データ復活 ・・・ ②

        \DB::table($table)->where('id', $id)->update([
            'deleted_at' => null
        ]);
        return back();

    }
}

ここは少し複雑なのでひとつずつ紹介していきます。

① 一覧ページ

削除されたデータを取得するのですが、取得するテーブルは「posts」と「products」の2つです。

そのため、union()を使って一気にデータ取得するわけですが、その際に気をつけないといけないのが「フィールド名を合わせる」ということです。

つまり、2つのテーブルのフィールド名は一致していないため、asを使って同じフィールド名を指定しているわけです。

最終的に取得するフィールドは、

  • id ・・・ ここは共通
  • label ・・・ 「products.name」か「posts.title」の内容
  • table_name ・・・ テーブル名「posts」か「products」
  • deleted_at ・・・ ここも共通

の4つになります。

② データ復活

テーブル名とIDでデータを特定し、deleted_atnullに更新します。
Laravelでは、deleted_atに日付が入っていれば削除されたものとみなされます)

ビューをつくる

最後にindex()で使うビューをつくります。

/resources/views/trash_box.blade.php

<html>
<head>
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css">
</head>
<body>
    <div class="p-5">
        <table class="table">
            <thead class="bg-light">
                <tr>
                    <th>ID</th>
                    <th>テーブル</th>
                    <th>ラベル</th>
                    <th></th>
                </tr>
            </thead>
            @foreach($trash_boxes as $trash_box)
            <tbody>
                <tr>
                    <td>{{ $trash_box->id }}</td>
                    <td><span class="badge badge-light">{{ $trash_box->table_name }}</span></td>
                    <td>{{ $trash_box->label }}</td>
                    <td class="text-right">
                        <a href="{{ route('trash_box.restore', [$trash_box->table_name, $trash_box->id]) }}" class="btn btn-secondary" type="button">元に戻す</a>
                    </td>
                </tr>
            </tbody>
            @endforeach
        </table>
        {{ $trash_boxes->links() }}
    </div>
</body>
</html>

この中では、TrashBoxControllerで取得した削除データをループさせながら一覧を作ることになります。

テストしてみる

では、テーブルpostsproductsを全てソフトデリートした状態にしてテストしてみましょう!

では、一番上のposts10番を元に戻してみます。

削除リストから消えました。

念のため、データベースも確認してみましょう。

10番のデータだけdeleted_atnullになっています。
成功です😊✨

おわりに

ということで、今回はLaravelで「ゴミ箱」機能をつくってみました。

ゴミ箱機能があれば、間違って削除しても簡単に復活させることができますし、なによりユーザー側もビクビク使わなくてよくなるので、きっと喜ばれることでしょう😊✨

また、今回は2つのテーブルだけに「ゴミ箱」機能をつくりましたが、union()する部分で3つでも4つでも追加できるのでフレキシブルに対応ができると思います。(ただし、データ数が増えると速度が遅くなるので、その場合は「ゴミ箱」専用テーブルをつくる方がいいです)

地味に便利な機能なので、ぜひ皆さんもやってみてくださいね。

ではでは〜!

この記事が役立ちましたらシェアお願いします😊✨ by 九保すこひ
また、わかりにくい部分がありましたらお問い合わせからお気軽にご連絡ください。
(また、個人レッスンも承ってます👍)
このエントリーをはてなブックマークに追加       follow us in feedly