Giter Club home page Giter Club logo

cakephp-audit-log-plugin's Introduction

Audit Log Plugin

A logging plugin for CakePHP 2.x. The included AuditableBehavior creates an audit history for each instance of a model to which it's attached.

The behavior tracks changes on two levels. It takes a snapshot of the fully hydrated object after a change is complete and it also records each individual change in the case of an update action.

Features

  • Support for CakePHP 2.2+. Thanks, @jasonsnider.
  • Tracks object snapshots as well as individual property changes.
  • Allows each revision record to be attached to a source -- usually a user -- of responsibility for the change.
  • Allows developers to ignore changes to specified properties. Properties named created, updated and modified are ignored by default, but these values can be overwritten.
  • Handles changes to HABTM associations.
  • Fully compatible with the PolymorphicBehavior.
  • Fully compatible with SoftDelete.

Versions

CakePHP 2.x

Use the current master branch and follow the instructions below.

CakePHP 3.x

The dev-3.x branch is now dedicated to any CakePHP 3.x development but is still WIP. If you are looking for working solutions you can look at the plugins listed at Awesome CakePHP

CakePHP 1.3.x

Use code from the 1.3 branch and follow the instructions in that README file. Please note that development has ended for this version.

Installation (2.x)

Installation Options

Using Composer

From your /app/ folder run:

$ composer require robwilkerson/cakephp-audit-log-plugin

This will automatically update your composer.json, download and install the required packages.

As an Archive

  1. Click the big ol' Downloads button next to the project description.
  2. Extract the archive to app/Plugin/AuditLog.

As a Submodule

  1. $ git submodule add git://github.com/robwilkerson/CakePHP-Audit-Log-Plugin.git <path_to>/app/Plugin/AuditLog
  2. $ git submodule init
  3. $ git submodule update

Load the Plugin

In app/Config/bootstrap.php add the following line:

CakePlugin::load('AuditLog');

Setup Database

To create the necessary tables, you can use the schema shell. Run from your /app/ folder:

php ./Console/cake.php schema create -p AuditLog

This will create the audits and audit_deltas tables that will store each object's relevant change history.

Next Steps

  1. Create a currentUser() method, if desired.

    The AuditableBehavior optionally allows each changeset to be "owned" by a "source" -- typically the user responsible for the change. Since user and authentication models vary widely, the behavior supports a callback method that should return the value to be stored as the source of the change, if any.

    The currentUser() method must be available to every model that cares to track a source of changes, so I recommend that a copy of CakePHP's AppModel.php file be created and the method added there. Keep it DRY, right?

    Storing the changeset source can be a little tricky if the core Auth component is being used since user data isn't readily available at the model layer where behaviors lie. One option is to forward that data from the controller. One means of doing this is to include the following code in AppController::beforeFilter():

    if (!empty($this->request->data) && empty($this->request->data[$this->Auth->userModel])) {
    	$user['User']['id'] = $this->Auth->user('id');
    	$this->request->data[$this->Auth->userModel] = $user;
    }

    The behavior expects the currentUser() method to return an associative array with an id key. It is also possible to set a description key to add additional details about the user. Continuing from the example above, the following code might appear in the AppModel:

    /**
     * Get the current user
     *
     * Necessary for logging the "owner" of a change set,
     * when using the AuditLog behavior.
     *
     * @return mixed|null User record. or null if no user is logged in.
     */
    public function currentUser() {
        App::uses('AuthComponent', 'Controller/Component');
        return array(
            'id' => AuthComponent::user('id'),
            'description' => AuthComponent::user('username'),
        );
    }
  2. Attach the behavior to any desired model and configure it to your needs.

Configuration

Applying the AuditableBehavior to a model is essentially the same as applying any other CakePHP behavior. The behavior does offer a few configuration options:

  • ignore An array of property names to be ignored when records are created in the deltas table.
  • habtm An array of models that have a HABTM relationship with the acting model and whose changes should be monitored with the model. If the HABTM model is auditable in its own right, don't include it here. This option is for related models whose changes are only tracked relative to the acting model.
/**
 * A model that uses the AuditLog default settings
 */
class SomeModel extends AppModel {

	/**
	 * Loading the AuditLog behavior without explicit settings.
	 * 
	 * @var array
	 */
	public $actsAs = array('AuditLog.Auditable');

