A package to automatically copy deleted records to a separate table
We've released a new package called spatie/laravel-deleted-models. When deleting a model, this package will copy over its attributes to a table called deleted_models
.
You can view this package as a "Recycle bin for models".
In this post, I'd like to tell you all about it.
Using the package
Installing the package is just a simple composer install away.
composer require spatie/laravel-deleted-models
After that, you should publish and run migrations to create deleted_models
table.
php artisan vendor:publish --tag="deleted-models-migrations"
php artisan migrate
With the package installed, you should use the KeepsDeletedModels
trait on every Eloquent model where you want to keep the attributes when the model is deleted.
use Illuminate\Database\Eloquent\Model;
use Spatie\DeletedModels\Models\Concerns\KeepsDeletedModels;
class BlogPost extends Model
{
use KeepsDeletedModels;
}
When you call delete on a model, its attributes will be copied to deleted_models
.
$blogPost = BlogPost::find($id);
// values will be copied to the `deleted_models` table
$blogPost->delete();
To restore a deleted model, you can call restore
and pass in the id
.
// $blogPost will be restored and returned
$blogPost = Blogpost::restore($id);
You can also restore the model in memory without saving it yet in the database, allowing you to make changes before saving it.
// the `$blogPost` isn't saved yet
$blogPost = BlogPost::makeRestored($id);
// make some modifications to the blog post
// ...
$blogPost->save();
The package has more features, and the entire deleting / restoring process can be customized. Head to the documentation on GitHub to learn more.
The trade-offs compared with soft deletes
In the Laravel ecosystem, there's another popular method of keeping deleted records: soft deleting. When using soft deletes, you add a deleted_at
column to each table. When that column has a value, it should be considered deleted, and you should take care that you don't select these records when performing queries in the regular operation of your app.
The big pro for soft deletes is that it's very convenient. No data needs to be copied when deleting a model. Also, when performing migrations on a table that uses soft deletes, these "deleted" records will be updated.
But there are also some significant downsides. You must always keep soft deletes in mind whenever you perform a query via Eloquent, or when performing a query directly on your database. It's very easy to forget a where clause to omit those soft deleted records.
When using soft deletes, you also lose the benefits of your database enforcing referential integrity. Put otherwise, if you soft delete a record that other records point to via a foreign key, you have to manually update those records to be soft deleted as well. With soft deletes, your database can't enforce referential integrity.
Definitely purging data from all tables that have soft deleted records involves monitoring and performing delete queries for all those tables. One simple query is usually not enough to remove all old soft-deleted data.
To undelete a soft deleted record, could be as simple as setting the deleted_at
to null. In many cases, more is needed. You also have to undelete all related records, and the original deletion might have triggered side effects outside your database that you'd need to revert. In many cases, an undelete will encompass more than just updating the deleted_at
.
Using a separate deleted_models
table solves some, but not all, of these problems described above, but not all. It's simply another set of trade-offs. Using a deleted_models
for deleted models will:
- not require you to adapt your queries. You can just select stuff from the original table without the need for an extra
where deleted_at = null
- allow your database to still protect the referential integrity of your database. Deleting a record will delete all related records as well.
- make it easy to permanently delete all old data. It's just performing one deletion query one the
deleted_models
table withwhere data_created < <your-treshold-date>
. - make it harder to restore deleted data as you need to copy stuff back in (versus just setting
deleted_at
tonull
when using soft deletes)
In closing
Our spatie/laravel-deleted-models package makes it easy to copy all deleted records to one table. It's an alternative strategy for soft deletes.
Both strategies have their unique pros and cons. Make up your mind about which of the two solutions offers the best trade-offs for your project.
This package and blog post were inspired by these two blog posts:
This package isn't the first Spatie package. Please look at this extensive list of Laravel and PHP packages we've made before. I'm sure there's something there for your next project. If you want to support our open-source efforts, consider picking up one of our paid products or subscribe at Mailcoach and/or Flare.
In case of data recovery, having a backup of deleted records available will significantly reduce the time. slope game