LogableBehavior
What
The intent of this behavior is to create a row in a log table every time a model's data (or all the model that the behavior is applied to) is created, edited or deleted. The developer can set this log table up to include as much detail as is required, and that is all the configuration that is needed.
How
Requirements
- The behavior found on page 2
- A Log model( empty but for a order variable [created DESC]
- A "logs" table with these fields required :
- id (int)
- title (string) automagically filled with the display field of the model that was modified.
- created (date/datetime) filled by cake in normal way
- actsAs = array("Logable"); on models that should be logged
Optional configurations
Optional extra table fields for the "logs" table
- description (string) Fill with a descriptive text of what, who and to which model/row
- Example :Contact "John Smith"(34) added by User "Administrator"(1).
or if u want more detail, add any combination of the following
- model (string) automagically filled with the class name of the model that generated the activity.
- model_id (int) automagically filled with the primary key of the model that was modified.
- action (string) automagically filled with what action is made (add/edit/delete)
- user_id (int) populated with the supplied user info. (May be renamed. See bellow.)
- change (string) depending on setting either
- full: [name (alek) => (Alek), age (28) => (29)] or list: [name, age]
- version_id (int) cooperates with VersionBehavior to link the the shadow table (thus linking to old data)
NB! VersionBehavior cooperation not implemented this version.
Optionally register what user was responisble for the activity
Supply configuration only if defaults are wrong. Example given with defaults:
Model Class:
Download code
<?php
class Apple extends AppModel {
var $name = 'Apple';
var $actsAs = array('Logable' => array(
'userModel' => 'User',
'userKey' => 'user_id',
'change' => 'list', // options are 'list' or 'full'
'description_ids' => TRUE // options are TRUE or FALSE
));
[..]
?>
The change fields modifies what will be automagic filled in the change field if the log table has it. The description_ids option sets whether the description field will include the ids of the mode and the user. (See example above)
Usage
If you are using the user feature of the behavior, the models needs to know the id of the active user. This is most easily set in app controller in this way, but note that you may use the Logable::setUserData() method manually should you so desire.
Controller Class:
Download code
<?php
// In AppController (or single controller if only needed once) add these lines to beforeFilter :
if (sizeof($this->uses) && $this->{$this->modelClass}->Behaviors->attached('Logable')) {
$this->{$this->modelClass}->setUserData($this->activeUser);
}
?>
Where "$activeUser" should be an array in the standard format for the User model used :[/]
Download code
<? $activeUser = array( $UserModel->alias => array( $UserModel->primaryKey => 123, $UserModel->displayField => 'Alexander')); ?>
any other key is just ignored by this behaviour.
Get the logs out
I don't supply a helper or views for this, I am sure you can manage, but I suggest you make one view and use the controllers viewpath or the controllers render method to only render a single view for all models that use the behavior.
To extract the logs, no matter of you want all events, or just for one model or one user, or even one user's activity on one model, you can ask any model that the behavior is enabled on. There are two methods
- findLog($params)
- findUserActions($user_id, $params)
You can off course query the Log model in the normal way.
findLog
This is the main function for retrieving the logged activities. It will by default (when called with no parameters) return all activities for the model it is called from, but it can also be used for any or all models from any model. The available options are listed bellow.
- model (string)
- action (string) (add/edit/delte) defaults to NULL (ie. all)
- fields (array)
- order (string) defaults to 'created DESC'
- conditions (array) add custom conditions
- model_id (int) ForeignKey for a single instance of logged model
- user_id (int) defaults to NULL (all users).
Remember to user your own foreignKey if you did not use 'user_id'
Download code
<?php // examples
// All acitivities on current model
$data = $this->Apple->findLog();
// All acitivities on current model instance
$data = $this->Apple->findLog('model_id'=>32);
// I am in apple controller, but i want acitivities for the user on a specific Logo isntance
$data = $this->Apple->findLog(array('user_id'=>66,'model'=>'Logo','model_id'=>123));
?>
findUserActions
The first parameter is compulsory and is the ID of the user (foreignKey). The second is an array of options. The available options are listed bellow. Model and fields does the expected things, while events will create a description on the fly. This function is intended to be improved in the next version to be translatable / customizable.
- model (string)
- events (boolean)
- fields (array)
Download code
<?php // examples
// note we are asking for a different model
$data = $this->User->findUserActions(301,array('model' => 'BookTest'));
$data = $this->Apple->findUserActions(301,array('events' => true));
$data = $this->Model->findUserActions(301,array('fields' => array('id','model'),'model' => 'BookTest');
?>
The code (or download link) can be found on the next page.
Comments
Comment
1 Great work!
Are you still working on linking it to the Revision Behaviour? it would be really great.
I´ll have a look and see what i can do with it.
Thank you!
Comment
2 Version 2
Where you can also download it's big brother, RevisionBehavior (that also just hit version 2) and it's cousin, MultilingualBehavior.
Comment
3 Great!
Just curious why a new User is being instantiated on line 98 if we're passing it info in setUserData??
Comment
4 Me too!
Same here. Anyone got a fix for this?
Comment
5 User data
I had some troubles figuring out what I should pass to setUserData in beforeFilter. These lines seems to do the job:
if (sizeof($this->uses) && $this->{$this->modelClass}->Behaviors->attached('Logable')) {
$this->{$this->modelClass}->setUserData($this->Session->read('Auth'));
}
Regards
Jonathan
Comment
6 Alternative way to pass User Data?
Fixed:
$this->DarkAuth->getUserInfo()