Coder Social home page Coder Social logo

revisionable's Introduction

Revisionable for Laravel

Latest Version Downloads License

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 your app/database folder, and change the classname from CreateRevisionsTable to something like CreateRevisionTable (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

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 Format output for an example of this.)

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 $keepRevisionOf setting 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);
    });
}

Format output

You can continue (and are encouraged to) use Eloquent accessors in 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'      => 'string:<strong>%s</strong>',
    'public'     => 'boolean:No|Yes',
    'modified'   => 'datetime:m/d/Y g:i A',
    'deleted_at' => 'isEmpty:Active|Deleted'
];

You can also override the field name output using the $revisionFormattedFieldNames array in your model, e.g.,

protected $revisionFormattedFieldNames = [
    'title'      => 'Title',
    'small_name' => 'Nickname',
    'deleted_at' => 'Deleted At'
];

This comes into play when you output the revision field name using $revision->fieldName()

String

To format a string, simply prefix the value with string: and be sure to include %s (this is where the actual value will appear in the formatted response), e.g.,

string:<strong>%s</strong>

Boolean

Booleans by default will display as a 0 or a 1, which is pretty bland and won't mean much to the end user, so this formatter can be used to output something a bit nicer. Prefix the value with boolean: and then add your false and true options separated by a pipe, e.g.,

boolean:No|Yes

Options

Analogous to "boolean", only any text or numeric values can act as a source value (often flags are stored in the database). The format allows you to specify different outputs depending on the value. Look at this as an associative array in which the key is separated from the value by a dot. Array elements are separated by a vertical line.

options:search.On the search|network.In networks

DateTime

DateTime by default will display as Y-m-d H:i:s. Prefix the value with datetime: and then add your datetime format, e.g.,

datetime:m/d/Y g:i A

Is Empty

This piggy backs off boolean, but instead of testing for a true or false value, it checks if the value is either null or an empty string.

isEmpty:No|Yes

This can also accept %s if you'd like to output the value, something like the following will display 'Nothing' if the value is empty, or the actual value if something exists:

isEmpty:Nothing|%s

Load revision history

To load the revision history for a given model, simply call the revisionHistory method on that model, e.g.,

$article = Article::find($id);
$history = $article->revisionHistory;

Displaying history

For the most part, the revision history will hold enough information to directly output a change history, however in the cases where a foreign key is updated we need to be able to do some mapping and display something nicer than plan_id changed from 3 to 1.

To help with this, there's a few helper methods to display more insightful information, so you can display something like Chris changed plan from bronze to gold.

The above would be the result from this:

@foreach($account->revisionHistory as $history )
    <li>{{ $history->userResponsible()->first_name }} changed {{ $history->fieldName() }} from {{ $history->oldValue() }} to {{ $history->newValue() }}</li>
@endforeach

If you have enabled revisions of creations as well you can display it like this:

@foreach($resource->revisionHistory as $history)
  @if($history->key == 'created_at' && !$history->old_value)
    <li>{{ $history->userResponsible()->first_name }} created this resource at {{ $history->newValue() }}</li>
  @else
    <li>{{ $history->userResponsible()->first_name }} changed {{ $history->fieldName() }} from {{ $history->oldValue() }} to {{ $history->newValue() }}</li>
  @endif
@endforeach

userResponsible()

Returns the User that was responsible for making the revision. A user model is returned, or false if there was no user recorded.

The user model that is loaded depends on what you have set in your config/auth.php file for the model variable.

fieldName()

Returns the name of the field that was updated, if the field that was updated was a foreign key (at this stage, it simply looks to see if the field has the suffix of _id) then the text before _id is returned. e.g., if the field was plan_id, then plan would be returned.

Remember from above, that you can override the output of a field name with the $revisionFormattedFieldNames array in your model.

identifiableName()

This is used when the value (old or new) is the id of a foreign key relationship.

By default, it simply returns the ID of the model that was updated. It is up to you to override this method in your own models to return something meaningful. e.g.,

use Venturecraft\Revisionable\Revisionable;

class Article extends Revisionable
{
    public function identifiableName()
    {
        return $this->title;
    }
}

oldValue() and newValue()

Get the value of the model before or after the update. If it was a foreign key, identifiableName() is called.

Unknown or invalid foreign keys as revisions

