Reputation: 29
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
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
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