09.24 php saved
ian
Tags add more
audit and behavior  
Note
A first attempt at reasonably generic "audit" behaviour that tracks changes to database fields.

To use, set $this->auditable = array('field_to_be_audited'); in the model
  1. <?php
  2.  
  3. /**
  4. *   Tracks changes made to fields of existing records
  5. */
  6.  
  7. uses('Sanitize');
  8. uses('cake_log');
  9.  
  10. class AuditBehavior extends ModelBehavior {     
  11.  
  12.     /**
  13.      * Data before the save was made
  14.      * @var array
  15.      */
  16.     var $before_save_data = array();
  17.  
  18.     /**
  19.      * Data as it will look after the save is made
  20.      * @var array
  21.      */
  22.     var $after_save_data = array();
  23.  
  24.     /**
  25.      * Changed data that must be stored to the associated audit table
  26.      * @var array
  27.      */
  28.     var $changed_data = array();
  29.  
  30. /**
  31. *   initialize - nothing at the moment
  32. */
  33.     function setup( &$model ) {
  34.     }
  35.  
  36.  
  37. /**
  38. *   Check that the model:
  39. *   Has any auditable fields at all
  40. *   Is having an existing record edited (ignore new records completely)
  41. *   Has an associated audits table (ignore those without completely)
  42. *
  43. *   Array diffs to get changed data. If save is successful then stores those changes
  44. */
  45.     function beforeSave( &$model ) {
  46.         if(!isset($model->auditable) || empty($model->auditable)) {
  47.             return true;
  48.         }
  49.  
  50.         if(!isset($model->id) || empty($model->id)) {
  51.             return true;
  52.         }
  53.  
  54.         $this->before_save_data = $model->findById($model->id);  // read populates $model->data which then screws up the save, so just don't use it!
  55.         $this->after_save_data = $model->data;
  56.  
  57.         $this->changed_data[$model->name] = Set::diff($this->after_save_data[$model->name], $this->before_save_data[$model->name]);
  58.     }
  59.  
  60.  
  61. /**
  62. *   If there are changes to the underlying data for an auditable field then stores those changes to the audit table
  63. *
  64. */
  65.     function afterSave( &$model ) {
  66.         if(!empty($this->changed_data[$model->name])) {
  67.             $data = array();
  68.             foreach($this->changed_data[$model->name] as $k => $v) {
  69.                 // check that the field is auditable
  70.                 if(!in_array($k, array_values($model->auditable))) {
  71.                     continue;
  72.                 }
  73.  
  74.                 $data['Audit'] = aa(    'model', low($model->name),
  75.                                         'model_id', $model->id,       'changed_by_id', $this->_returnUserId(),    'changed_by_model', $this->_returnUserType(),
  76.     'field_name', $k,                     'before_value', $this->before_save_data[$model->name][$k],  'after_value', $v,                     'created', date('Y-m-d H:i:s'),                        'modified', date('Y-m-d H:i:s'));
  77.  
  78.     loadModel('Audit');
  79.     if (!ClassRegistry::isKeySet('Audit')) {                  CakeLog::write('audit_behavior', 'Failed to load the audit model');
  80.     } else {
  81.       $Audit =& ClassRegistry::getObject('Audit');
  82.     }
  83.  
  84.                 if(!$Audit->create() || !$Audit->save($data)) {
  85.                     CakeLog::write('audit_behavior', 'auditable changes failed to save - changes were ' . serialize($data));
  86.                 }
  87.             }
  88.         }
  89.         return true;
  90.     }
  91.  
  92.  
  93.  
  94. /**
  95. *   Returns the ID of the person or account making the change. OthAuth specific method
  96. *   @return integer
  97. */
  98.     function _returnUserId() {
  99.         if(Set::check($_SESSION['othAuth'][AUTH_SESSION_KEY], 'User')) {
  100.             return Set::extract($_SESSION['othAuth'][AUTH_SESSION_KEY], 'User.id');
  101.         } else {
  102.             return Set::extract($_SESSION['othAuth'][AUTH_SESSION_KEY], 'Account.id');
  103.         }
  104.     }
  105.  
  106.  
  107.  
  108. /**
  109. *   Returns the type of personmaking the change. OthAuth specific method
  110. *   @return string, either user or account
  111. */
  112.     function _returnUserType() {
  113.         if(Set::check($_SESSION['othAuth'][AUTH_SESSION_KEY], 'User')) {
  114.             return 'user';
  115.         } else {
  116.             return 'account';
  117.         }   
  118.     }
  119. }
  120. ?>
  121.  
Parsed in 0.161 seconds, using GeSHi 1.0.7.14

Modify this Paste