Overview

Namespaces

  • Cron
  • None

Classes

  • _HtmlGrid_TableOut
  • _TransactionModel_RawSaveOperation
  • AccessControlComponent
  • AccessControlHelper
  • ActionListHelper
  • ActiveDirectoryUtils
  • AddCurrentPidToSchedulingShellCallLogs
  • AnonymousFunctionOperation
  • ArrayUtil
  • AssociationIntegrityBehavior
  • AtomicOperation
  • AuthenticationComponent
  • AuthenticationController
  • AuthenticationUser
  • AutocompleteDatasourceComponent
  • BaseModelComponent
  • Basics
  • CakeLayersHelper
  • CheckAndRunShell
  • ClassSearcher
  • CommandLineUtil
  • CommonValidationBehavior
  • ConfigurableShellCallsSchedulingTask
  • ConfigurationKey
  • ConfigurationKeys
  • ConfigurationKeysController
  • Context
  • ContextComponent
  • ContextHelper
  • Contexts
  • ControllerInspector
  • ControllerMenuHelper
  • CreateJournalingTables
  • CreateTableConfigurationKeys
  • CreateTableSchedulingConfigurableShellCalls
  • CreateTableSchedulingShellCallLogs
  • CreateTableSettedConfigurationKeys
  • CreateTableUserResetPasswordRequests
  • CreateTableUsers
  • CronSchedulingInstaller
  • CronValidationBehavior
  • CssBox
  • CssController
  • CssProperties
  • CssShell
  • CsvUtil
  • CustomDataModel
  • DatasourceDumperManager
  • DateTimeInput
  • DependencyShell
  • DetailHelper
  • DumperShell
  • ExtendedFieldsAccessControl
  • ExtendedFieldSet
  • ExtendedFieldSetHelper
  • ExtendedFieldsParser
  • ExtendedFormHelper
  • ExtendedHasManyAppModel
  • ExtendedOperationsBehavior
  • FieldDefinition
  • FieldRowDefinition
  • FieldSetDefinition
  • FieldSetLayoutHelper
  • FileOperations
  • FileOperations_Rename
  • FileOperations_SymLink
  • FileOperations_Touch
  • FileOperations_Unlink
  • FileSystem
  • FixConfigurationKeysPrimaryKey
  • FixSettedConfigurationKeysPrimaryKey
  • HasManyUtilsBehavior
  • HtmlDocument
  • HtmlGrid
  • HtmlGrid_Cell
  • HttpClient
  • HttpResponse
  • ImapClient
  • ImapMailBox
  • ImapParserShell
  • IncludePath
  • InputMasked
  • InputSearchable
  • InputsOnSubmit
  • InstallShell
  • JenkinsBuildShell
  • Journal
  • JournalDetail
  • JournalizedBehavior
  • JsonResponseComponent
  • LayoutsHelper
  • Ldap
  • LdapUtils
  • ListFieldSet
  • ListFieldSetHelper
  • ListsHelper
  • MailParser
  • Make
  • MenuHelper
  • MigrationAllPluginsShell
  • ModelOperations
  • ModelOperations_Delete
  • ModelOperations_Save
  • ModelTraverser
  • MysqlDumper
  • OpenLdapUtils
  • PaginatorUtilComponent
  • PaginatorUtilComponentFilter
  • PaginatorUtilHelper
  • Plugin
  • PluginManager
  • Reflections
  • RenameEnabledToActiveFromUsersTable
  • RunShellCallShell
  • ScaffoldUtilComponent
  • ScaffoldUtilHelper
  • Scheduling
  • SchedulingConfigurableShellCall
  • SchedulingConfigurableShellCallsController
  • SchedulingShellCallLog
  • SchedulingShellCallLogsController
  • SettedConfigurationKey
  • StuffreposPluginsRename
  • TimeZoneBehavior
  • TransactionModel
  • TransactionOperation
  • Translator
  • TranslatorShell
  • User
  • UserAuthenticationComponent
  • UserChangePassword
  • UserResetPassword
  • UserResetPasswordRequest
  • UserResetPasswordRequestSubmission
  • UsersController
  • ViewUtilHelper