In cases where the old or new version of a value is a foreign key that no longer exists, or indeed was null, there are two variables that you can set in your model to control the output in these situations:

protected $revisionNullString = 'nothing';
protected $revisionUnknownString = 'unknown';

disableRevisionField()

Sometimes temporarily disabling a revisionable field can come in handy, if you want to be able to save an update however don't need to keep a record of the changes.

$object->disableRevisionField('title'); // Disables title

or:

$object->disableRevisionField(['title', 'content']); // Disables title and content

Contributing

Contributions are encouraged and welcome; to keep things organised, all bugs and requests should be opened in the GitHub issues tab for the main project, at venturecraft/revisionable/issues

All pull requests should be made to the develop branch, so they can be tested before being merged into the master branch.

Having troubles?

If you're having troubles with using this package, odds on someone else has already had the same problem. Two places you can look for common answers to your problems are:

If you do prefer posting your questions to the public on StackOverflow, please use the 'revisionable' tag.

revisionable's People

Contributors

alan-smith-be avatar anarchocoder avatar argia-andreas avatar awjudd avatar dandarie avatar duellsy avatar fridzema avatar grahamcampbell avatar ivelrrat avatar laravel-shift avatar miclf avatar mmawdsleyhallnet avatar msonowal avatar paulofreitas avatar ps613 avatar rajivseelam avatar rdelorier avatar reinbier avatar rhynodesigns avatar rickmills avatar rolandsaven avatar roshangautam avatar sebastienheyd avatar seedgabo avatar sniper7kills avatar stierler avatar tabacitu avatar teaqu avatar trizz avatar vpyatnitskiy avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

revisionable's Issues

Toggle auto field naming on foreign keys

I do like the feature where it will try to find the name/label of the given foreign key ids object, but in the case where the value does not represent a foreign key but actually references something in the data called "whatever_id" (easily could have been called whatever_number, but this is the verbage the client used), how do I/can I disable that on a given field to prevent it from automatically looking for an object? Instead showing the actual Id represented?

e.g
Right now I have:
my_special_id [ code is looking for ] my_special_object

my_special_id references the name of the data in the column, not a foreign dependent object. So it needs to actually output the exact data in the column.

If this does not make sense, please let me know and I will clarify. Thanks for the great work. I really like using this tool.

Support inheriting from any other Eloquent implementation

If I'm using Ardent, which is derived from Eloquent, how could I also use Revisionable, since PHP doesn't support multiple inheritances.

Would be great if we could set the class from which Revisionable 'inherits' from or is 'created from' internally, so we could use any other implementation of Eloquent with the package.

Error: Class 'app\models\Eloquent' not found

Hi, I don't know if this is the right place for this. Kindly pardon my ignorance if so.

My problem is...I have installed the package per the instructions in my Laravel 4. I get the following error:

Class 'app\models\Eloquent' not found

when i use based on the new, trait based implementation like this:

<?php
use Illuminate\Auth\UserInterface;
 use Illuminate\Auth\Reminders\RemindableInterface;

namespace MyApp\Models;