	// More model code here.
}

/**
 * A model that sets explicit AuditLog settings
 */
class AnotherModel extends AppModel {

	/**
	 * Loading the AuditLog behavior with explicit settings.
	 * 
	 * @var array
	 */
	public $actsAs = array(
		'AuditLog.Auditable' => array(
			'ignore' => array('active', 'name', 'updated'),
			'habtm' => array('Type', 'Project'),
		)
	);

	// More model code here.
}

Callbacks

The plugin offers multiple Callbacks that allow the execution of additional logic before or after an operation of this Plugin.

To add a custom Callback create a method with one of the names listed below in your audited model.

afterAuditCreate

afterAuditCreate(Model $Model)

Triggers if a new record is inserted in the Audit table

  • $Model Name of the model where the record is created

afterAuditUpdate

afterAuditCreate(Model $Model, array $original, array $updates, int $auditId)

Triggers if a record is updated in the Audit table.

  • $Model Name of the model where record is updated
  • $original Contains a copy of the object as it existed prior to the save
  • $updates Set of records that have been updated
  • $auditId Id of the record in the Audit table

afterAuditProperty

afterAuditCreate(Model $Model, string $propertyName, string $oldValue, string $newValue)

Triggers each time a property is inserted into the audit_deltas table.

  • $Model Name of the model where record is created / updated
  • $propertyName Name of the property (field name)
  • $oldValue Original value of the property
  • $newValue New value of the property

License

This code is licensed under the MIT license.

Notes

Feel free to submit bug reports or suggest improvements in a ticket or fork this project and improve upon it yourself. Contributions welcome.

cakephp-audit-log-plugin's People

Contributors

chrisjohnson avatar codelingobot avatar cpuid avatar inigoflores avatar jasonsnider avatar jlpuder avatar josephsong avatar paulleephp avatar ptica avatar ravage84 avatar rchavik avatar robwilkerson avatar wewilkinson avatar wuilliam321 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

cakephp-audit-log-plugin's Issues

Does not work with HABTM relationships

I have a standard habtm config.
House habtm Property, with the table houses_properties and without the model HouseProperty.

On House model:
public $actsAs = array('AuditLog.Auditable' => array('Property'));

But when I change the house id = 20 changing only an association of a property in the table audits not recorded any changes!

2.x Branch

According to https://github.com/robwilkerson/CakePHP-Audit-Log-Plugin#cakephp-2x

The 2.x branch contains a stable version, but is not up to date.

So what's the point of it? It's probably a relict of when the master branch was planned to be the active development branch for the CakePHP 3.x plugin version.

I would remove that stale branch. It could confuse people.

The only downside I see, is that it could break the composer installation of some people relying on this (obviously outdated) branch.

array_key_exists() warning output

When I turn on the Auditable behaviour for some of my models, I get the following warning output when saving those models or related ones:

Warning: array_key_exists() expects parameter 2 to be array, null given in /Users/jarnold/git/game-minder-server/web/app/Plugin/AuditLog/Model/Behavior/AuditableBehavior.php on line 155

It's not clear what is exactly causing the problem to happen, and I'm looking into it as well.

Alternative way to get Auth User ID in AppModel

This might not be the place for this but i couldnt see anywhere else to comment or share it. I have implemented this excellent Plugin and accessed the currently logged in user (cakePHP Auth) with the following in app_model.php

App::uses('Model', 'Model');
App::uses('CakeSession', 'Model/Datasource');

class AppModel extends Model {
    public function currentUser() {
        return array('id' => CakeSession::read("Auth.User.id"));
    }
}

Thanks for the plugin. its great.

Executing the tests with MSSQL leads to error

It seems the test suite isn't as robust if you run it against a MSSQL server.

Running the same tests with MySQL works fine, while with MSSQL it spits out the following error:

Warning: Illegal string offset 'name' inPath\To/Application\app\Model\Datasource\Database\Sqlserver.php on line 904

