Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Laravel revisionable models with one-to-many relationship

Is it possible for revisionable to track changes to one-to-many relationships? For example:

Model: User. Model: Posts. User model uses Venturecraft\Revisionable\RevisionableTrait; and have a hasMany relationship to Posts. If a post is added or updated, can this be tracked by revisionable under the User which the post belongs to?

Thanks in advance

like image 914
user1209325 Avatar asked Nov 27 '14 14:11

user1209325


2 Answers

I was able to come up with something. However it's not the most elegant solution, so it'd be great if somebody would help me to clean this up (especially that unset is bothering me).

My solution will create duplicates in the table the Model belongs to. I don't know if this is what you wanted

The first thing you need to do is to add a nullable datetime revision_at column in the appropriate table.

The trait itself is pretty simple. We make use of the models boot() method to register the models updating event. It will fire whenever a model is about to update. That's exactly what we need, since we don't want a revision the first time we are creating the model.

<?php

trait RevisionableTrait {

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

        static::updating(function( $model ){

            // Grab the original Model and unset the id
            // from it, so that we don't get duplicate
            // entries when we create a new model.

            $attributes = $model->getOriginal();
            unset( $attributes['id'] );

            // Next we need to add the date the revision 
            // was created
            $attributes['revision_at'] = new DateTime();


            $revision = new static($attributes);
            $revision->save();

        });


    }

}

The only thing we do here is to grab the original model before the new fields were assigned, unset the id to make sure we don't create a duplicate entry, set the current time for the revision_at field and save the model.

That's it basically.

can this be tracked by revisionable under the User which the post belongs to?

This is automatically done since the new revision model still belongs to the respective user,

If you want to fine-tune it you could create a dedicated table for revisions where a reference to the model is stored. However storing the properties might get a little bit harder (Maybe you could store them serialized).

Another possible improvement would be to modify the getter methods of the model in the trait. For example let all() only return models that are no revisions. Then add a withRevisions() method to grab them too. You can extract the logic from it if you take a look how Laravel handles Soft Deletes. It's exactly the same.

like image 99
thpl Avatar answered Nov 15 '22 08:11

thpl


why not use this?

$user = User::first();
$user->posts->map(function($post) {
    return $post->revisionHistory;
});
like image 32
Arif Ikhsanudin Avatar answered Nov 15 '22 09:11

Arif Ikhsanudin