Implementing Soft Deletes in Laravel for Data Recovery and Auditing

Implementing Soft Deletes in Laravel for Data Recovery and Auditing

Soft deletes are a powerful feature in Laravel that allow you to "delete" records without actually removing them from your database. This approach is invaluable for maintaining data integrity, enabling easy recovery, and meeting auditing or compliance requirements. Let's explore how to implement and leverage soft deletes effectively in your Laravel applications.

Enabling Soft Deletes

To use soft deletes, first add the deleted_at column to your table migration:

Schema::table('posts', function (Blueprint $table) {
    $table->softDeletes();
});

Then, use the SoftDeletes trait in your model:

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

class Post extends Model
{
    use SoftDeletes;
}

Basic Usage

To soft delete a record:

$post->delete();

To restore a soft-deleted record:

$post->restore();

Querying Soft Deleted Records

Soft deleted records are automatically excluded from query results. To include them:

$posts = Post::withTrashed()->get();

To retrieve only soft deleted records:

$posts = Post::onlyTrashed()->get();

Permanently Deleting Records

To permanently remove a soft deleted record:

$post->forceDelete();

Cascading Soft Deletes

For related models, you might want to cascade soft deletes:

class Post extends Model
{
    use SoftDeletes;

    protected $cascadeDeletes = ['comments'];

    public function comments()
    {
        return $this->hasMany(Comment::class);
    }
}

Implement the cascading logic in your model's boot method:

protected static function boot()
{
    parent::boot();

    static::deleting(function($post) {
        $post->comments()->delete();
    });

    static::restoring(function($post) {
        $post->comments()->restore();
    });
}

Global Scopes

Laravel automatically applies a global scope to exclude soft deleted records. You can remove this scope if needed:

protected static function booted()
{
    static::addGlobalScope('withTrashed', function (Builder $builder) {
        $builder->withTrashed();
    });
}

Soft Deletes with Relationships

When working with relationships, you might want to include or exclude soft deleted records:

// Include soft deleted comments
$post->comments()->withTrashed()->get();

// Get only soft deleted comments
$post->comments()->onlyTrashed()->get();

Checking Deletion Status

To check if a model instance is soft deleted:

if ($post->trashed()) {
    // This post has been soft deleted
}

When restoring a parent model, you might want to restore related models as well:

class Post extends Model
{
    use SoftDeletes;

    public function restore()
    {
        $this->comments()->restore();
        return parent::restore();
    }
}

Soft Deletes for Auditing

Soft deletes are excellent for auditing purposes. You can track when a record was "deleted":

$deletedAt = $post->deleted_at;

You can also use this for time-based clean-up of old soft-deleted records:

// Delete posts soft-deleted more than a year ago
Post::onlyTrashed()
    ->where('deleted_at', '<', now()->subYear())
    ->forceDelete();

Performance Considerations

While soft deletes are powerful, they can impact query performance, especially on large tables. Consider using indexes on the deleted_at column:

Schema::table('posts', function (Blueprint $table) {
    $table->index('deleted_at');
});

Soft deletes in Laravel provide a robust way to implement data recovery and maintain a complete audit trail of your application's data. By leveraging this feature, you can enhance your application's data integrity, provide undo functionality, and meet various compliance requirements.

If this guide was helpful to you, subscribe to my daily newsletter and give me a follow on X/Twitter. It helps a lot!

Subscribe to Harris Raftopoulos

Don’t miss out on the latest issues. Sign up now to get access to the library of members-only issues.
jamie@example.com
Subscribe