I have pushed this repo to composer as well:
https://packagist.org/packages/sammaye/auditrail2
This is basically a reload of the extension by MadSkillsTisdale here audittrail
I decided to re-release this instead of wait for a confirmation from the author to merge my changes since the code base has changed so much only about one file remains relatively/exactly the same as it did before as well as taking numerous suggestions from advice posted on the previous extensions thread, namely this one
You can find/fork/whatever the project and its documentation on Github:
The method of installation has changed. I have removed the need to install a module class since:
CGridViewAs such for these reasons the module itself has been deleted.
To install you must first choose a folder in which to place this repository. I have chosen:
/root/backend/extensions/modules
Since this seems most right to me. Download the zip file and unzip it to a folder called "audittrail" within that directory.
Time to install the table. You can use the migration file provided by the original author of this extension or you can use the SQL file bundled within the migrations folder. Simply run it on your DB server (using PHPMyAdmin or something) and watch the magic unfold.
Reference the AuditTrail model within your configuration:
'import'=>array( 'site.backend.extensions.modules.auditTrail.models.AuditTrail', ),
Note You can move AuditTrail to your models folder preventing you from having to link it like this.
Simply use the behaviour within a model like:
'LoggableBehavior'=> array( 'class' => 'site.backend.extensions.modules.auditTrail.behaviors.LoggableBehavior', )
If your user class is not User then you may (depending on your setup) need to change the relation within the AuditLog model to suite your needs.
Some people don't actually have defined users but do have an attribute of the auditable model that would define a unique identification of who edited it. For this end you can use:
'LoggableBehavior'=> array( 'class' => 'site.backend.extensions.modules.auditTrail.behaviors.LoggableBehavior', 'userAttribute' => 'name' )
The date of the audit can be changed to used timestamps instead using:
'LoggableBehavior'=> array( 'class' => 'site.backend.extensions.modules.auditTrail.behaviors.LoggableBehavior', 'storeTimestamp' => true )
You can adjust the date format using the dateFormat property of the behaviour:
'LoggableBehavior'=> array( 'class' => 'site.backend.extensions.modules.auditTrail.behaviors.LoggableBehavior', 'dateFormat' => 'Y-m-d H:i:s' )
There is one interesting addition to this version. You can now specify an allowed set of fields and a ignored set of fields...or both.
To do this include the behaviour in your models like you normally would:
'LoggableBehavior'=> 'site.backend.extensions.modules.auditTrail.behaviors.LoggableBehavior'
But then add either a ignored or allowed (or both) to the behaviour like so:
'LoggableBehavior'=> array( 'class' => 'site.backend.extensions.modules.auditTrail.behaviors.LoggableBehavior', 'allowed' => array( 'version', 'ns_purchase_description' ), 'ignored' => array( 'ns_purchase_description', 'ns_display_name', 'update_time' ) )
The names put into the allowed and ignored parameters of the behaviour represent field names.
As you will notice I allow the ns_purchase_description field but also ignore it. When you use the fields in this way ignored will replace the allowed and this field will be omitted.
Since this no longer uses a module to do its work there is no global configuration for the previously inbuilt audit log to work from. Instead you can insert an audit log onto a models page using (as an example only, showing an audit of changes to a book title and it's products on a book title page) the code below.
As Per the comments the old code that used to display here did not take model name into account so here is a better piece of code to do so (from a little help on Stackoverflow cos I got turned around by the CDbCriteria class):
$model_ids = array(array($model->id, 'Title')); foreach($model->products as $id => $product){ $model_ids[] = array($product->id, 'Product'); } $criteria=new CDbCriteria(array( 'order'=>'stamp DESC', 'with'=>array('user'), )); $param_id = 0; foreach( $model_ids as $id_pair ) { $criteria->addCondition( '( model_id = :id' . $param_id . ' AND model = :model' . $param_id . ' )', 'OR' ); $criteria->params[ ':id' . $param_id ] = $id_pair[0]; $criteria->params[ ':model' . $param_id ] = $id_pair[1]; $param_id++; } $this->widget('zii.widgets.grid.CGridView', array( 'id'=>'title-grid', 'dataProvider'=>new CActiveDataProvider('AuditTrail', array( 'criteria'=>$criteria, 'pagination'=>array( 'pageSize'=>100, ) )), 'columns'=>array( array( 'name' => 'Author', 'value' => '$data->user ? $data->user->email : ""' ), 'model', 'model_id', 'action', array( 'name' => 'field', 'value' => '$data->getParent()->getAttributeLabel($data->field)' ), 'old_value', 'new_value', array( 'name' => 'Date Changed', 'value' => 'date("d-m-Y H:i:s", strtotime($data->stamp))' ) ), ));
Total 15 comments
I have opened a new toic here: http://www.yiiframework.com/forum/index.php/topic/40416-extension-audittrail-2/
You can also post an issue on github: https://github.com/Sammaye/audittrail/issues?state=open
Can you open a forum topic for this extension, or if one exist post the link?
Yeah, that is very weird.
I would try and see what getAttributes returns and if it returns fields that are not empty I would iterate through
auditAttributesto see why it ditches them.I can't see anything obvious from the classes.
@Sammaye It seems to get the old value on some models but on others nothing is stored, let me investigate, here are dropbox link to the two different models,does not work on this one Example One Works on this one Example Two . I have also tried playing with
nothing much, I am using the github version
Strange indeed.
Can you post a code snippet that can replicate this behaviour?
Maybe it is how it is being used in the model as a behaviour in the parent model.
Also can you just tell me if
getAttributes()actually returns anything in this case?It might not be recording old values because those values are either '' or
null, these values I omit to save database space; that option can be turned off however.I cant seem to get Old value to be recorded, its seems this is tied to
Any pointers, thanks again, the allowed and ignored functionality is really awesome
I will look into that
getIsNewRecordone though it does work on my system.Ah I see, it is running the validation rules. Strange I don't see that behaviour in my system but you are right that is a bug. I have fixed it now :).
you have this in your rules for model AuditTrail array('action, model, field, stamp, model_id', 'required'),
but when you create a trail for create (there another issue here I think) or delete only pass variable $action and save fails. another thing I changed is that you use afterSave to save the trail and you use isNewRecord, I'm not sure right now cause I can't check it right away but that will always be false, because the model is already saved so you have to check that flag in beforeSave and ask latter in the afterSave.
Hope it helps sorry if I'm wrong :D
Fixed time bug.
Would be awesome if you can give an example of the Delete thing you said about :)
Strange I use delete and what not and it works fine for me. It should place "Create" (or "Delete") and the field attribute, as for the model_id: that is indeed a required attribute. Is there a reason you are using this without activeRecord since all active record models should have an id (primary key).
I shall look into that time thing. I must admit I had not tested that functionality, however
$time()is not a valid variable. Can you give me an example code which causes the bugable behaviour?Edit: I see what you meant now by $time(), lol. I will change that asap.
There are some issues with audittrails2, for example is unable to record create and delete trails because model_id and field attributes in model AuditTrail are required so save fails every time. Another bug is found in LoggableBehavior in line 101, when using variable $time() instead of function time(), by default it would not give error because the default is to not save timestamp.
thanks for your extension, very usefull to me!
Yea it is quite bad example but the alternative is a really complex PDO statement with lots of
ORs which is bad. I may proposed something like:Anyway let's see where it goes :).
aa, ok. I did not check source codes, just slightly misunderstood 'printing out' snippet, because you are preparing there criteria with just model id's and without model names...
Indeed normally you cannot differentiate the model however this too stores the model name.
So it stores:
If you check the AuditTrail model and the function getParent() within that you will see this is how I get the parent model (The line for it here: https://github.com/Sammaye/audittrail/blob/master/behaviors/LoggableBehavior.php#L98).
The field name is a little confusing and could probably do with changing. I originally made this to work on the same schema as the previous extension.
The last snippet was just an example of getting all audit logs by a specific primary key. Probably a bad one since I too realised this key confliction and have since changed the code I show here to go on the "model" field as well. I might also allow extra descriptive fields as a future addition since I realised to get a group of audit logs for a specific context you might need to know more about the subobjects of a parent. However I am unsure how this will be done atm.
When the Primary is an array it should JSON encode the primary key (https://github.com/Sammaye/audittrail/blob/master/behaviors/LoggableBehavior.php#L122), I am unsure as to whether that is the right thing to do since I personally have never had an array based primary, in Yii yet.
Hope it helps,
I did notice, that you just store primary key of model in your audit trail (looking at $criteria in last snippet). It is rather wrong, because you cannoc assign this behavior to more than one model, or its keys will collide. To be more clear:
Lets say you have two models: User, Company. Both have attached your behavior. If I change User with id=1 AuditTrail record is created with model_id=1. When I change Company with id=1 - same thing (audittrail is created with model_id=1), but both have same foreign key reference and you cannot say whoch is for User trail and witch for Company...
I did write very similiar behavior for my project, but I store both class name of model and it's primary key. In fact there are also cases when primary key is an array (multiple column primary key) and in such case your behavior will fail as well...
Leave a comment
Please login to leave your comment.