class User extends Eloquent implements UserInterface, RemindableInterface {

use Venturecraft\Revisionable\Revisionable;
...

Please what could be the issue here?

Boolean always get an entry in history...

If I submit a form with a single string change on it, no matter what the boolean field value is set to (even if it's the same), I always gets an entry in the revisions table. See below. Am I just doing something wrong, or did I stumble across a bug? At first I thought it was a false vs. 0 issue, but even when I change the value to 0 when setting the boolean flag, I still see the result in the database as below. Thanks!!

id          revisionable_type  revisionable_id  user_id     key         old_value      new_value          created_at           updated_at         
----------  -----------------  ---------------  ----------  ----------  -------------  -----------------  -------------------  -------------------
1           Thing              1                2           name        String         Stringtest         2013-06-13 21:32:58  2013-06-13 21:32:58
2           Thing              1                2           disabled    0              0                  2013-06-13 21:32:58  2013-06-13 21:32:58
3           Thing              1                2           name        Strintgtest    String             2013-06-13 21:33:24  2013-06-13 21:33:24
4           Thing              1                2           disabled    0              0                  2013-06-13 21:33:24  2013-06-13 21:33:24

Display revision log for all

It would be great if you provided a method to output all of the revision logs for a specific model. I would like to output all revisions to a table. I can do that now with a custom query, but it would be nice to output in a way that is "Laravel" friendly :)

Get the model state by providing a revision ID

Is there any way to retrieve all the values for a model at a specified revision ? To make it simple, I would like to checkout a model on a revision (like you would checkout a repository on a commit with Git).

If it's not possible, is it planned for the v2 ?

Show complete history for all models

It's possible to load the history for a specific model using $history = $article->revisionHistory;. I'm wondering if it's also possible to load the complete history for all the records in the revisions table, independent of the model. Are there any shortcuts for this in the package?

Create tests

There's currently no tests, need to make some and setup the package to auto validate via travis-ci

Enhancement Request: Formatted Output for Fields Name

As we have the option to format the output regarding the field values, it would be a very nice idea to have the option to format the field name output.

For example, we could define something like:
protected $revisionFormattedFieldsName = array(
'title' => 'Title',
'small_name' => 'Nickname'
'deleted_at' => 'Deleted At'
);

So when we call, $history->fieldName(), instead of get 'title' it would show 'Title' and same for others...

Please, implement?
Really useful!

Thank you very much.

Robson Martins

Migrations break

You should rename the migration file, as it breaks in (at least) the latest version of the Laravel framework.

the resolve file method in Migrator.php slices the first four (date values) of the filename, causing the create_revisionstable.php migration to fail, as Laravel thinks the filname is an empty string.

'updating' is Model method

please use different flag
and i dont really see the point.
just use $this->exists

if ($this->revisionEnabled AND $this->exists) {
...

Trait please

Could we also get a Revisionable trait for those of us already extending our models?

Revisionable Pivot

maybe you can implement this like said in here:
http://forumsarchive.laravel.io/viewtopic.php?id=10935

[quote]
There is no real support for it, as there is no real pivot model.
There is though a model-like object Pivot, which you can bound a listener to, but it will fire for any pivot, not just the one you want.
It is equal to: Event::listen('eloquent.saving: Pivot', $callback).
What you could do is to test what's is the current table inside the event.

Pivot::saving(function($pivot) {
if ($pivot->getTable() == with(new ModelA)->theRelation()->getTable()) {
$pivot->hash = Hash::make(Str::random());
}
});
Where ModelA is one of the models in the relation and theRelation() is the the relation method you defined which returns the belongsToMany relation object. This way you don't have to modify the table name here if it's changed.

Edit: Btw Pivot is not an aliased class, so you can access it through the namespace: \Illuminate\Database\Eloquent\Relations\Pivot

Return a name instead of an ID

In cases where an ID was updated (e.g., foreign key), there needs to be an easy way to say the 'user' was updated, not user_id updated

Additionally, should be able to display the name of the referenced item, e.g., instead of saying that 1 changed to 2, it should allow you to say something like

User changed from Chris to Matt

Revisionable and Mutators

Hi,

one of my revisionable models has some mutators like getPriceAttribute / setPriceAttribute.

Revisionable's oldValue / newValue irgnores my getter and returns the raw price atrribute?

Ordering revisionHistory?

I can't find anything on this but is it possible to order the revisionHistory? I'd like to show the most recent changes first.

Trait Mode Not Working?

I can swap out Eloquent for Revisionable and add use Venturecraft\Revisionable\Revisionable; to the top and it works, but in trait mode it doesn't record my revision history. Existing revision history recorded in extend mode is still accessible. How would I go about debugging this?

from composer:

    "require": {
        "laravel/framework": "4.1.*",
        "doctrine/dbal": "~2.3",
        "intervention/image": "dev-master",
        "way/generators": "dev-master",
        "sebklaus/profiler": "dev-master",
        "davejamesmiller/laravel-breadcrumbs": "dev-master",
        "liuggio/excelbundle": ">=1.0.4",
        "ezyang/htmlpurifier": ">=4.6",
        "mews/purifier": "dev-master",
        "robclancy/presenter": "1.1.*",
        "symfony/yaml":"*",
        "venturecraft/revisionable": "1.5.0",
        "jenssegers/agent": "*"
    },

from models/User.php

use Illuminate\Auth\UserInterface;
use Illuminate\Auth\Reminders\RemindableInterface;

class User extends Eloquent implements UserInterface, RemindableInterface {
      [...]
    /*******************************************************************
     *  Revision History
     */

    use \Venturecraft\Revisionable\RevisionableTrait;
    //protected $revisionEnabled = true;

    // The $keepRevisionOf setting takes precendence over $dontKeepRevisionOf
    //protected $keepRevisionOf = array('phone');

    protected $dontKeepRevisionOf = array(
        'verify',
        'deleted_at',
        'created_at',
        'updated_at',
    );

    //protected $revisionFormattedFields = array(
        //'title'  => 'string:<strong>%s</strong>',
        //'public' => 'boolean:No|Yes'
    //);

    //protected $revisionNullString = 'nothing';
    //protected $revisionUnknownString = 'unknown';

    /******************************************************************/
     [...]
}

Related models with multiple word attributes throws error at line 105 in Revision.php

Let's say I have a model with the following revision rules:

protected $keepRevisionOf = array(
        'title',
        'filename',
        'published_status_id'
);

On the model, I would also have:

public function publishedStatus() 
    {
        return $this->hasOne('PublishedStatus', 'id', 'published_status_id');
    }

But it fails, because it is looking for published_status with method_exists. It should be looking for publishedStatus (from the point of view that relationships should be defined with camel case I believe). I wrapped camel_Case around the str_replace on line 102, and it seems to work fine. 

Provide pre-formatted history string

Instead of forcing people to write out their own history, provide both the breakdown methods so they can still do this, but also a pre-formatted full string.

Getting single revision out of revisionHistory

Hi,

in my app i generate a list out with revisionHistory without oldValue and newValue to keep it clean.

I offer a revision details modal where i load the details with ajax. Is there a smarter way to load one revision by revision_id (with working relations) than this:

$revision = $modelfull::find($id)->revisionHistory->find($revision_id)

I think this is much overhead? If there is no better way perhaps you might consider this as a feature request :)

Exceptions when saving relationships in seed files

I came across two exceptions when running a seed script. Both occur in the afterSave method.

The first is an undefined index Revisionable.php line 112. Occurs because the originalData array does not contain the new items key.

The second is trying to get property of non-object on line 114. Auth::user() will return null as no User will be present when running seed files via artisan.

How can we handle Sync / Detach?

Hello,

I'm using Revisionable for some time now, and I still didn't find a way to keep history from Sync or Detach calls, when you have ManyToMany, where a third table is created to hold the relations and there is no Model for it Revisionable does not detect the sync/detach changes.

Anybody has any idea on a workaround to keep track on this?

Maybe something to be implemented so this become an ER?

Thank you,

Robson

Use Cartalyst Sentry user id

We're using Sentry to handle our users. It would be great there was an option to use Sentry's user id instead of Laravel's built it one.

I know what needs to be changed, but I'm just not sure how to make it easily configurable for others.

Line #120 would be replaced with the following:

'user_id' => (\Sentry::check() ? \Sentry::getUser()->id : null),

Maybe a solution would be to have a package configuration file with an option like culpa. https://github.com/rmasters/culpa#changing-the-user-source

Create / Destroy

Before I log this as an issue, is this package supposed to also log create / destroy hits on the model or is it only firing for updates? The event seems to be firing on ->save() but when I create a new object, nothing is logged.

Overwriting of $revisionNullString and $revisionUnknownString

Hi,

i have overwritten $revisionNullString and $revisionUnknownString in my models like described in the readme, but i still get the default strings.

$revisionNullString and $revisionUnknownString belong to "Revision", app models extend "Revisionable", so overwriting can't work atm?

Or is it my fault :)

