Overview

Packages

  • application
    • commands
    • components
      • actions
      • filters
      • leftWidget
      • permissions
      • sortableWidget
      • util
      • webupdater
      • x2flow
        • actions
        • triggers
      • X2GridView
      • X2Settings
    • controllers
    • models
      • embedded
    • modules
      • accounts
        • controllers
        • models
      • actions
        • controllers
        • models
      • calendar
        • controllers
        • models
      • charts
        • models
      • contacts
        • controllers
        • models
      • docs
        • components
        • controllers
        • models
      • groups
        • controllers
        • models
      • marketing
        • components
        • controllers
        • models
      • media
        • controllers
        • models
      • mobile
        • components
      • opportunities
        • controllers
        • models
      • products
        • controllers
        • models
      • quotes
        • controllers
        • models
      • services
        • controllers
        • models
      • template
        • models
      • users
        • controllers
        • models
      • workflow
        • controllers
        • models
      • x2Leads
        • controllers
        • models
  • None
  • system
    • base
    • caching
    • console
    • db
      • ar
      • schema
    • validators
    • web
      • actions
      • auth
      • helpers
      • widgets
        • captcha
        • pagers
  • zii
    • widgets
      • grid

Classes

  • AccountsGridViewProfileWidget
  • ActionMenu
  • ActionsGridViewProfileWidget
  • ActionsQuickCreateRelationshipBehavior
  • ActiveDateRangeInput
  • ApplicationConfigBehavior
  • Attachments
  • ChatBox
  • CommonControllerBehavior
  • ContactMapInlineTags
  • ContactsGridViewProfileWidget
  • CronForm
  • CSaveRelationsBehavior
  • DateRangeInputsWidget
  • DocsGridViewProfileWidget
  • DocViewer
  • DocViewerProfileWidget
  • EButtonColumnWithClearFilters
  • EmailDeliveryBehavior
  • EmailProgressControl
  • EncryptedFieldsBehavior
  • EventsChartProfileWidget
  • FileUploader
  • FontPickerInput
  • Formatter
  • FormView
  • GridViewWidget
  • History
  • IframeWidget
  • ImportExportBehavior
  • InlineActionForm
  • InlineEmailAction
  • InlineEmailForm
  • InlineEmailModelBehavior
  • InlineQuotes
  • JSONEmbeddedModelFieldsBehavior
  • JSONFieldsDefaultValuesBehavior
  • LeadRoutingBehavior
  • LeftWidget
  • LoginThemeHelper
  • LoginThemeHelperBase
  • MarketingGridViewProfileWidget
  • MediaBox
  • MessageBox
  • MobileFormatter
  • MobileFormLayoutRenderer
  • MobileLayoutRenderer
  • MobileLoginThemeHelper
  • MobileViewLayoutRenderer
  • ModelFileUploader
  • NewWebLeadsGridViewProfileWidget
  • NormalizedJSONFieldsBehavior
  • NoteBox
  • OnlineUsers
  • OpportunitiesGridViewProfileWidget
  • Panel
  • ProfileDashboardManager
  • ProfileGridViewWidget
  • ProfileLayoutEditor
  • ProfilesGridViewProfileWidget
  • Publisher
  • PublisherActionTab
  • PublisherCalendarEventTab
  • PublisherCallTab
  • PublisherCommentTab
  • PublisherEventTab
  • PublisherSmallCalendarEventTab
  • PublisherTab
  • PublisherTimeTab
  • QuickContact
  • QuickCreateRelationshipBehavior
  • QuotesGridViewProfileWidget
  • RecordAliasesWidget
  • RecordViewLayoutManager
  • RecordViewWidgetManager
  • RememberPagination
  • Reminders
  • ResponseBehavior
  • ResponsiveHtml
  • SearchIndexBehavior
  • ServicesGridViewProfileWidget
  • SmallCalendar
  • SmartActiveDataProvider
  • SmartDataProviderBehavior
  • SmartSort
  • SocialForm
  • SortableWidgetManager
  • SortableWidgets
  • TagBehavior
  • TagCloud
  • TemplatesGridViewProfileWidget
  • TimeZone
  • TopContacts
  • TopSites
  • TransformedFieldStorageBehavior
  • TranslationLogger
  • TwitterFeed
  • TwoColumnSortableWidgetManager
  • UpdaterBehavior
  • UpdatesForm
  • UserIdentity
  • UsersChartProfileWidget
  • WorkflowBehavior
  • X2ActiveGridView
  • X2ActiveGridViewForSortableWidgets
  • X2AssetManager
  • X2AuthManager
  • X2ChangeLogBehavior
  • X2ClientScript
  • X2Color
  • X2DateUtil
  • X2FixtureManager
  • X2FlowFormatter
  • X2GridView
  • X2GridViewBase
  • X2GridViewForSortableWidgets
  • X2GridViewSortableWidgetsBehavior
  • X2LeadsGridViewProfileWidget
  • X2LinkableBehavior
  • X2ListView
  • X2PillBox
  • X2ProgressBar
  • X2SmartSearchModelBehavior
  • X2TimestampBehavior
  • X2TranslationBehavior
  • X2UrlRule
  • X2WebModule
  • X2Widget
  • X2WidgetList
  • Overview
  • Package
  • Class
  • Tree
  1: <?php
  2: /*****************************************************************************************
  3:  * X2Engine Open Source Edition is a customer relationship management program developed by
  4:  * X2Engine, Inc. Copyright (C) 2011-2016 X2Engine Inc.
  5:  * 
  6:  * This program is free software; you can redistribute it and/or modify it under
  7:  * the terms of the GNU Affero General Public License version 3 as published by the
  8:  * Free Software Foundation with the addition of the following permission added
  9:  * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK
 10:  * IN WHICH THE COPYRIGHT IS OWNED BY X2ENGINE, X2ENGINE DISCLAIMS THE WARRANTY
 11:  * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
 12:  * 
 13:  * This program is distributed in the hope that it will be useful, but WITHOUT
 14:  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 15:  * FOR A PARTICULAR PURPOSE.  See the GNU Affero General Public License for more
 16:  * details.
 17:  * 
 18:  * You should have received a copy of the GNU Affero General Public License along with
 19:  * this program; if not, see http://www.gnu.org/licenses or write to the Free
 20:  * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 21:  * 02110-1301 USA.
 22:  * 
 23:  * You can contact X2Engine, Inc. P.O. Box 66752, Scotts Valley,
 24:  * California 95067, USA. or at email address contact@x2engine.com.
 25:  * 
 26:  * The interactive user interfaces in modified source and object code versions
 27:  * of this program must display Appropriate Legal Notices, as required under
 28:  * Section 5 of the GNU Affero General Public License version 3.
 29:  * 
 30:  * In accordance with Section 7(b) of the GNU Affero General Public License version 3,
 31:  * these Appropriate Legal Notices must retain the display of the "Powered by
 32:  * X2Engine" logo. If the display of the logo is not reasonably feasible for
 33:  * technical reasons, the Appropriate Legal Notices must display the words
 34:  * "Powered by X2Engine".
 35:  *****************************************************************************************/
 36: 
 37: /**
 38:  * Changelog recording behavior class.
 39:  *
 40:  * X2ChangeLogBehavior is a CActiveRecordBehavior which automatically saves changelog
 41:  * data when a record is saved. It also looks up any applicable notification criteria
 42:  * and takes the appropriate action (create a notification, create a new action,
 43:  * reassign the record, etc.)
 44:  *
 45:  * @package application.components
 46:  * @property string $autoCompleteSource The action to user for autocomplete data
 47:  * @property string $baseRoute The default module/controller this model "belongs" to
 48:  * @property string $editingUsername Username of the user who is performing the save operation.
 49:  * @property string $viewRoute The default action to view this model
 50:  */
 51: class X2ChangeLogBehavior extends CActiveRecordBehavior  {
 52: 
 53:     public function events() {
 54:         return array_merge(parent::events(),array(
 55:             'onAfterCreate'=>'afterCreate',
 56:             'onAfterUpdate'=>'afterUpdate',
 57:         ));
 58:     }
 59: 
 60:     private $_editingUsername;
 61:     public $createEvent = true;
 62:     protected $validated = false;
 63: 
 64:     /**
 65:      * Magic getter for {@link editingUsername} that returns a username regardless of context.
 66:      *
 67:      * {@link editingUsername} should be used in place of Yii::app()->user->name
 68:      * in order for X2Model to work in console commands and API calls (where
 69:      * there is no user session).
 70:      *
 71:      * @return type
 72:      */
 73:     public function getEditingUsername() {
 74:         if (!isset($this->_editingUsername))
 75:             $this->_editingUsername = Yii::app()->getSuName();
 76:         return $this->_editingUsername;
 77:     }
 78: 
 79:     /**
 80:      * Sets username fields of a model
 81:      */
 82:     public static function usernameFieldsSet(CActiveRecord $model,$username){
 83:         if($model->hasAttribute('updatedBy')){
 84:             $model->updatedBy = $username;
 85:         }
 86:         if($model->hasAttribute('createdBy') && $model->isNewRecord)
 87:             $model->createdBy = $username;
 88:     }
 89: 
 90:     public function beforeSave($event){
 91:         $model=$this->getOwner();
 92:         self::usernameFieldsSet($model,$this->editingUsername);
 93:         return parent::beforeSave($event);
 94:     }
 95: 
 96:     public function afterCreate($event) {
 97: 
 98:         $model = $this->getOwner();
 99: 
100:         //$api = 0;    // FIX THIS
101: 
102:         if($this->createEvent){
103:             $event = new Events;
104:             $event->visibility = $model->hasAttribute('visibility')? $model->visibility : 1;
105:             $event->associationType = get_class($model);
106:             $event->associationId = $model->id;
107:             $event->user = $this->editingUsername;
108:             $event->type = 'record_create';
109:             
110:             // Event creation already handled by web lead.
111:             // if(!$model instanceof Contacts || $api==0) 
112: 
113:             $event->save();
114:         }
115: 
116:         if($model->hasAttribute('assignedTo')) {
117:             if(!empty($model->assignedTo) && $model->assignedTo != $this->editingUsername && 
118:                 $model->assignedTo != 'Anyone') {
119: 
120:                 $notif = new Notification;
121:                 $notif->user = $model->assignedTo;
122:                 //$notif->createdBy = ($api == 1) ? 'API' : $this->editingUsername;
123:                 $notif->createdBy = $this->editingUsername;
124:                 $notif->createDate = time();
125:                 $notif->type = 'create';
126:                 $notif->modelType = get_class($model);
127:                 $notif->modelId = $model->id;
128:                 $notif->save();
129:             }
130:         }
131:     }
132: 
133:     /**
134:      * Marks the record as validated, so we know somebody called CActiveRecord::save() rather than CActiveRecord::update() on it
135:      */
136:     public function afterValidate($event) {
137:         $this->validated = true;
138:     }
139: 
140:     /**
141:      * Triggers record_updated, runs changelog calculations and checks notification criteria (soon to be removed)
142:      */
143:     public function afterUpdate($event) {
144:         if($this->validated) {
145:             $changes = $this->getChanges();
146:             $this->updateChangelog($changes);
147:         }
148:         $this->validated = false;    // reset in case CActiveRecord::update() is called after CActiveRecord::save()
149:     }
150: 
151:     /**
152:      * Logs the deletion of the model
153:      */
154:     public function afterDelete($event) {
155:         $modelClass = get_class($this->getOwner());
156:         if($modelClass === 'Actions' && $this->getOwner()->workflowId !== null)        // no deletion events for workflow actions, that's somebody else's problem
157:             return;
158:         if($this->createEvent){
159:             $event = new Events();
160:             $event->type='record_deleted';
161:             $event->associationType = $modelClass;
162:             $event->associationId = $this->getOwner()->id;
163:             if($this->getOwner()->hasAttribute('visibility')){
164:                 $event->visibility=$this->getOwner()->visibility;
165:             }
166:             $event->text = $this->getOwner()->name;
167:             $event->user = $this->editingUsername;
168:             $event->save();
169:         }
170: 
171:         $log = new Changelog;
172:         $log->type = $modelClass;
173:         $log->itemId = $this->getOwner()->id;
174:         $log->recordName = $this->getOwner()->name;
175:         $log->changed = 'delete';
176: 
177:         $log->changedBy = $this->editingUsername;
178:         $log->timestamp = time();
179: 
180:         $log->save();
181: 
182:         X2Flow::trigger('RecordDeleteTrigger',array(
183:             'model'=>$this->getOwner()
184:         ));
185:     }
186: 
187:     /**
188:      * Finds attributes that were changed and generates an array of changes.
189:      *
190:      * @return array a 2-dimensional array of changes, with the format $fieldName => array($old,$new)
191:      */
192:     public function getChanges() {
193:         $changes = array();
194: 
195:         // $this->_oldAttributes
196:         $oldAttributes = $this->getOwner()->getOldAttributes();
197:         $newAttributes = $this->getOwner()->getAttributes();
198: 
199:         // compare old and new
200:         foreach($newAttributes as $fieldName => $new) {
201:             if(isset($oldAttributes[$fieldName])) {
202:                 $old = $oldAttributes[$fieldName];
203:                 if(is_array($old))
204:                     $old = implode(', ',$old);    // convert arrays to a string with commas in it (for example multiple assignedTo)
205: 
206:                 if($new != $old)
207:                     $changes[$fieldName] = array($old,$new);
208:             }elseif(!is_null($new)){
209:                 $changes[$fieldName]=array(null,$new);
210:             }
211:         }
212: 
213:         return $changes;
214:     }
215: 
216: 
217: /*     public function writeChangelog($changes) {
218:         for($i=0;$i<count($changes); $i++) {
219:             $old = &$changes[$i][0];
220:             $new = &$changes[$i][1];
221: 
222:             if($new != $old) {
223:                 $log = new Changelog;
224:                 $log->type = get_class($this->getOwner());
225: 
226:                 $log->itemId = $this->getOwner()->id;
227:                 $log->changedBy = $this->editingUsername;
228:                 $log->fieldName = $field;
229:                 // $log->oldValue = $old;
230:                 $log->timestamp = time();
231: 
232:                 if(empty($old)) {
233:                     $log->diff = false;
234:                     $log->newValue = $new;
235:                 } else {
236:                     $diff = FineDiff::getDiffOpcodes($old,$new,FineDiff::$wordGranularity);
237: 
238:                     $log->diff = strlen($diff) > strlen($old);
239:                     $log->newValue = $log->diff? $diff : $new;
240:                 }
241: 
242:                 $log->save();
243:             }
244:         }
245:     } */
246: 
247:     /**
248:      * Writes field changes to the changelog. Calls {@link checkNotificationCriteria()} for each change
249:      * @param array $changes the changes array, calls {@link getChanges()} if not provided
250:      */
251:     public function updateChangelog($changes = null) {
252:         $model = $this->getOwner();
253: 
254:         if($changes === null)
255:             $changes = $this->getChanges();
256: 
257:         // $model->lastUpdated = time();
258:         // $model->updatedBy = Yii::app()->user->getName();
259:         // $model->save();
260:         $type = get_class($model);
261: 
262:         // Handle special types
263:         $pluralize = array('Quote', 'Product');
264:         if (in_array($type, $pluralize))
265:             $type .= "s";
266:         else if ($type == 'Campaign')
267:             $type = "Marketing";
268:         else if ($type == 'bugreports')
269:             $type = 'BugReports';
270: 
271:         $excludeFields=array(
272:             'lastUpdated',
273:             'createDate',
274:             'lastActivity',
275:             'updatedBy',
276:             'trackingKey',
277:         );
278:         if(is_array($changes)) {
279: 
280:             foreach($changes as $fieldName => $change){
281:                 if(!in_array($fieldName,$excludeFields)){
282:                     $changelog = new Changelog;
283:                     $changelog->type = $type;
284:                     if (!isset($model->id)) {
285:                         if ($model->save()) {
286: 
287:                         }
288:                     }
289:                     $changelog->itemId = $model->id;
290:                     if ($model->hasAttribute('name')) {
291:                         $changelog->recordName=$model->name;
292:                     } else {
293:                         $changelog->recordName=$type;
294:                     }
295:                     $changelog->changedBy = $this->editingUsername;
296:                     $changelog->fieldName = $fieldName;
297:                     $changelog->oldValue = $change[0];
298:                     $changelog->newValue = $change[1];
299:                     $changelog->timestamp = time();
300: 
301:                     $changelog->save();
302: 
303:                     $this->checkNotificationCriteria($fieldName,$change[0],$change[1]);
304:                 }
305:             }
306:         }
307:         // } elseif($changes == 'Create' || $changes == 'Edited') {
308:             // if($model instanceof Contacts)
309:                 // $change = $model->backgroundInfo;
310:             // else if($model instanceof Actions)
311:                 // $change = $model->actionDescription;
312:             // else if($model instanceof Docs)
313:                 // $change = $model->text;
314:             // else
315:                 // $change = $model->name;
316:         // } elseif($changes != '' && $changes != 'Completed') {
317:             // $pieces = explode("<br />", $change);
318:             // foreach($pieces as $piece) {
319:                 // $newPieces = explode("TO:", $piece);
320:                 // $forDeletion = $newPieces[0];
321:                 // if(isset($newPieces[1]) && preg_match('/<b>' . Yii::t('actions', 'color') . '<\/b>/', $piece) == false) {
322:                     // $changes[] = $newPieces[1];
323:                 // }
324:             // }
325:         // }
326:     }
327: 
328:     /**
329:      * Looks up notification criteria in x2_criteria relevant to this model
330:      * and field and performs the specified operation.
331:      * Soon to be eliminated in wake of x2flow automation system.
332:      *
333:      * @param string $fieldName the name of the current field
334:      * @param string $old the old value
335:      * @param string $new the new value
336:      */
337:     public function checkNotificationCriteria($fieldName,$old,$new) {
338: 
339:         $model = $this->getOwner();
340:         $modelClass = get_class($model);
341: 
342:         $allCriteria = Criteria::model()->findAllByAttributes(array('modelType' => $modelClass, 'modelField' => $fieldName));
343:         foreach ($allCriteria as $criteria) {
344:             if (($criteria->comparisonOperator == "=" && $new == $criteria->modelValue)
345:                     || ($criteria->comparisonOperator == ">" && $new >= $criteria->modelValue)
346:                     || ($criteria->comparisonOperator == "<" && $new <= $criteria->modelValue)
347:                     || ($criteria->comparisonOperator == "change" && $new != $old)) {
348: 
349:                 $users = preg_split('/[\s,]+/',$criteria->users,null,PREG_SPLIT_NO_EMPTY);
350: 
351:                 if($criteria->type == 'notification') {
352:                     foreach($users as $user) {
353:                         $event=new Events;
354:                         $event->user=$user;
355:                         $event->associationType='Notification';
356:                         $event->type='notif';
357: 
358:                         $notif = new Notification;
359:                         $notif->type = 'change';
360:                         $notif->fieldName = $fieldName;
361:                         $notif->modelType = get_class($model);
362:                         $notif->modelId = $model->id;
363: 
364:                         if($criteria->comparisonOperator == 'change') {
365:                             $notif->comparison = 'change';    // if the criteria is just 'changed'
366:                             $notif->value = $new;            // record the new value
367:                         } else {
368:                             $notif->comparison = $criteria->comparisonOperator;  // otherwise record the operator type
369:                             $notif->value = mb_substr($criteria->modelValue, 0, 250, 'UTF-8'); // and the comparison value
370:                         }
371:                         $notif->user = $user;
372:                         $notif->createdBy = $this->editingUsername;
373:                         $notif->createDate = time();
374: 
375:                         if($notif->save()) {
376:                             $event->associationId = $notif->id;
377:                             $event->save();
378:                         }
379:                     }
380:                 } elseif($criteria->type == 'action') {
381:                     foreach($users as $user) {
382:                         $action = new Actions;
383:                         $action->assignedTo = $user;
384:                         if ($criteria->comparisonOperator == "=") {
385:                             $action->actionDescription = "A record of type " . $modelClass . " has been modified to meet $criteria->modelField $criteria->comparisonOperator $criteria->modelValue" . " by " . $this->editingUsername;
386:                         } else if ($criteria->comparisonOperator == ">") {
387:                             $action->actionDescription = "A record of type " . $modelClass . " has been modified to meet $criteria->modelField $criteria->comparisonOperator $criteria->modelValue" . " by " . $this->editingUsername;
388:                         } else if ($criteria->comparisonOperator == "<") {
389:                             $action->actionDescription = "A record of type " . $modelClass . " has been modified to meet $criteria->modelField $criteria->comparisonOperator $criteria->modelValue" . " by " . $this->editingUsername;
390:                         } else if ($criteria->comparisonOperator == "change") {
391:                             $action->actionDescription = "A record of type " . $modelClass . " has had its $criteria->modelField field changed from ".$old.' to '.$new.' by '.$this->editingUsername;
392:                         }
393:                         $action->dueDate = mktime('23', '59', '59');
394:                         $action->createDate = time();
395:                         $action->lastUpdated = time();
396:                         $action->updatedBy = 'admin';
397:                         $action->visibility = 1;
398:                         $action->associationType = lcfirst($modelClass);
399:                         $action->associationId = $model->id;
400:                         $action->associationName = $model->name;
401:                         $action->save();
402:                     }
403:                 } elseif ($criteria->type == 'assignment') {
404:                     $model->assignedTo = $criteria->users;
405: 
406:                     if ($model->save()) {
407:                         $event=new Events;
408:                         $event->type='notif';
409:                         $event->user=$model->assignedTo;
410:                         $event->associationType='Notification';
411: 
412:                         $notif = new Notification;
413:                         $notif->user = $model->assignedTo;
414:                         $notif->createDate = time();
415:                         $notif->type = 'assignment';
416:                         $notif->modelType = $modelClass;
417:                         $notif->modelId = $model->id;
418:                         if($notif->save()){
419:                             $event->associationId = $notif->id;
420:                             if($this->createEvent){
421:                                 $event->save();
422:                             }
423:                         }
424:                     }
425:                 }
426:             }
427:         }
428:     }
429: 
430: }
431: 
X2CRM Documentation API documentation generated by ApiGen 2.8.0