The Complete Guide to Soft Deletes in Laravel Livewire CRUD

The Complete Guide to Soft Deletes in Laravel Livewire CRUD

Setting up Soft Deletes in Laravel Livewire requires a specific sequence: updating the database schema, configuring the Eloquent model, and then handling the logic in your Livewire component.

Here is the complete, step-by-step implementation.


Step 1: Create the Migration

You need to add a deleted_at column to your database table. Run the following command in your terminal:

Bash

php artisan make:migration add_soft_deletes_to_posts_table --table=posts

Open the newly created migration file in database/migrations/ and add the softDeletes() helper:

PHP

public function up(): void
{
    Schema::table('posts', function (Blueprint $table) {
        $table->softDeletes(); // This creates the 'deleted_at' column
    });
}

public function down(): void
{
    Schema::table('posts', function (Blueprint $table) {
        $table->dropSoftDeletes(); // This removes it if rolled back
    });
}

Run the migration:

Bash

php artisan migrate

Step 2: Update the Eloquent Model

Your model must use the SoftDeletes trait so Laravel knows to intercept the delete command and update the timestamp instead of removing the row.

File: app/Models/Post.php

PHP

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes; // 1. Import the trait

class Post extends Model
{
    use SoftDeletes; // 2. Use the trait inside the class

    protected $fillable = ['title', 'content'];
}

Step 3: The Livewire Component Logic

In your Livewire component, you need methods to handle the three states: Soft Delete, Restore, and Force Delete.

File: app/Livewire/PostTable.php

PHP

namespace App\Livewire;

use Livewire\Component;
use App\Models\Post;

class PostTable extends Component
{
    // Standard Soft Delete
    public function deletePost($id)
    {
        Post::findOrFail($id)->delete();
        session()->flash('message', 'Post moved to trash.');
    }

    // Restore a Soft Deleted Post
    public function restorePost($id)
    {
        Post::withTrashed()->findOrFail($id)->restore();
        session()->flash('message', 'Post restored successfully.');
    }

    // Permanently Remove from Database
    public function forceDeletePost($id)
    {
        Post::withTrashed()->findOrFail($id)->forceDelete();
        session()->flash('message', 'Post permanently deleted.');
    }

    public function render()
    {
        return view('livewire.post-table', [
            // Using withTrashed() allows you to see both active and deleted items
            'posts' => Post::withTrashed()->latest()->get(),
        ]);
    }
}

Step 4: The Blade Template

You can use the $post->trashed() method to check if a record is soft-deleted and change the UI buttons accordingly.

File: resources/views/livewire/post-table.blade.php

HTML

<div>
    @if (session()->has('message'))
        <div class="alert alert-success">{{ session('message') }}</div>
    @endif

    <table class="table">
        <thead>
            <tr>
                <th>Title</th>
                <th>Status</th>
                <th>Actions</th>
            </tr>
        </thead>
        <tbody>
            @foreach($posts as $post)
            <tr class="{{ $post->trashed() ? 'table-secondary' : '' }}">
                <td>{{ $post->title }}</td>
                <td>
                    {{ $post->trashed() ? 'In Trash' : 'Active' }}
                </td>
                <td>
                    @if($post->trashed())
                        <button wire:click="restorePost({{ $post->id }})" class="btn btn-sm btn-success">Restore</button>
                        <button wire:click="forceDeletePost({{ $post->id }})" 
                                onclick="confirm('Are you sure? This cannot be undone!') || event.stopImmediatePropagation()" 
                                class="btn btn-sm btn-danger">Permanent Delete</button>
                    @else
                        <button wire:click="deletePost({{ $post->id }})" class="btn btn-sm btn-warning">Trash</button>
                    @endif
                </td>
            </tr>
            @endforeach
        </tbody>
    </table>
</div>

Summary of Commands

ActionEloquent Method
Soft Delete$model->delete();
Find including deletedModel::withTrashed()->find($id);
Find only deletedModel::onlyTrashed()->get();
Restore$model->restore();
Permanent Delete$model->forceDelete();


Leave a Reply

Your email address will not be published. Required fields are marked *