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

  • ActionFormModel
  • ArrayUtil
  • ArrayValidator
  • AssociatedMediaBehavior
  • AuxLib
  • Changelog
  • DetailView
  • EncryptUtilTmp
  • EventsWidgetFieldFormatter
  • FailedLogins
  • FieldFormatter
  • FieldFormatterBase
  • FieldInputRenderer
  • FileFieldBehavior
  • FiltersForm
  • FilterUtil
  • FineDiff
  • FineDiffCopyOp
  • FineDiffDeleteOp
  • FineDiffInsertOp
  • FineDiffOp
  • FineDiffOps
  • FineDiffReplaceOp
  • GlobalCSSFormModel
  • GlobalImportFormModel
  • GoogleAuthenticator
  • JSONFieldsBehavior
  • JSONResponse
  • MediaFieldFormatter
  • MediaSelector
  • MobileActiveRecordFieldFormatter
  • MobileActivityFeed
  • MobileChartDashboard
  • MobileFieldFormatter
  • MobileFieldInputRenderer
  • ModuleModelNameValidator
  • MultiChildNode
  • MultiTypeAutocomplete
  • PasswordUtil
  • ProductFeature
  • ProfileWidgetLayout
  • QueryParamGenerator
  • RecordLimitBehavior
  • RecordView
  • RecordViewWidgetLayout
  • RelationshipsGridModel
  • RelationshipsJoin
  • RepairUserDataCommand
  • RequestUtil
  • RequiredIfNotSetValidator
  • ResponseUtil
  • RunMigrationScriptCommand
  • ServiceWebFormDesigner
  • Settings
  • StringUtil
  • TestEmailAction
  • TestEmailActionForm
  • ThemeGenerator
  • TimerUtil
  • TopicsFieldFormatter
  • TopicsWidgetLayout
  • TransactionalViewFieldFormatter
  • UrlUtil
  • ValidLinkValidator
  • WebFormDesigner
  • WebLeadFormDesigner
  • X2ActiveRecordBehavior
  • X2ActiveRecordFieldFormatter
  • X2ButtonColumn
  • X2ConditionList
  • X2ConsoleCommand
  • X2ControllerBehavior
  • X2DataColumn
  • X2DuplicateBehavior
  • X2Flashes
  • X2GridViewFieldFormatter
  • X2IPAddress
  • X2LeadsDataColumn
  • X2MergeableBehavior
  • X2MessageSource
  • X2MobileControllerBehavior
  • X2MobileProfileControllerBehavior
  • X2MobileQuotesControllerBehavior
  • X2MobileSiteControllerBehavior
  • X2MobileTopicsControllerBehavior
  • X2ModelConversionBehavior
  • X2ModelConversionWidget
  • X2ModelForeignKeyValidator
  • X2ModelUniqueIndexValidator
  • X2NonWebUser
  • X2StaticDropdown
  • X2StaticField
  • X2StaticFieldsBehavior
  • X2UrlManager
  • X2Validator
  • X2WidgetBehavior

Interfaces

  • AdminOwnedCredentials

Exceptions

  • CampaignMailingException
  • CodeExchangeException
  • GetCredentialsException
  • NoRefreshTokenException
  • NoUserIdException
  • StringUtilException