Support for Multiauth (or custom driver)

First of all You've done a really good package, thanks a lot.

Should be a good thing to support multiple auth driver or to save also the "model" associated with the auth user. In my case (an I think in many cases) Auth::user() can be User, Admin, or another model depending on current login.

needed stuffs are ..

  • in the revision table add a field "user_type", and add a setter method to fill it on booting
  • by default "user_type" should save get_class(Auth::user()) or a user defined class name.
  • to find userResponsible revision model should use something like:
    {$this->user_type}::find($this->user_id) instead of: \Config::get('auth.model')

I'm extending my models from Revisionable because I'm on laravel 4.1 and php5.3 (so no traits).
I think I'll override postSave(), postDelete() and getUserId() in my Revisionable extended model,I'm on the right road?

anyway here are a lot of private methods and attributes (like getUserId(), $updating, ...) so my extended model need to overwrite many things. Please consider to switch private to protected in next relase.

Batch inserts

At the moment, it seems that each attribtue change in a model results in a separate query being run

$revision = new Revision();
$revision->revisionable_type = get_class($this);
$revision->revisionable_id = $this->id;
$revision->key = $key;
$revision->old_value = (isset($this->originalData[$key]) ? $this->originalData[$key]: null);
$revision->new_value = $this->updatedData[$key];
$revision->user_id = (\Auth::user() ? \Auth::user()->id : null);
$revision->save();

