How to Create a Trash Can using Soft Delete - Laravel, PHP, MySQL

How to Create a Trash Can using Laravel Soft Delete – PHP, MySQL

0
(0)

Laravel soft deletes allow you to enable some models that will not be permanently deleted by just calling the delete() method. Instead, you need to call the forceDelete() method in order to permanently delete the data.

The deleted models will not be fetched from Eloquent or Query Builder queries. Instead, you need to call a separate function in order to fetch the records along with deleted ones, we will get on that later in this article. Soft deleting has several advantages:

  • First, it works like your PC’s recycle bin. If you accidentally deleted from record from your admin panel, it will not be deleted permanently at once.
  • Second, you can display all deleted data in a separate page.
  • You have backup of your deleted data, so in future if you need some old data, you can always get it from recycle bin or trash can.
  • You can display all data to the user and highlight the data that is deleted.
  • You can always restore the accidentally deleted records.

Let’s get started

For the sake of this article, we will be implementing a trash can in our user’s model.

1. Creating a column in users table

First, you need to run the following command to create a migration for soft deleting:

php artisan make:migration add_column_soft_delete_in_users_table

Then you need to open your migration file and add the following line in the Schema::table function inside up() method:

$table->softDeletes();

Then you need to run the migration using the following command:

php artisan migrate

Open your phpMyAdmin and you will see a new column at the end of the users table named deleted_at. Its default value will be NULL and it will have a current date & time value once you call the delete() method.

2. Setting Model as Soft Delete

Open your user model usually in App\Models\User.php and update it as the following:

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

class User extends Authenticatable
{
    use HasFactory, Notifiable, SoftDeletes;

    ///////////
}

After that, whenever you call the delete() method on any user object, you will see that deleted_at the field will be updated to the current date & time of that user.

3. Display all Users with Pagination

Let’s say that you have an admin panel. We will be displaying all users (non-deleted) on one page. So first create a route for this in your routes/web.php file:

use App\Http\Controllers\UserController;

Route::group([
    "prefix" => "users"
], function () {
    Route::get("/", [UserController::class, "index"]);

    // [other routes goes here]
});

We have created a group because we will be adding more routes to it. For example, route to delete a user, route to display all deleted users, route to restore a user, and route to permanently delete a user. Run the following command if you do not have the UserController:

php artisan make:controller UserController

Now, create an index() method in your UserController class. Following is what your UserController should look like:

use App\Models\User;

public function index()
{
    $users = User::orderBy("id", "desc")->paginate();
    $trashed = User::onlyTrashed()->count();

    return view("users/index", [
        "users" => $users,
        "trashed" => $trashed
    ]);
}

Create a folder named users and inside this folder, create a file in resources/views/users/index.blade.php. This file should have the following code:

<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.4.1/dist/css/bootstrap.min.css" />
<script src="https://code.jquery.com/jquery-3.4.1.slim.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@4.4.1/dist/js/bootstrap.min.js"></script>

<a href="{{ url('/users/trashed') }}">
    Trash ({{ $trashed }})
</a>

<table class="table table-bordered">
    <thead>
        <tr>
            <th>ID</th>
            <th>Name</th>
            <th>Email</th>
        </tr>
    </thead>

    <tbody>
        @foreach ($users as $user)
            <tr>
                <td>{{ $user->id }}</td>
                <td>{{ $user->name }}</td>
                <td>{{ $user->email }}</td>
            </tr>
        @endforeach
    </tbody>
</table>

{{ $users->appends(request()->except("page"))->links() }}

Refresh the page now and you will see a list of all users. Now we need to create a button to delete a user.

4. Delete a User

To delete a user, we will first a heading in our <thead> tag:

<th>Actions</th>

Then in <tbody>, we need to create a form which when submit will first ask for confirmation. If confirmed, then it will mark the user as deleted.

<td>
	<form method="POST" action="{{ url('/users/delete') }}" onsubmit="return confirm('Are you sure you want to delete this user ?');">
		{{ csrf_field() }}
		<input type="hidden" name="id" value="{{ $user->id }}" required>
		<button type="submit" class="btn btn-danger">
			Delete
		</button>
	</form>
</td>

Refresh the page and you will see a delete button along with each user. Then create a route on your web.php file:

Route::post("/delete", [UserController::class, "destroy"]);

The above lines go in the [other routes goes here] section of web.php. Then create a method in your UserController to mark the user as deleted:

public function destroy()
{
    $user = User::find(request()->id);
    if ($user == null)
    {
        abort(404);
    }

    $user->delete();
    return redirect()->back();
}