Interfaces

  • AccessControlFilter
  • CommitableOperation
  • DatasourceDumper
  • MakeListener
  • SchedulingInstaller
  • TasksObject
  • UndoableOperation

Exceptions

  • LdapObjectNotWritableException
  • ModelTraverserException
  • Overview
  • Namespace
  • Class
  • Tree
  1: <?php
  2: 
  3: App::import('Lib', 'StuffreposBase.ArrayUtil');
  4: 
  5: class JournalizedBehavior extends ModelBehavior {
  6: 
  7:     private $rowsBeforeSave = array();
  8: 
  9:     public function setup(\Model $model, $config = array()) {
 10:         parent::setup($model, $config);
 11:         $model->bindModel(
 12:             array(
 13:                 'hasMany' => array(
 14:                     'Journal' => array(
 15:                         'className' => 'Journaling.Journal',
 16:                         'foreignKey' => 'journalized_id',
 17:                         'conditions' => array(
 18:                             'Journal.journalized_type' => $model->name
 19:                         ),
 20:                         'dependent' => false,
 21:                     )
 22:                 )
 23:             ),
 24:             false
 25:         );
 26:     }
 27: 
 28:     public function beforeSave(\Model $model, $options = array()) {
 29:         if (!parent::beforeSave($model)) {
 30:             return false;
 31:         }
 32: 
 33:         $this->storeRowPreviousValues($model);
 34:     }
 35: 
 36:     public function afterSave(\Model $model, $created, $options = array()) {
 37:         if (!parent::afterSave($model, $created, $options)) {
 38:             return false;
 39:         }
 40: 
 41:         if ($created) {
 42:             return $this->createJournal(
 43:                     $model
 44:                     , 'create'
 45:                     , $this->emptyFields($model)
 46:                     , $model->data
 47:             );
 48:         } else {
 49:             return $this->createJournal(
 50:                     $model
 51:                     , 'update'
 52:                     , $this->rowBeforeSave($model)
 53:                     , $model->data
 54:             );
 55:         }
 56:     }
 57: 
 58:     public function beforeDelete(\Model $model, $cascade = true) {
 59:         if (!parent::beforeDelete($model, $cascade)) {
 60:             return false;
 61:         }
 62: 
 63:         $this->storeRowPreviousValues($model);
 64:     }
 65: 
 66:     public function afterDelete(\Model $model) {
 67:         parent::afterDelete($model);
 68: 
 69:         return $this->createJournal(
 70:                 $model
 71:                 , 'delete'
 72:                 , $this->rowBeforeSave($model)
 73:                 , $this->emptyFields($model)
 74:         );
 75:     }
 76: 
 77:     private function rowBeforeSave(Model $model) {
 78:         if ($this->primaryKeyValue($model, false)) {
 79:             $path = array($model->name, $this->primaryKeyValue($model));
 80: 
 81:             if (ArrayUtil::hasArrayIndex($this->rowsBeforeSave, $path)) {
 82:                 return ArrayUtil::arrayIndex($this->rowsBeforeSave, $path);
 83:             } else {
 84:                 throw new Exception(
 85:                     "Previous value not found. " . print_r(array(
 86:                         'modelName' => $model->name,
 87:                         'modelAlias' => $model->alias,
 88:                         'rowsBeforeSave' => $this->rowsBeforeSave,
 89:                         'primaryKeyValue' => $this->primaryKeyValue($model),
 90:                         'path' => $path
 91:                         ), true));
 92:             }
 93:         } else {
 94:             throw new Exception("No primary key found. {$model->alias}: {$model->name}.");
 95:         }
 96:     }
 97: 
 98:     private function storeRowPreviousValues(Model $model) {
 99:         if ($this->primaryKeyValue($model, false)) {
100:             $row = $model->find('first', array(
101:                 'conditions' => array(
102:                     "{$model->alias}.{$model->primaryKey}" => $this->primaryKeyValue($model),
103:                 )
104:                 ));
105: 
106:             if (!$row) {
107:                 throw new Exception("Row not found.");
108:             }
109: 
110:             $this->rowsBeforeSave[$model->name][$this->primaryKeyValue($model)] =
111:                 $row;
112:         }
113:     }
114: 
115:     private function primaryKeyValue(Model $model, $required = true) {
116:         if (!empty($model->data[$model->alias][$model->primaryKey])) {
117:             return $model->data[$model->alias][$model->primaryKey];
118:         } else if (!empty($model->id)) {
119:             return $model->id;
120:         } else if ($required) {
121:             throw new Exception("{$model->alias} has no primary key current value.");
122:         } else {
123:             return null;
124:         }
125:     }
126: 
127:     /**
128:      * 
129:      * @param Model $model
130:      * @param string $type
131:      * @param array $oldValues
132:      * @param array $values
133:      * @return boolean
134:      * @throws Exception
135:      */
136:     private function createJournal(Model $model, $type, $oldValues, $values) {
137:         $diffValues = $this->diffValues($model, $oldValues, $values);
138: 
139:         if ($type == 'update' && empty($diffValues)) {
140:             return true;
141:         }
142: 
143:         $model->Journal->create();
144:         if (!$model->Journal->save(array(
145:                 'Journal' => array(
146:                     'type' => $type,
147:                     'journalized_type' => $model->name,
148:                     'journalized_id' => $model->id,
149:                 )
150:             ))) {
151:             throw new Exception("Could not save Journal. " . print_r($model->Journal->validationErrors, true));
152:         }
153: 
154:         foreach ($diffValues as $field => $change) {
155:             $model->Journal->JournalDetail->create();
156:             if (!$model->Journal->JournalDetail->save(array(
157:                     'JournalDetail' => array(
158:                         'property' => $field,
159:                         'old_value' => $change['old'],
160:                         'value' => $change['current'],
161:                         'journal_id' => $model->Journal->id,
162:                     )
163:                 ))) {
164:                 throw new Exception("Could not save JournalDetail. " . print_r($model->Journal->JournalDetail->validationErrors, true));
165:             }
166:         }
167: 
168:         return true;
169:     }
170: 
171:     public function diffValues(Model $model, $oldValues, $values) {
172:         $changedFields = array();
173: 
174:         foreach ($this->journalizedFields($model) as $field) {
175:             $index = array($model->alias, $field);
176:             $old = ArrayUtil::hasArrayIndex($oldValues, $index) ?
177:                 ArrayUtil::arrayIndex($oldValues, $index) :
178:                 null;
179:             $current = ArrayUtil::hasArrayIndex($values, $index) ?
180:                 ArrayUtil::arrayIndex($values, $index) :
181:                 $old;
182: 
183:             if ($old === null && $current === null) {
184:                 $changed = false;
185:             } else if ($old === null || $current === null) {
186:                 $changed = true;
187:             } else {
188:                 $changed = $old != $current;
189:             }
190: 
191:             if ($changed) {
192:                 $changedFields[$field] = compact('old', 'current');
193:             }
194:         }
195: 
196:         return $changedFields;
197:     }
198: 
199:     public function emptyFields(Model $model) {
200:         $fields = array();
201: 
202:         foreach ($this->journalizedFields($model) as $field) {
203:             $fields[$field] = null;
204:         }
205: 
206:         return array(
207:             $model->alias => $fields
208:         );
209:     }
210: 
211:     private function journalizedFields(Model $model) {
212:         $fields = array();
213:         foreach (array_keys($model->schema()) as $field) {
214:             switch ($field) {
215:                 case $model->primaryKey:
216:                 case 'created':
217:                 case 'modified':
218:                 case 'updated':
219:                     continue;
220: 
221:                 default:
222:                     $fields[] = $field;
223:             }
224:         }
225:         return $fields;
226:     }
227: 
228: }
API documentation generated by ApiGen 2.8.0