If only a few attributes were changed, then this is fine. However, if there are a large number of attributes, then its much better to do a batch insert.

I would suggest moving all saves to using the QueryBuilder's batch insert method (http://four.laravel.com/docs/queries#inserts).

User responsible not saved if the user model is in a namespace.

The User model is hard-coded to be in the root namespace. This means that if someone namespaces their model like namespace App\Models; It will fail to save the user id. The model to use should be put into a configuration file that way people can publish it and change to suite their needs without fear of updates breaking it.

Unique ID of revision?

Is there any way to get the unique ID(s) of a revision? I'm trying to link exact changes to an existing activity feed module. I realize I could query after the update but that leaves the possibility of a race condition.

From what I've seen its not built in currently but my guess is that there would have to be some kind of "batch id" in the case of multiple fields being updated at once and that id would be set as an attribute on the model.

What changes (if any) need to be made to existing tables?

I've been looking to revision data in a new project and I think that this will work wonderfully but I was wondering what (if any) changes I need to make to my existing database tables to support revisioning?

I looked through the issue queue and read the read me and I didn't see anything about this but I could have just missed it so I apologize if the information on this is already available.

Ability to format field value

To be used in cases of boolean values, instead of having

Chris changed public from 0 to 1

Should be able to display something like

Chris changed public from no to yes

Struggling to get _id ref / formatting working

Hi Chris

I have the following migration:

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;

class CreateTables extends Migration {

    public function up()
    {
        Schema::create('person_types', function(Blueprint $table)
        {
            $table->increments('id');
            $table->timestamps();
            $table->string('description');
        });

        Schema::create('people', function(Blueprint $table)
        {
            $table->increments('id');
            $table->unsignedInteger('person_type_id');
            $table->foreign('person_type_id')->references('id')->on('person_types');
            $table->string('first_name');
            $table->string('last_name');
            $table->string('id_number', 13)->unique();
            $table->date('birth_date')->nullable();
            $table->unsignedInteger('age')->nullable();
            $table->string('email')->unique();
            $table->string('mobile', 10)->unique();
            $table->text('postal_address')->nullable();
            $table->text('physical_address')->nullable();
            $table->timestamps();
            $table->softDeletes();
        });

    }

    public function down()
    {
        Schema::drop('people');
        Schema::drop('person_types');
    }

}

and the following model:

use Watson\Validating\ValidatingTrait; // Model Validation
use Illuminate\Database\Eloquent\SoftDeletingTrait; // Soft Deletes
use Venturecraft\Revisionable\RevisionableTrait; // Model Auditing

class Person extends Eloquent
{
    use SoftDeletingTrait,RevisionableTrait,ValidatingTrait;

    protected $softDelete = true;
    protected $guarded = array();

    protected $rules = [
        'first_name'    => 'required',
        'last_name'     => 'required',
        'id_number'     => 'required|numeric|digits:13|id_number|unique:people',
        'mobile'        => 'required|numeric|digits:10|unique:people',
        'email'         => 'required|email|unique:people',
        'age'           => 'numeric|between:1,120',
        'birth_date'    => 'date|date_past',
        'person_type_id'=> 'required|numeric'
    ];

    /**
     * Person Type: One to One Relationship
     *
     * @return \Illuminate\Database\Eloquent\Relations\BelongsTo
     */
    public function personType()
    {
        return $this->belongsTo('PersonType');
    }

    /**
     * Scope: Sort by Last Name Ascending
     *
     * @param $query
     * @return mixed
     */
    public function scopeLastNameAscending($query)
    {
        return $query->orderBy('last_name','ASC');
    }

}