Functions

  • checkCurrency
  • checkDNS
  • checkServerVar
  • checkTimezone
  • decodeQuotes
  • echoIcons
  • encodeQuotes
  • exceptionForError
  • getField
  • getLanguageName
  • getModuleTitle
  • handleReqError
  • handleReqException
  • installer_t
  • installer_tr
  • isAllowedDir
  • mediaMigrationRrmdir
  • migrateMediaDir
  • printGraph
  • printR
  • renderFields
  • reqShutdown
  • RIP
  • translateOptions
  • tryGetRemote
  • Overview
  • Package
  • Class
  • Tree
  1: <?php
  2: 
  3: /*****************************************************************************************
  4:  * X2Engine Open Source Edition is a customer relationship management program developed by
  5:  * X2Engine, Inc. Copyright (C) 2011-2016 X2Engine Inc.
  6:  * 
  7:  * This program is free software; you can redistribute it and/or modify it under
  8:  * the terms of the GNU Affero General Public License version 3 as published by the
  9:  * Free Software Foundation with the addition of the following permission added
 10:  * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK
 11:  * IN WHICH THE COPYRIGHT IS OWNED BY X2ENGINE, X2ENGINE DISCLAIMS THE WARRANTY
 12:  * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
 13:  * 
 14:  * This program is distributed in the hope that it will be useful, but WITHOUT
 15:  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 16:  * FOR A PARTICULAR PURPOSE.  See the GNU Affero General Public License for more
 17:  * details.
 18:  * 
 19:  * You should have received a copy of the GNU Affero General Public License along with
 20:  * this program; if not, see http://www.gnu.org/licenses or write to the Free
 21:  * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 22:  * 02110-1301 USA.
 23:  * 
 24:  * You can contact X2Engine, Inc. P.O. Box 66752, Scotts Valley,
 25:  * California 95067, USA. or at email address contact@x2engine.com.
 26:  * 
 27:  * The interactive user interfaces in modified source and object code versions
 28:  * of this program must display Appropriate Legal Notices, as required under
 29:  * Section 5 of the GNU Affero General Public License version 3.
 30:  * 
 31:  * In accordance with Section 7(b) of the GNU Affero General Public License version 3,
 32:  * these Appropriate Legal Notices must retain the display of the "Powered by
 33:  * X2Engine" logo. If the display of the logo is not reasonably feasible for
 34:  * technical reasons, the Appropriate Legal Notices must display the words
 35:  * "Powered by X2Engine".
 36:  *****************************************************************************************/
 37: 
 38: /**
 39:  * Behavior to define the set of methods necessary to merge two or more records
 40:  * into a single record. Should always be implemented on records which have
 41:  * X2DuplicateBehavior but is more general in its application.
 42:  */
 43: class X2MergeableBehavior extends CActiveRecordBehavior {
 44:     
 45:     /**
 46:      * Fields which should not be set from old records in a merge.
 47:      * @var array 
 48:      */
 49:     public $restrictedFields = array(
 50:         'id',
 51:         'nameId',
 52:     );
 53:     
 54:     
 55:     
 56:     /**
 57:      * Set the value of $this->owner->{$field->fieldName} to the merged value from
 58:      * the set of duplicates. The value will be set to the value of the duplicate
 59:      * which has a non-null value for this field and the most recent lastUpdated value.
 60:      * @param Fields $field The field object determining which field to set
 61:      * @param array $duplicates Records to set the value from
 62:      */
 63:     public function setMergedField($field, $duplicates) {
 64:         $value = null;
 65:         $oldModelId = null;
 66:         $timestamp = 0;
 67:         foreach ($duplicates as $oldModel) {
 68:             if ($field->type === 'text') {
 69:                 // Text fields should be concatenated
 70:                 if(!empty($oldModel->{$field->fieldName})){
 71:                     if (is_null($value)) {
 72:                         $value = $oldModel->{$field->fieldName};
 73:                     }else{
 74:                         $value .= "\n--\n" . $oldModel->{$field->fieldName};
 75:                     }
 76:                 }
 77:             } else if (!is_null($oldModel->{$field->fieldName}) && $oldModel->lastUpdated >= $timestamp) {
 78:                 $value = $oldModel->{$field->fieldName};
 79:                 //Store lastUpdated of the model used to set this value
 80:                 $timestamp = $oldModel->lastUpdated;
 81:                 //Maintain ID of model used to set this value in case of unique fields
 82:                 $oldModelId = $oldModel->id;
 83:             }
 84:         }
 85:         $this->owner->{$field->fieldName} = $value;
 86:         if ($field->uniqueConstraint) {
 87:             //If there is a unique constraint, we need to set the value of the model that was used to null
 88:             $tmpModel = X2Model::model(get_class($this->owner))->findByPk($oldModelId);
 89:             if($tmpModel){
 90:                 $tmpModel->{$field->fieldName} = null;
 91:                 $tmpModel->update(array($field->fieldName));
 92:             }
 93:         }
 94:     }
 95: 
 96:     /**
 97:      * Set the createDate value of $this->owner to the oldest createDate of the duplicates
 98:      * @param array $duplicates
 99:      */
100:     public function setMergedCreateDate($duplicates) {
101:         foreach ($duplicates as $oldModel) {
102:             if (!empty($oldModel->createDate) && (empty($this->owner->createDate) || $oldModel->createDate < $this->owner->createDate)) {
103:                 $this->owner->createDate = $oldModel->createDate;
104:             }
105:         }
106:     }
107: 
108:     /**
109:      * Wrapper for mergeRelatedRecords to merge each duplicate into the new record
110:      * and hide the duplicate.
111:      * @param array $duplicates Records to be merged into $this->owner
112:      * @param boolean $logMerge Whether to log merge information so it can be undone
113:      */
114:     public function massMergeRelatedRecords($duplicates, $logMerge) {
115:         foreach ($duplicates as $oldModel) {
116:             $this->owner->mergeRelatedRecords($oldModel, $logMerge);
117:             if ($oldModel->hasAttribute('visibility')) {
118:                 $oldModel->visibility = 0;
119:             }
120:             if ($oldModel->hasAttribute('assignedTo')) {
121:                 $oldModel->assignedTo = 'Anyone';
122:             }
123:             if ($oldModel->hasAttribute('doNotCall')) {
124:                 $oldModel->doNotCall = 1;
125:             }
126:             if ($oldModel->hasAttribute('doNotEmail')) {
127:                 $oldModel->doNotEmail = 1;
128:             }
129:             $oldModel->update();
130:         }
131:     }
132: 
133:     /**
134:      * Transfers all events, notifications, and actions, tags, relationships, and 
135:      * lookup fields related to the given $model to $this->owner. 
136:      */
137:     public function mergeRelatedRecords(X2Model $model, $logMerge = false) {
138: 
139:         $mergeData = array();
140:         
141:         $ret = $this->owner->mergeActions($model, $logMerge);
142:         if ($logMerge && !empty($ret)) {
143:             $mergeData['data']['actions'] = $ret;
144:         }
145:         
146:         $ret = $this->owner->mergeEvents($model, $logMerge);
147:         if ($logMerge && !empty($ret)) {
148:             $mergeData['data']['events'] = $ret;
149:         }
150:          
151:         $ret = $this->owner->mergeNotifications($model, $logMerge);
152:         if ($logMerge && !empty($ret)) {
153:             $mergeData['data']['notifications'] = $ret;
154:         }
155:             
156:         $ret = $this->owner->mergeTags($model, $logMerge);
157:         if ($logMerge && !empty($ret)) {
158:             $mergeData['data']['tags'] = $ret;
159:         }
160:         
161:         $ret = $this->owner->mergeRelationships($model, $logMerge);
162:         if ($logMerge && !empty($ret)) {
163:             $mergeData['data']['relationships'] = $ret;
164:         }
165:         
166:         $ret = $this->owner->mergeLinkFields($model, $logMerge);
167:         if ($logMerge && !empty($ret)) {
168:             $mergeData['data']['linkFields'] = $ret;
169:         }
170:         
171:         if ($logMerge) {
172:             $mergeData['assignedTo'] = $model->assignedTo;
173:             $mergeData['visibility'] = $model->visibility;
174:             Yii::app()->db->createCommand()
175:                     ->insert('x2_merge_log', array(
176:                         'modelType' => get_class($model),
177:                         'modelId' => $model->id,
178:                         'mergeModelId' => $this->owner->id,
179:                         'mergeData' => json_encode($mergeData),
180:                         'mergeDate' => time(),
181:             ));
182:         }
183:     }
184: 
185:     /**
186:      * Transfers all related Actions from $model to $this->owner
187:      */
188:     public function mergeActions(X2Model $model, $logMerge = false) {
189:         $ret = array();
190:         $associationType = X2Model::getAssociationType(get_class($model));
191:         $tartgetAssociationType = X2Model::getAssociationType(get_class($this->owner));
192:         if ($logMerge) {
193:             $ids = Yii::app()->db->createCommand()
194:                     ->select('id')
195:                     ->from('x2_actions')
196:                     ->where(
197:                             'associationType = :type AND associationId = :id', array(':type' => $associationType, ':id' => $model->id))
198:                     ->queryColumn();
199:             $ret = $ids;
200:         }
201: 
202:         X2Model::model('Actions')->updateAll(array(
203:             'associationType' => $tartgetAssociationType,
204:             'associationId' => $this->owner->id,
205:                 ), 'associationType = :type AND associationId = :id', array(
206:             ':type' => $associationType,
207:             ':id' => $model->id
208:         ));
209: 
210:         return $ret;
211:     }
212: 
213:     /**
214:      * Transfers all related Events from $model to $this->owner
215:      */
216:     public function mergeEvents(X2Model $model, $logMerge = false) {
217:         $ret = array();
218:         if ($logMerge) {
219:             $ids = Yii::app()->db->createCommand()
220:                     ->select('id')
221:                     ->from('x2_events')
222:                     ->where(
223:                             'associationType = :type AND associationId = :id', array(':type' => get_class($model), ':id' => $model->id))
224:                     ->queryColumn();
225:             $ret = $ids;
226:         }
227:         X2Model::model('Events')->updateAll(
228:                 array(
229:             'associationId' => $this->owner->id,
230:             'associationType' => get_class ($this->owner),
231:                 ), 'associationType = :type AND associationId = :id', array(':type' => get_class($model), ':id' => $model->id));
232:         return $ret;
233:     }
234: 
235:     /**
236:      * Transfers all related Notifications from $model to $this->owner
237:      */
238:     public function mergeNotifications(X2Model $model, $logMerge = false) {
239:         $ret = array();
240:         $modelType = get_class($model);
241:         $targetModelType = get_class($this->owner);
242:         if ($logMerge) {
243:             $ids = Yii::app()->db->createCommand()
244:                     ->select('id')
245:                     ->from('x2_notifications')
246:                     ->where(
247:                             'modelType = :type and modelId = :id', array(':type' => $modelType, ':id' => $model->id))
248:                     ->queryColumn();
249:             $ret = $ids;
250:         }
251:         X2Model::model('Notification')
252:                 ->updateAll(array(
253:                     'modelId' => $this->owner->id,
254:                     'modelType' => $targetModelType,
255:                         ), 'modelType = :type AND modelId = :id', array(
256:                     ':type' => $modelType,
257:                     ':id' => $model->id
258:         ));
259:         return $ret;
260:     }
261: 
262:     /**
263:      * Transfers all tags from $model to $this->owner
264:      */
265:     public function mergeTags(X2Model $model, $logMerge = false) {
266:         $ret = array();
267:         if ($logMerge) {
268:             $ret = $model->getTags();
269:         }
270:         $this->owner->disableTagTriggers();
271:         $this->owner->addTags($model->getTags());
272:         $this->owner->enableTagTriggers();
273:         $model->clearTags();
274:         return $ret;
275:     }
276: 
277:     /**
278:      * Transfers all relationships of $model to $this->owner 
279:      */
280:     public function mergeRelationships(X2Model $model, $logMerge = false) {
281:         $ret = array();
282:         $modelType = get_class($model);
283:         $targetModelType = get_class($this->owner);
284:         if ($logMerge) {
285:             $firstIds = Yii::app()->db->createCommand()
286:                     ->select('id')
287:                     ->from('x2_relationships')
288:                     ->where(
289:                             'firstType = :type AND firstId = :id', array(':type' => $modelType, ':id' => $model->id))
290:                     ->queryColumn();
291:             if (!empty($firstIds)) {
292:                 $ret['first'] = $firstIds;
293:             }
294: 
295:             $secondIds = Yii::app()->db->createCommand()
296:                     ->select('id')
297:                     ->from('x2_relationships')
298:                     ->where(
299:                             'secondType = :type AND secondId = :id', array(':type' => $modelType, ':id' => $model->id))
300:                     ->queryColumn();
301:             if (!empty($secondIds)) {
302:                 $ret['second'] = $secondIds;
303:             }
304:         }
305:         Relationships::model()->updateAll(array(
306:             'firstId' => $this->owner->id,
307:             'firstType' => $targetModelType,
308:                 ), 'firstType = :type AND firstId = :id', array(
309:             ':type' => $modelType,
310:             ':id' => $model->id,
311:         ));
312:         Relationships::model()->updateAll(array(
313:             'secondId' => $this->owner->id,
314:             'secondType' => $targetModelType,
315:                 ), 'secondType = :type AND secondId = :id', array(
316:             ':type' => $modelType,
317:             ':id' => $model->id,
318:         ));
319:         return $ret;
320:     }
321: 
322:     /**
323:      * Transfers link fields pointing to $model to $htis->owner
324:      */
325:     public function mergeLinkFields(X2Model $model, $logMerge = false) {
326:         $ret = array();
327: 
328:         $linkFields = Fields::model()
329:                 ->findAllByAttributes(array('type' => 'Link', 'linkType' => get_class($model)));
330:         foreach ($linkFields as $field) {
331:             if ($logMerge) {
332:                 $ids = Yii::app()->db->createCommand()
333:                         ->select('id')
334:                         ->from(X2Model::model($field->modelName)->tableName())
335:                         ->where($field->fieldName . ' = :id', array(':id' => $model->nameId))
336:                         ->queryColumn();
337:                 if (!empty($ids)) {
338:                     $ret[$field->modelName]['field'] = $field->fieldName;
339:                     $ret[$field->modelName]['ids'] = $ids;
340:                 }
341:             }
342:             Yii::app()->db->createCommand()->update(
343:                     X2Model::model($field->modelName)->tableName(), array(
344:                 $field->fieldName => $this->owner->nameId,
345:                     ), $field->fieldName . ' = :id', array(':id' => $model->nameId));
346:         }
347:         return $ret;
348:     }
349:     
350:     /**
351:      * Undo a merge based on merge log data stored during the merge process. Should
352:      * only be called by models which have a corresponding merge log entry. Most helper
353:      * functions are simpler than their merge counterparts because related records can be
354:      * transferred between different record types, but actual merges (which are capable
355:      * of being undone) can only be performed on records of the same type.
356:      */
357:     public function revertMerge() {
358:         $mergeLog = Yii::app()->db->createCommand()
359:             ->select('*')
360:             ->from('x2_merge_log')
361:             ->where(
362:                 'mergeModelId = :id AND modelType = :type', 
363:                 array(':id' => $this->owner->id, ':type' => get_class($this->owner)))
364:             ->queryAll();
365:         if (!empty($mergeLog)) {
366:             foreach ($mergeLog as $log) {
367:                 $mergeData = json_decode($log['mergeData'], true);
368:                 $model = X2Model::model($log['modelType'])->findByPk($log['modelId']);
369:                 if (isset($model) && !empty($mergeData)) {
370:                     $model->assignedTo = $mergeData['assignedTo'];
371:                     $model->visibility = $mergeData['visibility'];
372:                     $model->save();
373:                     if (isset($mergeData['data']) && !empty($mergeData['data'])) {
374:                         foreach ($mergeData['data'] as $key => $data) {
375:                             switch ($key) {
376:                                 case 'actions':
377:                                     $this->owner->unmergeActions($model->id, $data);
378:                                     break;
379:                                 case 'events':
380:                                     $this->owner->unmergeEvents($model->id, $data);
381:                                     break;
382:                                 case 'notifications':
383:                                     $this->owner->unmergeNotifications($model->id, $data);
384:                                     break;
385:                                 case 'tags':
386:                                     $this->owner->unmergeTags($model->id, $data);
387:                                     break;
388:                                 case 'relationships':
389:                                     $this->owner->unmergeRelationships($model->id, $data);
390:                                     break;
391:                                 case 'linkFields':
392:                                     $this->owner->unmergeLinkFields($model->id, $data);
393:                                     break;
394:                             }
395:                         }
396:                     }
397:                 }
398:             }
399:             $mergeLog = Yii::app()->db->createCommand()
400:                 ->delete(
401:                     'x2_merge_log', 'mergeModelId = :id AND modelType = :type', 
402:                     array(':id' => $this->owner->id, ':type' => get_class($this->owner)));
403:             $this->owner->delete();
404:         }
405:     }
406: 
407:     public function unmergeActions($id, $actionIds) {
408:         X2Model::model('Actions')->updateByPk($actionIds, array('associationId' => $id));
409:     }
410: 
411:     public function unmergeEvents($id, $eventIds) {
412:         X2Model::model('Events')->updateByPk($eventIds, array('associationId' => $id));
413:     }
414: 
415:     public function unmergeNotifications($id, $notifIds) {
416:         X2Model::model('Notification')->updateByPk($notifIds, array('modelId' => $id));
417:     }
418: 
419:     public function unmergeTags($id, $tags) {
420:         $this->owner->removeTags($tags);
421:         $model = X2Model::model(get_class($this->owner))->findByPk($id);
422:         $model->addTags($tags);
423:     }
424: 
425:     public function unmergeRelationships($id, $data) {
426:         if (isset($data['first'])) {
427:             X2Model::model('Relationships')->updateByPk($data['first'], array('firstId' => $id));
428:         }
429:         if (isset($data['second'])) {
430:             X2Model::model('Relationships')->updateByPk($data['second'], array('secondId' => $id));
431:         }
432:     }
433: 
434:     public function unmergeLinkFields($id, $data) {
435:         $model = X2Model::model(get_class($this->owner))->findByPk($id);
436:         foreach ($data as $modelName => $fieldData) {
437:             X2Model::model($modelName)
438:                 ->updateByPk($fieldData['ids'], array($fieldData['field'] => $model->nameId));
439:         }
440:     }
441: 
442: }
443: 
X2CRM Documentation API documentation generated by ApiGen 2.8.0