You can delete the user in one line too, like this: User::destroy(request()->id); but fetching the user first has some advantages:

  • You can perform any other sub-functions before deleting a user.
  • You can check if the user exists or not, and display the proper messages accordingly.

Try deleting a user now, you will see that will no longer be displayed in your Bootstrap table. But you can still see the record in your database using phpMyAdmin. However, you will notice that the deleted_at the field is updated and now has the UTC date and time value when the delete operation was performed.

5. Show All Deleted Users

At 3rd step, we create an anchor tag that displays all the trashed user’s counts. Now is the time to create a route for it. To create a route on your routes/web file.

Route::get("/trashed", [UserController::class, "trashed_users"]);

Then create the following method in your UserController:

public function trashed_users()
{
    $trashed = User::onlyTrashed()->orderBy("id", "desc")->paginate();

    return view("users/trashed", [
        "trashed" => $trashed
    ]);
}

After that, create a file resources/views/users/trashed.blade.php. It will have the following code:

<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.4.1/dist/css/bootstrap.min.css" />
<script src="https://code.jquery.com/jquery-3.4.1.slim.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@4.4.1/dist/js/bootstrap.min.js"></script>

<table class="table table-bordered">
    <thead>
        <tr>
            <th>ID</th>
            <th>Name</th>
            <th>Email</th>
            <th>Deleted at</th>
            <th>Actions</th>
        </tr>
    </thead>

    <tbody>
        @foreach ($trashed as $user)
            <tr>
                <td>{{ $user->id }}</td>
                <td>{{ $user->name }}</td>
                <td>{{ $user->email }}</td>
                <td>{{ $user->deleted_at }}</td>
            </tr>
        @endforeach
    </tbody>
</table>

{{ $trashed->appends(request()->except("page"))->links() }}

Refresh the page now and you will see all deleted users in a table. You will also be able to view the date and time when they were deleted.

6. Restore the Deleted Records

First, create another <td> tag at the end of <tbody> tag. In this table cell, we will create a button that will ask for confirmation. And when confirmed, will restore the user.

<td>
    <form method="POST"
        action="{{ url('/users/restore') }}"
        onsubmit="return confirm('Are you sure you want to restore this user ?');">

        {{ csrf_field() }}

        <input type="hidden" name="id" value="{{ $user->id }}" required />
        <button type="submit" class="btn btn-success">
            Restore
        </button>
    </form>
</td>

Then create a route in your web/routes.php that will handle this request.

Route::post("/restore", [UserController::class, "do_restore"]);

After that, create the following method in your UserController:

public function do_restore()
{
    $user = User::withTrashed()->find(request()->id);
    if ($user == null)
    {
        abort(404);
    }

    $user->restore();
    return redirect()->back();
}

Refresh the page now and you will see a “Restore” button along with each delete user. On clicking that, you will be asked for confirmation. If confirmed, you will no longer see that record in the trash can. But you will start seeing that record in all users table.

If you open your database using phpMyAdmin, you will see that user will again have the deleted_at column value as NULL.

7. Permanently Delete Records

Where you are displaying all soft-deleted records in your trash can, you are already displaying a button to restore the record. Now is the time to display another button that will permanently delete the record from the database. Create a button along with the “Restore” button in your trash can:

<form method="POST"
    action="{{ url('/users/delete-permanently') }}"
    onsubmit="return confirm('Are you sure you want to permanently delete this user ?');">

    {{ csrf_field() }}

    <input type="hidden" name="id" value="{{ $user->id }}" required />
    <button type="submit" class="btn btn-danger">
        Delete
    </button>
</form>

Then, you need to create a route that will handle this request.

Route::post("/delete-permanently", [UserController::class, "delete_permanently"]);

Then you need to create a method in your UserController that will permanently delete that record from the database.

public function delete_permanently()
{
    $user = User::withTrashed()->find(request()->id);
    if ($user == null)
    {
        abort(404);
    }

    $user->forceDelete();
    return redirect()->back();
}

Refresh the page now and click on the delete button from the trash can. You will be asked for confirmation. Once confirmed, you will no longer see that record in the trash can nor in all users table. If you check the database, you will see that, that user’s row has been permanently deleted from the database.

Kindly login or create a new account to download the files.

How useful was this post

Click on a star to rate it!

Average rating 0 / 5. Vote count: 0

No votes so far! Be the first to rate this post.

As you found this post useful...

Follow us on social media!

We are sorry that this post was not useful for you!

Let us improve this post!

Tell us how we can improve this post





Please disable your adblocker or whitelist this site!