Call Stack:
    0.0670     128480   1. {main}()Path\To/Application\app\Console\cake.php:0
    0.0700     194280   2. ShellDispatcher::run(???)Path\To/Application\app\Console\cake.php:42
    0.1090    2266608   3. ShellDispatcher->dispatch()Path\To/Application\vendor\cakephp\cakephp\lib\Cake\Console\ShellDispatcher.php:66
    0.1180    3152328   4. Shell->runCommand(???, ???)Path\To/Application\vendor\cakephp\cakephp\lib\Cake\Console\ShellDispatcher.php:212
    0.1330    3657544   5. TestShell->main()Path\To/Application\vendor\cakephp\cakephp\lib\Cake\Console\Shell.php:461
    0.1340    3658552   6. TestShell->_run(???, ???)Path\To/Application\vendor\cakephp\cakephp\lib\Cake\Console\Command\TestShell.php:260
    0.1360    3813808   7. CakeTestSuiteCommand->run(???, ???)Path\To/Application\vendor\cakephp\cakephp\lib\Cake\Console\Command\TestShell.php:275
    0.1680    5298880   8. CakeTestRunner->doRun(???, ???)Path\To/Application\vendor\cakephp\cakephp\lib\Cake\TestSuite\CakeTestSuiteCommand.php:98
    0.2130    6391192   9. PHPUnit_TextUI_TestRunner->doRun(???, ???)Path\To/Application\vendor\cakephp\cakephp\lib\Cake\TestSuite\CakeTestRunner.php:62
    0.2150    6503448  10. PHPUnit_Framework_TestSuite->run(???, ???, ???, ???, ???)Path\To/Application\vendor\phpunit\phpunit\PHPUnit\TextUI\TestRunner.php:350
    0.2150    6504112  11. PHPUnit_Framework_TestSuite->runTest(???, ???)Path\To/Application\vendor\phpunit\phpunit\PHPUnit\Framework\TestSuite.php:749
    0.2150    6504176  12. CakeTestCase->run(???)Path\To/Application\vendor\phpunit\phpunit\PHPUnit\Framework\TestSuite.php:779
    0.2150    6504288  13. CakeFixtureManager->load(???)Path\To/Application\vendor\cakephp\cakephp\lib\Cake\TestSuite\CakeTestCase.php:80
    0.2390    6514960  14. CakeFixtureManager->_setupTable(???, ???, ???)Path\To/Application\vendor\cakephp\cakephp\lib\Cake\TestSuite\Fixture\CakeFixtureManager.php:231
    0.2410    6517656  15. CakeTestFixture->create(???)Path\To/Application\vendor\cakephp\cakephp\lib\Cake\TestSuite\Fixture\CakeFixtureManager.php:205
    0.2410    6518008  16. Sqlserver->createSchema(???, ???)Path\To/Application\vendor\cakephp\cakephp\lib\Cake\TestSuite\Fixture\CakeTestFixture.php:234

Issue CakePHP 3.0 -Audit-Log-Plugin

Hi,
Below is the Audit log plugin behavior with cakephp 3.0 version.In that i am not able to insert the 'created' field in 'audits' table.
please resolve the issue and if need please the improve the code quality.

