donahoed
donahoed

Reputation: 29

Soft delete eloquent model on save

I have an Eloquent model and want to track every change that is made it over time. I have soft deletes enabled on the model and that part works fine.

When I want to save the model, I clone it, delete the original model and save the clone. This way I can see every change to the model over time.

What I'd like to do, is have logic built into the model itself that mimics this behavior when calling a plain model->save().

Is this possible to do?

Upvotes: 2

Views: 1812

Answers (2)

andrewtweber
andrewtweber

Reputation: 25509

I like Josh's answer, especially the isDirty check. One major change I would suggest is to create a separate database table and separate model. Name the table with a _revisions suffix and then you can even have a relationship to easily fetch revisions for that model.

For example, if your entity was called Post, then the post_revisions table should be identical except with an additional post_id column which references the original model.

class PostRevision {
    protected $table = 'post_revisions';

    public function post() {
        return $this->belongsTo(Post::class);
    }
}

class Post {
    protected $table = 'posts';

    public function revisions() {
        return $this->hasMany(PostRevision::class);
    }
}

Now your posts table is not cluttered up with junk revisions

Upvotes: 1

Josh
Josh

Reputation: 8149

You could use events to do this, sure. On your model, something like:

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

    self::saving(function (Model $model) {
        if ($model->isDirty()) {
            // clone the $model here
        }
    });

    self::saved(function (Model $model) {
        if ($model->isDirty()) {
            // delete the model here
        }
    });
}

You'll notice I use both the saving and saved events. I did this purposefully so that you can clone the model before its data is updated (either by re-retrieving the model from the database or using the original data stored within the model) and then the model is not deleted until it also is updated and saved to the database, giving you the pattern it seems you are trying to achieve.

For the record, though, I dislike this style of versioning. How do you know if a record was actually deleted or is just a historical item? It's also difficult to account for changes in relationships using this method. I'd prefer a log style (where you save a serialized list of what values were changed and transform that as needed). This would result in less data in the database itself (since you would ideally only saved the columns that were changed), a more clearly defined data structure, and all of your logged updates in a central table that is managed by a polymorphic relationship.

If you want to do it your way, I think the better route is to clone your model and delete the clone. This way would be less disruptive to the user, I think, since IDs and the like would not be continuously changing and possibly be out-of-date for other users. Regardless, I would prefer to do a serialized list.

Upvotes: 1

Related Questions