Revisionable
Easily create a revision history for any laravel model
Install / Use
/learn @VentureCraft/RevisionableREADME
Wouldn't it be nice to have a revision history for any model in your project, without having to do any work for it. By simply adding the RevisionableTrait Trait to your model, you can instantly have just that, and be able to display a history similar to this:
- Chris changed title from 'Something' to 'Something else'
- Chris changed category from 'News' to 'Breaking news'
- Matt changed category from 'Breaking news' to 'News'
So not only can you see a history of what happened, but who did what, so there's accountability.
Revisionable is a laravel package that allows you to keep a revision history for your models without thinking. For some background and info, see this article
Working with 3rd party Auth / Eloquent extensions
Revisionable has support for Auth powered by
(Recommended) Revisionable can also now be used as a Trait, so your models can continue to extend Eloquent, or any other class that extends Eloquent (like Ardent).
Installation
Revisionable is installable via composer, the details are on packagist, here.
Add the following to the require section of your projects composer.json file:
"venturecraft/revisionable": "1.*",
Run composer update to download the package
php composer.phar update
Open config/app.php and register the required service provider (Laravel 5.x)
'providers' => [
Venturecraft\Revisionable\RevisionableServiceProvider::class,
]
Publish the configuration and migrations (Laravel 5.x)
php artisan vendor:publish --provider="Venturecraft\Revisionable\RevisionableServiceProvider"
Finally, you'll also need to run migration on the package (Laravel 5.x)
php artisan migrate
For Laravel 4.x users:
php artisan migrate --package=venturecraft/revisionable
If you're going to be migrating up and down completely a lot (using
migrate:refresh), one thing you can do instead is to copy the migration file from the package to yourapp/databasefolder, and change the classname fromCreateRevisionsTableto something likeCreateRevisionTable(without the 's', otherwise you'll get an error saying there's a duplicate class)
cp vendor/venturecraft/revisionable/src/migrations/2013_04_09_062329_create_revisions_table.php database/migrations/
Docs
- Implementation
- More control
- Format output
- Load revision history
- Display history
- Contributing
- Having troubles?
<a name="intro"></a>
Implementation
The new, Trait based implementation (recommended)
Traits require PHP >= 5.4
For any model that you want to keep a revision history for, include the VentureCraft\Revisionable namespace and use the RevisionableTrait in your model, e.g.,
namespace App;
use \Venturecraft\Revisionable\RevisionableTrait;
class Article extends \Illuminate\Database\Eloquent\Model {
use RevisionableTrait;
}
Being a trait, Revisionable can now be used with the standard Eloquent model, or any class that extends Eloquent, such as Ardent.
Legacy class based implementation
The new trait based approach is backwards compatible with existing installations of Revisionable. You can still use the below installation instructions, which essentially is extending a wrapper for the trait.
For any model that you want to keep a revision history for, include the VentureCraft\Revisionable namespace and use the RevisionableTrait in your model, e.g.,
use Venturecraft\Revisionable\Revisionable;
namespace App;
class Article extends Revisionable { }
Note: This also works with namespaced models.
Implementation notes
If needed, you can disable the revisioning by setting $revisionEnabled to false in your Model. This can be handy if you want to temporarily disable revisioning, or if you want to create your own base Model that extends Revisionable, which all of your models extend, but you want to turn Revisionable off for certain models.
namespace App;
use \Venturecraft\Revisionable\RevisionableTrait;
class Article extends \Illuminate\Database\Eloquent\Model {
protected $revisionEnabled = false;
}
You can also disable revisioning after X many revisions have been made by setting $historyLimit to the number of revisions you want to keep before stopping revisions.
namespace App;
use \Venturecraft\Revisionable\RevisionableTrait;
class Article extends \Illuminate\Database\Eloquent\Model {
protected $revisionEnabled = true;
protected $historyLimit = 500; //Stop tracking revisions after 500 changes have been made.
}
In order to maintain a limit on history, but instead of stopping tracking revisions if you want to remove old revisions, you can accommodate that feature by setting $revisionCleanup.
namespace App;
use \Venturecraft\Revisionable\RevisionableTrait;
class Article extends \Illuminate\Database\Eloquent\Model {
protected $revisionEnabled = true;
protected $revisionCleanup = true; //Remove old revisions (works only when used with $historyLimit)
protected $historyLimit = 500; //Maintain a maximum of 500 changes at any point of time, while cleaning up old revisions.
}
Storing Soft Deletes
By default, if your model supports soft deletes, Revisionable will store this and any restores as updates on the model.
You can choose to ignore deletes and restores by adding deleted_at to your $dontKeepRevisionOf array.
To better format the output for deleted_at entries, you can use the isEmpty formatter (see <a href="#format-output">Format output</a> for an example of this.)
<a name="control"></a>
Storing Force Delete
By default the Force Delete of a model is not stored as a revision.
If you want to store the Force Delete as a revision you can override this behavior by setting revisionForceDeleteEnabled to true by adding the following to your model:
protected $revisionForceDeleteEnabled = true;
In which case, the created_at field will be stored as a key with the oldValue() value equal to the model creation date and the newValue() value equal to null.
Attention! Turn on this setting carefully! Since the model saved in the revision, now does not exist, so you will not be able to get its object or its relations.
Storing Creations
By default the creation of a new model is not stored as a revision. Only subsequent changes to a model is stored.
If you want to store the creation as a revision you can override this behavior by setting revisionCreationsEnabled to true by adding the following to your model:
protected $revisionCreationsEnabled = true;
More Control
No doubt, there'll be cases where you don't want to store a revision history only for certain fields of the model, this is supported in two different ways. In your model you can either specifiy which fields you explicitly want to track and all other fields are ignored:
protected $keepRevisionOf = ['title'];
Or, you can specify which fields you explicitly don't want to track. All other fields will be tracked.
protected $dontKeepRevisionOf = ['category_id'];
The
$keepRevisionOfsetting takes precedence over$dontKeepRevisionOf
Storing additional fields in revisions
In some cases, you'll want additional metadata from the models in each revision. An example of this might be if you have to keep track of accounts as well as users. Simply create your own new migration to add the fields you'd like to your revision model, add them to your config/revisionable.php in an array like so:
'additional_fields' => ['account_id', 'permissions_id', 'other_id'],
If the column exists in the model, it will be included in the revision.
Make sure that if you can't guarantee the column in every model, you make that column nullable() in your migrations.
Events
Every time a model revision is created an event is fired. You can listen for revisionable.created,
revisionable.saved or revisionable.deleted.
// app/Providers/EventServiceProvider.php
public function boot()
{
parent::boot();
$events->listen('revisionable.*', function($model, $revisions) {
// Do something with the revisions or the changed model.
dd($model, $revisions);
});
}
<a name="formatoutput"></a>
Format output
You can continue (and are encouraged to) use
Eloquent accessorsin your model to set the output of your values, see the Laravel Documentation for more information on accessors The below documentation is therefor deprecated
In cases where you want to have control over the format of the output of the values, for example a boolean field, you can set them in the $revisionFormattedFields array in your model. e.g.,
protected $revisionFormattedFields = [
'title