_table = $table; $this->_ignore_properties = $config; } /** - @param Event $event - @param EntityInterface $entity */ public function afterSave(Event $event, EntityInterface $entity, ArrayObject $options) { //before change the data $arrOldData = $entity->extractOriginal($entity->visibleProperties()); //updated fields array object $arrUpdatedProperties = $entity->extractOriginalChanged($entity->visibleProperties()); //updated data object $arrUpdatedData = $entity->jsonSerialize(); //audit data $arrData = array( 'id'=>self::request_id(), 'event' => ($entity->isNew()) ? 'CREATE' : 'EDIT', 'model' => $event->subject()->alias(), 'entity_id' => $entity->id, 'request_id' => self::request_id(), 'json_object'=> json_encode( $arrUpdatedData ), 'source_id' => isset( $source['id'] ) ? $source['id'] : null, 'description'=> isset( $source['description'] ) ? $source['description'] : null ); //saving audit record $auditTable = TableRegistry::get('Audits'); $audit = $auditTable->newEntity($arrData); $auditTable->save($audit); $auditDeltaTable = TableRegistry::get('AuditDeltas'); foreach($arrUpdatedProperties as $sPropertyName=>$sValue) { //ignore the fields if(in_array($sPropertyName, $this->_ignore_properties)){ continue; } $delta = array( 'id'=> Text::uuid(), 'audit_id' => $audit->id, 'property_name' => $sPropertyName, 'old_value' => $sValue, 'new_value' => $entity->$sPropertyName ); $auditDeltas = $auditDeltaTable->newEntity($delta); $auditDeltaTable->save($auditDeltas); } } /** - @param Event $event - @param EntityInterface $entity - @param ArrayObject $options */ public function beforeSave(Event $event, EntityInterface $entity, ArrayObject $options) { return true; } }

New release overdue

People shouldn't use a dev-master revision as a dependency in their apps.
The last release 1.0.1 was tagged on 4 Sep 2011 .

Could you please tag a new release?
Either 1.1.0 or 1.0.2, depending on how much was added/changed.

See SemVer for further guidance on the release numbers.

Don't bind model on each callback

I understand why you bind the Audit and AuditDelta models, but I do not understand the goal in binding Audit to the model that is being audited.

String no longer supported from Cake 2.7

I scratched my head for hours before finally working this out.

I run CakePHP 2.7 and on line 21 of the AuditableBehavior.php file there is a declaration using String::uuid() which fails all attempts at adding, editing etc.

String is deprecated from Cake 2.7 and should be replaced by CakeText instead. May I suggest a check whether the model String exists and if not use CakeText instead in the request_id() method?

Unable to get HABTM to work for a hasMany relationship

Hi, Rob. Thanks for your creation, this has been a great deal for me.

This is the first time I have included your plugin in a project, so please bear with me. By the way, before I talk about my problem, I must mention that I have already checked #19 and also, I have read and understood the instructions in README, esp. this:

habtm
An array of models that have a HABTM relationship with the acting model and whose changes should be monitored with the model. If the HABTM model is auditable in its own right, don't include it here. This option is for related models whose changes are only tracked relative to the acting model.

I have 2 linked models: 'Job' hasMany 'Attachment'. At present, 'Attachment' is not polymorphic but I may need to do that later to link with other models(I will come back with new issues ๐Ÿ˜œ ). With my configuration, any and every changes to Job model are saved in the 2 DB tables perfectly. However, any addition/change on Attachment model are not recorded at all. It works if I attach the behaviour separately in latter model, but that's not what I want, I want to track linked changes. You can find my configuration for AuditLog below:

appModel

class AppModel extends Model {
    public function currentUser() {
        return CakeSession::read("Auth.User"); // Fix based on solution suggested in issue #35 
    }
}

Job

    public $actsAs = array(
        'Tree',     // inclusion of this behavior is somewhat common here and in issue #19, but not exactly same
        'AuditLog.Auditable' => array(
            'ignore' => array( 'lft', 'rght', 'created_by', 'created' ),
            'habtm'  => array( 'Attachment' )
        )
    );

// No validations exist in test env so far. 
// 'belongsTo' associations are not shown for the sake of brevity

// trimmed hasMany associations to show necessary code only 
    public $hasMany = array(
        'Attachment' => array(
            'className' => 'Attachment',
            'foreignKey' => 'job_id',
            'dependent' => false,
            'conditions' => '',
            'fields' => '',
            'order' => '',
            'limit' => '',
            'offset' => '',
            'exclusive' => '',
            'finderQuery' => '',
            'counterQuery' => ''
        ),
        'Audit' => array(       // Used to retrieve and display log
            'className' => 'Audit',
            'foreignKey' => 'entity_id',
            'dependent' => false,
            'conditions' => array(
                'Audit.model' => 'Job',
            ),
            'fields' => '',
            'order' => '',
            'limit' => '',
            'offset' => '',
            'exclusive' => '',
            'finderQuery' => '',
            'counterQuery' => ''
        )
    );

AuditableBehavior is not directly called in any other model.

Apologies for such long post, I just wanted to make sure that you understand my implementation clearly.

_P.S:_

  1. Suggested currentUser() and associated code in controller's beforeFilter() in README doesn't work. An edit in README will be great.
  2. I hoped that Audit hasMany AuditDelta would be in place to support easy retrieval. On checking the behavior, I noticed the association exists in beforeSave() which is called only before saving. While there is no provision for retrieving the log (which I agree, is reasonable due different needs of different developer), it should still be handy to have the relationship available during a find() call. For now, I used containable in my controller to cover this shortcoming.

ERROR in AuditableBehavior.php while deleting Objects

Hello,

you have got a mistake in your code.
If you have no 'json_object' in your model->alias:

In the function "afterDelete(Model $model)" there is this statement:
if (($this->_settings[$model->alias]['json_object']) {
$data['Audit']['json_object'] = json_encode($audit);
}
BUT it should be this:
if (!empty($this->_settings[$model->alias]['json_object'])) {
$data['Audit']['json_object'] = json_encode($audit);
}

Please change your code accordingly, it will always give you an error while deleting if this json-Object is not defined.

Packagist error when trying to publish

Oh dear!

The package name robwilkerson/CakePHP-Audit-Log-Plugin is invalid, it should not contain uppercase characters. We suggest using robwilkerson/cake-php-audit-log-plugin instead.

Can the repository be renamed?

currentUser code

couldn't get the currentUser functionality working as suggested.

eventually put:
public function currentUser() // for AuditLog.Auditable behavior
{
return CakeSession::read("Auth.User");
}
into AppModel (note public, not protected as suggested); and nothing required in AppController.

Thanks
Chris

Add displayField to JSON Object

How would I go about adding the displayField value to the stored json object? I am creating a view and would be nice to be able to display this in the view rather than an ID, at the moment I am querying the db but obviously this won't work if the record has been deleted, it would be great if I could just pull displayField from the json object then it won't mater if the record has been deleted or not

Make description field more flexible

The description field seems to be filled by the currentUser() method:

'description' => isset( $source['description'] ) ? $source['description'] : null,

This functionality is not dcumented anywhere and I doubt most people have a column description in their users table, thus this field stays empty in the audits table all the time.

It should be configurable, falling back to the current field name description for backwards compatibilty.

Add settings option to disable json_object

Reminder to myself implementing a settings option to not fetch the json_object data.

This would solve #30.

Take inspiration here:
jippi@de5c3d3

Additionally, it would be settable on what action it does save the json_object (CREATE, EDIT, DELETE).

Auditable Behavior does not respect empty habtm array

When I don't want any HABTM related models to be logged with given model, I expected to be able to set an empty habtm key.

For example like:

    public $actsAs = array(
        'AuditLog.Auditable' => array(
            'habtm' => array(),
        ),
    );

But it seems the setup() method does not respect an empty habm settings key:

https://github.com/robwilkerson/CakePHP-Audit-Log-Plugin/blob/2.0.1/Model/Behavior/AuditableBehavior.php#L40-L51

In my case, this leads to an untestable code base as the initialisation of one model during fixture setup tries to spawn many HABTM related models.

Why is primary key a non-integer

Is there a reason the primary key n the audit table is not an integer? This seems like a waste of space and is bad for indexing....

Using Auditable with the Translate behavior

I just started using your plugin with my CakePHP 2.x installation and so far, so good.

Then I saved some translated data to the I18n table associated with the Translate behavior, but there was no corresponding entry in the audits table.

Both the primary and I18n models are set to $actAs = array('AuditLog.Auditable'); but only the primary model causes Auditable to store the corresponding data.

I'm not saying this is necessarily unexpected, just that it would be useful if there was something similar to the 'habtm' switch which could cause a table related via a behavior (perhaps not only Translate), to save its data as well.

I tried wrapping my head around using the 'afterAuditCreate' method to accomplish what I want, but since I am trying to make an associated model save its data from the primary model, I'm at a loss.

Perhaps you have run across this situation and can point me in the right direction?

Unsupported operand types

Hi.
Thanks for the behaviour.
I had this problem:
Unsupported operand types in /lib/Cake/Core/CakePlugin.php on line 78

You can help?

ENHANCEMENT: summary in AuditDelta

At present, the AuditDelta model stores property_value, old_value and new_value as available in $this->request->data. However, this becomes very tedious to audit the changes that has HABTM associations. For example, if on Task model, if the assignment of task changes from user_id 1 to 5, the log should save the display name of User model in old_value and new_value, while the alias name of associated model, i.e., Assignee (alias for User model to manage assignments) should be saved in property_value.

This can probably be achieved by modifying the afterSave() in behavior. I started editing the behavior to apply a quick hack for my situation but it failed to save anything after that. So I had to revert the changes due to lack of time. Thought I should share the idea with you so that you can pursue it further for actual implementation. A gist of my code is below:

$btModels = $Model->belongsTo; // List of belongsTo Models with association info. I needed on belongsTo associations in my audit log
$btm = $this->_btModel($property, $btModels);
$pn = Inflector::humanize($property);
$ov = $Model->$btm->find('list', array('conditions' => array($btm.'.id' => $this->_original[$Model->alias][$property])));
$nv = $Model->$btm->find('list', array('conditions' => array($btm.'.id' => $value)));

$delta = array(
    'AuditDelta' => array(
    'property_name' => $pn,
    'old_value'     => $ov,
    'new_value'     => $nv
    )
);
/*********************************************************************/
/* Above code was substituted with the actual $delta in the behavior */
/*********************************************************************/

/* A quick and dirty workaround to be used to extract HABTM details */
private function _btModel($str, $array) {
    foreach ($array as $key => $val) {
        if ($val['foreignKey'] === $str) {
            return $key;
        }
    }
    return null;
}

I'll be more than happy to contribute if you are willing to include such enhancement. Meanwhile, if you can point out where in above code I may be doing wrong to achieve this, I will be thankful.

Regards

json_object mismatch with related models in DELETE scenario

This may be a misunderstanding on my part, but thought I would bring it up here.

When DELETEing a model which has a related model also acting as Auditable, the related model's data overrides the _original field, so the saved json_object for the deletion contains the related model's data rather than the deleted model's.

I have a Member model with a hasOne relationship to MemberPreference. I added a log message to print the model->alias in beforeDelete, and when deleting a Member, I see the following:

2011-12-20 21:26:20 Debug:
AuditableBehavior::beforeDelete() - APP/plugins/audit_log/models/behaviors/auditable.php, line 83
ModelBehavior::dispatchMethod() - CORE/cake/libs/model/model_behavior.php, line 169
BehaviorCollection::trigger() - CORE/cake/libs/model/model_behavior.php, line 494
Model::delete() - CORE/cake/libs/model/model.php, line 1829
MembersController::delete() - /home/jack/devel/proto/trunk/cake_app/controllers/members_controller.php, line 2081
Dispatcher::_invoke() - CORE/cake/dispatcher.php, line 204
Dispatcher::dispatch() - CORE/cake/dispatcher.php, line 171
[main] - APP/webroot/index.php, line 82
"beforeDelete: Member"
2011-12-20 21:26:20 Debug:
AuditableBehavior::beforeDelete() - APP/plugins/audit_log/models/behaviors/auditable.php, line 83
ModelBehavior::dispatchMethod() - CORE/cake/libs/model/model_behavior.php, line 169
BehaviorCollection::trigger() - CORE/cake/libs/model/model_behavior.php, line 494
Model::delete() - CORE/cake/libs/model/model.php, line 1829
Model::_deleteDependent() - CORE/cake/libs/model/model.php, line 1892
Model::delete() - CORE/cake/libs/model/model.php, line 1835
MembersController::delete() - /home/jack/devel/proto/trunk/cake_app/controllers/members_controller.php, line 2081
Dispatcher::_invoke() - CORE/cake/dispatcher.php, line 204
Dispatcher::dispatch() - CORE/cake/dispatcher.php, line 171
[main] - APP/webroot/index.php, line 82
"beforeDelete: MemberPreference"

I am able to workaround by adding if ($this->_original != null) return true; to the start of the beforeDelete() method, at least in the one case that I see this happening.

Thanks for the great plugin!
Jack

Auditing all models directly question

Hi!
Thanks for the behaviour!
How would you audit all models?
E.g can I simply enable this in app_model and update the behaviour to bypass the Audit model callbacks (so it doesn't recurse)
Thanks

PHP 5.4 incompatibility

Seems the inheritance is causing some issues on PHP 5.4 (CakePHP 2.1 here)... see below:

Strict (2048): Declaration of AuditableBehavior::setup() should be compatible with ModelBehavior::setup(Model $model, $config = Array) [APP/Plugin/AuditLog/Model/Behavior/AuditableBehavior.php, line 6]
Strict (2048): Declaration of AuditableBehavior::beforeSave() should be compatible with ModelBehavior::beforeSave(Model $model) [APP/Plugin/AuditLog/Model/Behavior/AuditableBehavior.php, line 6]
Strict (2048): Declaration of AuditableBehavior::afterSave() should be compatible with ModelBehavior::afterSave(Model $model, $created) [APP/Plugin/AuditLog/Model/Behavior/AuditableBehavior.php, line 6]
Strict (2048): Declaration of AuditableBehavior::beforeDelete() should be compatible with ModelBehavior::beforeDelete(Model $model, $cascade = true) [APP/Plugin/AuditLog/Model/Behavior/AuditableBehavior.php, line 6]
Strict (2048): Declaration of AuditableBehavior::afterDelete() should be compatible with ModelBehavior::afterDelete(Model $model) [APP/Plugin/AuditLog/Model/Behavior/AuditableBehavior.php, line 6]

Allowing currentUser via behaviors

It would be useful to be able to allow currentUser() to be implemented in a behavior. Not currently possible because of the use of method_exists() in AuditableBehavior::afterSave(), which doesn't take into account __call(). One solution might be to use is_callable() instead:

(from line 125)

if ( is_callable( array( $Model, 'currentUser' ) ) ) {
  $source = $Model->currentUser();
} else if ( is_callable( array( $Model, 'current_user' ) ) ) {
  $source = $Model->current_user();
}

cacheQueries

Shouldn't the behavior turn cacheQueries off inside _getModelData function?

_getModelData fails on models with virtual field containing related model field

I encountered the following SQL error when AuditLog tried to write the audit log for a model that has a dynamically created virtual field, which contains data from a related model:

Error: SQLSTATE[42S22]: Column not found: 1054 Unknown column 'LocationRoom.location' in 'field list'

The reduced model in question:

// In Rack model constructor

$this->virtualFields['display_name'] = sprintf(
    "CONCAT(LocationRoom.location, '.', LocationRoom.room, '.', %s.name)",
    $this->alias);
};

LocationRoom is another model.

If one has such a field as the default order, the following SQL error could occur, too:

Error: SQLSTATE[42S22]: Column not found: 1054 Unknown column 'LocationRoom.location_room' in 'order clause'

View audit Log?

Maybe I'm being totally dumb, I've got this working after a little name changing, I can see my audit logs nicely in the db, whats the best way to view these in my app and perhaps create a rollback or undo method?

Problems with the sample currentUser code

I haven't been able to get the currentUser code to work with Auth.

There were several errors using the sample code as is, here are some fixes:

  1. AppController code references $this->currentUser() which is not listed. A sample implementation is:
function currentUser() 
    {
        $result = array('id' => null);

        if ($this->Session->read('Auth.User') && $this->Auth->user('id') !== null)
        {
            $result['id'] = $this->Auth->user('id');
        }

        return $result;
    }
  1. Setting $this->data gives "Notice: Indirect modification of overloaded property" errors. Furthermore, Auth->userModel may not even be set. The first problem requires declaring the variable, and for the second I just used a constant string.
public $data = array();

....

        if( empty( $this->data['AuditLogCurrentUser'] ) ) 
        {
            $this->data['AuditLogCurrentUser'] = $this->currentUser();
        }
  1. AppModel::currentUser() must be public, not protected, or you get SQL errors.
  2. The AppModel::currentUser() sample references Auth, which is not available at that level. This is where I'm stuck -- dumping $this inside AppModel::currentUser() does not have the value I set up in the AppController. Any help here?

Auditable Behavior should not be attachable to Audit or AuditDelta models

If you attach the Auditable behavior to all models, e.g. through attaching it in AppModel, it will also be attached to the Audit and AuditDelta models.
This in return will lead to an infinite loop, which will end in an SQL error like Error: SQLSTATE[22001]: String data, right truncated: 1406 Data too long for column 'json_object' at row 1, as it tries to save the the serialized data recursivly.

This should be prevented by either make it impossible to attach the Auditable behavior to the Audit and AuditDelta models or make the relevant behavior callbacks no-ops on these models.

Auditable not firing with SaveAll

I have a User model as follows:

public $hasOne = array('Profile');
public $hasAndBelongsToMany = array('Group');

The submitted data is:

array(
    'User' => array(
        'password' => '*****',
        'id' => '',
        'group_id' => '3',
        'username' => 'foobar',
        'active' => '1',
        'reset_pw_after' => '60',
        'confirm_password' => '*****'
    ),
    'Profile' => array(
        'id' => '',
        'transl8nable_locale_id' => '2',
        'email' => '[email protected]',
        'firstname' => 'Foo',
        'lastname' => 'Bar',
        'id_type_id' => '1',
        'ident' => '23409988893'
    ),
    'Group' => array(
        'Group' => array()
    )
)

And the SQL log from DebugKit is like this:

1.  SELECT COUNT(*) AS `count` FROM `database`.`users` AS `User` WHERE `User`.`username` = 'foobar'
2.  SELECT COUNT(*) AS `count` FROM `database`.`profiles` AS `Profile` WHERE `Profile`.`email` = '[email protected]'
3.  BEGIN
4.  SELECT `User`.`id` FROM `database`.`users` AS `User` WHERE 1 = 1 ORDER BY `User`.`id` DESC LIMIT
5.  INSERT INTO `database`.`authable_acls` (`model`, `foreign_id`, `acl`, `id`) VALUES ('User', 9, NULL, '50ab13aa-ddcc-99bf-01b2-048cc1e0ba83')
6.  INSERT INTO `database`.`users` (`group_id`, `username`, `active`, `reset_pw_after`, `password`, `modified`, `created`) VALUES (3, 'foobar', '1', 60, 'a$P7hSzS8kPYPvLkZXy2I81.m4tte9/C.bndS/66R3ZErfUVrMh7yDW', '2012-11-20 02:22:50', '2012-11-20 02:22:50') 
7.  SELECT `GroupsUser`.`group_id` FROM `database`.`groups_users` AS `GroupsUser` WHERE `GroupsUser`.`user_id` = 9
8.  INSERT INTO `database`.`profiles` (`user_id`, `transl8nable_locale_id`, `email`, `firstname`, `lastname`, `id_type_id`, `ident`, `modified`, `created`) VALUES (9, 2, '[email protected]', 'Foo', 'Bar', 1, '23409988893', '2012-11-20 02:22:50', '2012-11-20 02:22:50')
9.  COMMIT

There actually is an associated behavior that adds an entry into a polymorphic table (SQL statement 5) before the User model is actually saved via this statement:

$this->User->saveAll($this->request->data, array('callbacks' => 'before'))

where the callback is for that other behavior.

As you can see, Auditable is never called.

I tried placing 'AuditLog.Auditable' before and after that behavior in $actsAs with no success.

Any ideas?

Document the event callbacks

The event callbacks such as:

  • afterAuditCreate
  • afterAuditUpdate
  • afterAuditProperty

are currently not documented.

Get related models within same audit

Hi

I am using this nice plugin on several models, one of them (users) is related to some others via hasOne (e.g. profiles). Each related model has the plugin attached and everything works nicely together. On saving associated data through the main model AuditLog creates logs for each model like expected.

So, I would like to build an interface to revert back to a previous state on a given time through the main model (users). But unfortunatley each "related" entry in the audits-table exists on its own (profiles).

Of course I could knock everthing together manually, but there must be an easy way to get an audit with all related data. Has anyone done this before? Any suggestions?

Thanks,
Frank

Undefined index notice on nested call

My situation:

Rack hasMany RackUnit (fully pedendent)
RackUnit belongsTo Reservation (optionally)

Deleting a Rack, deletes all its RackUnit.
If one of those RackUnit belongTo a Reservation, that Reservation will be deleted, too.
If a Reservation gets deleted, another behavior will unset (means updated, not deleted) all reserved RackUnit.

This leads to a nested call stack, which in turn leads to a Undefined index: RackUnit notice.

The simplified call stack is:

  1. beforeDelete() RackUnit 123
    • Sets the original data for RackUnit 123
  2. delete() Reservation ABC
  3. Update RackUnit 123
  4. beforeSave() RackUnit 123
    • Overwrites the original data for RackUnit 123 (still same content)
  5. afterSave() RackUnit 123
    • Unsets the original data for RackUnit 123
  6. afterDelete() RackUnit 123
    • Original data for RackUnit 123 is missing!

I see two workarounds an one solution.

  1. Workaround 1: Do not unset the original data, which means the original data stacks up. Is this a problem?
  2. Workaround 2: Return empty arrray, if key is not set, which is a silent error
  3. Solution: Implement a pushable/popable stack of original data.

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.