However, I cannot get the foreign key description to display for the person_type_id, nor can I change the field format displayed. (I tried the $revisionFormattedFieldName. Also tried to do the accessor / mutator thing to no avail (copied and modified the examples from laravel's docs))

Any idea what I could be doing wrong?

image

Foreign key problem with namespaced Models

Hi,

first of all thanks for the revisionable package, saving me hours of work!

I made most of my namspaced models "revisionable" and everything works fine. Bit if i try to get the oldValue() from a foreign key relation, Class "myrelatedmodel" can't be found. If i look in Revision.php line 72, i know why:

$item  = $model::find($this->old_value);

This will try to get myrelatedmodel, not App/Models/myrelatedmodel.

I don't know how to solve the issue - un-namespacing all my models would work but is no option for me. Perhaps revisionable can extract the model namespace (if there is any) stored in revisionable_type like 'App\Models\Mymodel'? Ir is there a simple solution i can't think about?

Thanks in advance!

Sentry fix

The Sentry works as intended if you're logged in. If you're not logged in, it still tries to use Auth::check() which throws an exception if not configured.

Replace:

if (class_exists('Sentry') && \Sentry::check()) {
    $user = \Sentry::getUser();
    return $user->id;
} else if (\Auth::check()) {
    return \Auth::user()->getAuthIdentifier();
}

With:

if (class_exists('Sentry')) {
    if( \Sentry::check() ) {
        $user = \Sentry::getUser();
        return $user->id;
    } else {
        return null;
    }
} else if (\Auth::check()) {
    return \Auth::user()->getAuthIdentifier();
}

Defect with revisionHistory ?

Hello,

Please, I need some assistance here, not sure if this can be a defect.

I select my objects based on its owner, becase I have a 'multiple-user-shared' database, so it is a hasMany relationship.

Also, I'm using Ardent, so I'm including/using Revisionable as Traits.

When I run:
foreach (Auth::user()->db_owner()->coreusers as $coreuser)
{
echo "
Changes for user: ".$coreuser->id."
";
foreach ($coreuser->revisionHistory as $history)
{
echo "


  • on ".date_format(date_create($history->created_at), "d-m-Y H:i:s")."
    user ".$history->userResponsible()->morph->imodpessoa->nome_razao."
    changed field ".$history->fieldName()."
    from ".$history->oldValue()."
    to ".$history->newValue()."
  • ";
    }
    }

    It does not work, returns an empty/null revisionHistory result.

    Now, if I change foreach loop:
    from -> foreach ($coreuser->revisionHistory as $history)
    to -> foreach (CoreUser::find($coreuser->id)->revisionHistory as $history)

    However, I can not change my Application and I need it to work with the first foreach loop, would someone know to confirm if this is a issue, or if maybe I'm doing something wrong?

    I really appreciate any assistance.

    Thank you very much,

    Robson.

    Support for BatchIds

    This seems like it would be fairly easy to implement. Basically it is a batch_id for each time the revision is saved. For example - I have a model that has 5 fields, I changed all of those fields from -> to something. When its saves, it saves that as a batch. Next time that particular model get changed again in multiple fields, the batch number auto-increments. Does this feature make any sense. If not, what would be the best way for me to implement this out side of your package?

    Recommend Projects

    • React photo React

      A declarative, efficient, and flexible JavaScript library for building user interfaces.

    • Vue.js photo Vue.js

      ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

    • Typescript photo Typescript

      TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

    • TensorFlow photo TensorFlow

      An Open Source Machine Learning Framework for Everyone

    • Django photo Django

      The Web framework for perfectionists with deadlines.

    • D3 photo D3

      Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

    Recommend Topics

    • javascript

      JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

    • web

      Some thing interesting about web. New door for the world.

    • server

      A server is a program made to process requests and deliver data to clients.

    • Machine learning

      Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

    • Game

      Some thing interesting about game, make everyone happy.

    Recommend Org

    • Facebook photo Facebook

      We are working to build community through open source technology. NB: members must have two-factor auth.

    • Microsoft photo Microsoft

      Open source projects and samples from Microsoft.

    • Google photo Google

      Google โค๏ธ Open Source for everyone.

    • D3 photo D3

      Data-Driven Documents codes.