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

  • ActionMetaData
  • ActionText
  • Admin
  • AmorphousModel
  • ApiHook
  • APIModel
  • ChartSetting
  • ContactForm
  • ContactList
  • Credentials
  • Criteria
  • Dropdowns
  • Events
  • EventsData
  • Fields
  • FormLayout
  • Imports
  • InlineEmail
  • LeadRouting
  • Locations
  • LoginForm
  • Maps
  • Modules
  • Notes
  • Notification
  • PhoneNumber
  • Profile
  • Record
  • Relationships
  • Roles
  • RoleToPermission
  • RoleToUser
  • RoleToWorkflow
  • Rules
  • Session
  • SessionLog
  • Social
  • Tags
  • TempFile
  • Tips
  • Tours
  • TrackEmail
  • TriggerLog
  • URL
  • ViewLog
  • Widgets
  • X2List
  • X2ListCriterion
  • X2ListItem
  • X2Model
  • 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: Yii::import('application.components.X2LinkableBehavior');
  38: Yii::import('application.modules.users.models.*');
  39: Yii::import('application.components.NormalizedJSONFieldsBehavior');
  40: Yii::import('application.components.WidgetLayoutJSONFieldsBehavior');
  41: Yii::import('application.components.X2SmartSearchModelBehavior');
  42: Yii::import('application.components.sortableWidget.SortableWidget');
  43: 
  44: /**
  45:  * This is the model class for table "x2_profile".
  46:  * @package application.models
  47:  */
  48: class Profile extends X2ActiveRecord {
  49: 
  50:     /**
  51:      * username of guest profile record 
  52:      */
  53:     const GUEST_PROFILE_USERNAME = '__x2_guest_profile__';
  54: 
  55:     private $_isActive;
  56: 
  57:     public $photo; // used for avatar upload
  58: 
  59:     /**
  60:      * @var string Used in the search scenario to uniquely identify this model. Allows filters
  61:      *  to be saved for each grid view.
  62:      */
  63:     public $uid;
  64: 
  65:     /**
  66:      * @var bool If true, grid views displaying models of this type will have their filter and
  67:      *  sort settings saved in the database instead of in the session
  68:      */
  69:     public $dbPersistentGridSettings = false;
  70: 
  71:     public function __construct(
  72:         $scenario = 'insert', $uid = null, $dbPersistentGridSettings = false){
  73: 
  74:         if ($uid !== null) {
  75:             $this->uid = $uid;
  76:         }
  77:         $this->dbPersistentGridSettings = $dbPersistentGridSettings;
  78:         parent::__construct ($scenario);
  79:     }
  80: 
  81: 
  82:     public function getName () {
  83:         return $this->fullName;
  84:     }
  85: 
  86: 
  87:     public function setIsActive ($isActive) {
  88:         $this->_isActive = $isActive;
  89:     }
  90: 
  91:     public function getIsActive () {
  92:         if (isset ($this->_isActive)) {
  93:             return $this->_isActive;
  94:         } else {
  95:             return null;
  96:         }
  97:     }
  98: 
  99:     /**
 100:      * Returns the static model of the specified AR class.
 101:      * @return Profile the static model class
 102:      */
 103:     public static function model($className = __CLASS__){
 104:         return parent::model($className);
 105:     }
 106: 
 107:     /**
 108:      * @return string the associated database table name
 109:      */
 110:     public function tableName(){
 111:         return 'x2_profile';
 112:     }
 113: 
 114: 
 115:     public function getLanguageOptions () {
 116:         $languageDirs = scandir('./protected/messages'); // scan for installed language folders
 117:         if(is_dir('./custom/protected/messages')){
 118:             $languageDirs += scandir('./custom/protected/messages');
 119:         }
 120:         sort($languageDirs);
 121:         $languages = array('en' => 'English');
 122: 
 123:         foreach ($languageDirs as $code) {  // look for langauges name
 124:             $name = $this->getLanguageName($code, $languageDirs);  // in each item in $languageDirs
 125:             if ($name !== false)
 126:                 $languages[$code] = $name; // add to $languages if name is found
 127:         }
 128:         return $languages;
 129:     }
 130: 
 131:     /**
 132:      * Obtain the name of the language given its 2-5 letter code.
 133:      *
 134:      * If a language pack was found for the language code, return its full
 135:      * name. Otherwise, return false.
 136:      *
 137:      * @param string $code
 138:      * @param array $languageDirs
 139:      * @return mixed
 140:      */
 141:     public function getLanguageName($code, $languageDirs) { // lookup language name for the language code provided
 142:         if (in_array($code, $languageDirs)) { // is the language pack here?
 143:             if(file_exists("custom/protected/messages/$code/app.php")){
 144:                 $appMessageFile = "custom/protected/messages/$code/app.php";
 145:             }else{
 146:                 $appMessageFile = "protected/messages/$code/app.php";
 147:             }
 148:             if (file_exists($appMessageFile)) { // attempt to load 'app' messages in
 149:                 $appMessages = include($appMessageFile);     // the chosen language
 150:                 if (is_array($appMessages) and isset($appMessages['languageName']) && $appMessages['languageName'] != 'Template')
 151:                     return $appMessages['languageName'];       // return language name
 152:             }
 153:         }
 154:         return false; // false if languge pack wasn't there
 155:     }
 156: 
 157:     public function behaviors(){
 158:         Yii::import ('application.components.X2ActiveRecordBehavior');
 159:         Yii::import ('application.components.behaviors.FileFieldBehavior');
 160:         // Skip loading theme settins if this request isn't associated with a session, eg API
 161:         $theme = (Yii::app()->params->noSession ? array() :
 162:             ThemeGenerator::getProfileKeys(true, true, false));
 163: 
 164:         $that = $this;
 165:         return array(
 166:             'X2StaticFieldsBehavior' => array(
 167:                 'class' => 'application.components.behaviors.X2StaticFieldsBehavior',
 168:                 'translationCategory' => 'profile',
 169:                 'fields' => array (
 170:                     array (
 171:                         'fieldName' => 'fullName',
 172:                         'attributeLabel' => 'Full Name',
 173:                         'type' => 'varchar',
 174:                     ),
 175:                     array (
 176:                         'fieldName' => 'tagLine',
 177:                         'attributeLabel' => 'Tag Line',
 178:                         'type' => 'varchar',
 179:                     ),
 180:                     array (
 181:                         'fieldName' => 'username',
 182:                         'attributeLabel' => 'Username',
 183:                         'type' => 'varchar',
 184:                     ),
 185:                     array (
 186:                         'fieldName' => 'officePhone',
 187:                         'attributeLabel' => 'Office Phone',
 188:                         'type' => 'phone',
 189:                     ),
 190:                     array (
 191:                         'fieldName' => 'cellPhone',
 192:                         'attributeLabel' => 'Cell Phone',
 193:                         'type' => 'phone',
 194:                     ),
 195:                     array (
 196:                         'fieldName' => 'emailAddress',
 197:                         'attributeLabel' => 'Email Address',
 198:                         'type' => 'email',
 199:                     ),
 200:                     array (
 201:                         'fieldName' => 'language',
 202:                         'attributeLabel' => 'Language',
 203:                         'type' => 'dropdown',
 204:                         'includeEmpty' => false,
 205:                         'linkType' => function () use ($that) {
 206:                             return $that->getLanguageOptions ();
 207:                         },
 208:                     ),
 209:                     array (
 210:                         'fieldName' => 'googleId',
 211:                         'attributeLabel' => 'Google ID',
 212:                         'type' => 'email',
 213:                     ),
 214:                 ),
 215:             ),
 216:             'FileFieldBehavior' => array(
 217:                 'class' => 'application.components.behaviors.FileFieldBehavior',
 218:                 'attribute' => 'avatar',
 219:                 'fileAttribute' => 'photo',
 220:                 'fileType' => FileFieldBehavior::IMAGE,
 221:                 'getFilename' => function (CUploadedFile $file) {
 222:                     $time = time();
 223:                     $rand = chr(rand(65, 90));
 224:                     $salt = $time . $rand;
 225:                     $name = md5($salt . md5($salt) . $salt);
 226:                     return 'uploads/protected/'.$name.'.'.$file->getExtensionName ();
 227:                 }
 228:             ),
 229:             'X2LinkableBehavior' => array(
 230:                 'class' => 'X2LinkableBehavior',
 231:                 'baseRoute' => '/profile',
 232:                 'autoCompleteSource' => null,
 233:                 'module' => 'profile'
 234:             ),
 235:             'ERememberFiltersBehavior' => array(
 236:                 'class' => 'application.components.ERememberFiltersBehavior',
 237:                 'defaults' => array(),
 238:                 'defaultStickOnClear' => false
 239:             ),
 240:             'NormalizedJSONFieldsBehavior' => array(
 241:                 'class' => 'application.components.NormalizedJSONFieldsBehavior',
 242:                 'transformAttributes' => array(
 243:                     'theme' => array_merge($theme, array(
 244:                         'backgroundColor', 'menuBgColor', 'menuTextColor', 'pageHeaderBgColor',
 245:                         'pageHeaderTextColor', 'activityFeedWidgetBgColor',
 246:                         'activityFeedWidgetTextColor', 'backgroundImg', 'backgroundTiling',
 247:                         'pageOpacity', 'themeName', 'private', 'owner', 'loginSound',
 248:                         'notificationSound', 'gridViewRowColorOdd', 'gridViewRowColorEven',
 249:                         'enableLoginBgImage')),
 250:                 ),
 251:             ),
 252:             'JSONFieldsDefaultValuesBehavior' => array(
 253:                 'class' => 'application.components.JSONFieldsDefaultValuesBehavior',
 254:                 'transformAttributes' => array(
 255:                     'miscLayoutSettings' => array(
 256:                         'themeSectionExpanded'=>true, // preferences theme sub section
 257:                         'unhideTagsSectionExpanded'=>true, // preferences tag sub section
 258:                         'x2flowShowLabels'=>true, // flow node labels
 259:                         'profileInfoIsMinimized'=>false, // profile page profile info section
 260:                         // 'fullProfileInfo'=>false, // profile page profile info section
 261:                         'perStageWorkflowView'=>true, // selected workflow view interface
 262:                         'columnWidth'=>50, // selected workflow view interface
 263:                         'recordViewColumnWidth'=>65, 
 264:                         'enableTransactionalView'=>false, 
 265:                         'enableJournalView'=>true, 
 266:                         'viewModeActionSubmenuOpen'=>true, 
 267:                     ),
 268:                 ),
 269:                 'maintainCurrentFieldsOrder' => true
 270:             ),
 271:             'X2SmartSearchModelBehavior' => array (
 272:                 'class' => 'application.components.X2SmartSearchModelBehavior',
 273:             )
 274:         );
 275:     }
 276: 
 277:     /**
 278:      * Save default layouts 
 279:      */
 280:     public function afterSave () {
 281:         parent::afterSave ();
 282:         foreach ($this->_widgetLayouts as $name => $settings) {
 283:             if ($settings) $settings->save ();
 284:         }
 285:     }
 286: 
 287:     public function getProfileWidgetLayout () {
 288:         return $this->getWidgetLayout ('ProfileWidgetLayout')->settings->attributes;
 289:     }
 290: 
 291:     public function setProfileWidgetLayout ($layout) {
 292:         $this->getWidgetLayout ('ProfileWidgetLayout')->settings->attributes = $layout;
 293:     }
 294: 
 295:     public function getTopicsWidgetLayout () {
 296:         return $this->getWidgetLayout ('TopicsWidgetLayout')->settings->attributes;
 297:     }
 298: 
 299:     public function setTopicsWidgetLayout ($layout) {
 300:         $this->getWidgetLayout ('TopicsWidgetLayout')->settings->attributes = $layout;
 301:     }
 302: 
 303:      
 304: 
 305:     public function getRecordViewWidgetLayout () {
 306:         return $this->getWidgetLayout ('RecordViewWidgetLayout')->settings->attributes;
 307:     }
 308: 
 309:     public function setRecordViewWidgetLayout ($layout) {
 310:         $this->getWidgetLayout ('RecordViewWidgetLayout')->settings->attributes = $layout;
 311:     }
 312: 
 313: 
 314:     /**
 315:      * @return array validation rules for model attributes.
 316:      */
 317:     public function rules(){
 318:         // NOTE: you should only define rules for those attributes that
 319:         // will receive user inputs.
 320:         return array(
 321:             array('fullName, username, status', 'required'),
 322:             array('status, lastUpdated, disableNotifPopup, allowPost', 'numerical', 'integerOnly' => true),
 323:             array('enableFullWidth,showSocialMedia,showDetailView,disablePhoneLinks,disableTimeInTitle,showTours', 'boolean'), //,showWorkflow
 324:             array('emailUseSignature', 'length', 'max' => 10),
 325:             array('startPage', 'length', 'max' => 30),
 326:             array('googleId', 'unique'),
 327:             array('isActive', 'numerical'),
 328:             array('fullName', 'length', 'max' => 60),
 329:             array('username, updatedBy', 'length', 'max' => 20),
 330:             array('officePhone, extension, cellPhone, language', 'length', 'max' => 40),
 331:             array('timeZone', 'length', 'max' => 100),
 332:             array('widgets, tagLine, emailAddress', 'length', 'max' => 255),
 333:             array('widgetOrder', 'length', 'max' => 512),
 334:             array('emailSignature', 'safe'),
 335:             array('notes, avatar, gridviewSettings, formSettings, widgetSettings', 'safe'),
 336:             // The following rule is used by search().
 337:             // Please remove those attributes that should not be searched.
 338:             array('id, fullName, username, officePhone, extension, cellPhone, emailAddress, lastUpdated, language', 'safe', 'on' => 'search'),
 339:         );
 340:     }
 341: 
 342:     /**
 343:      * @return array relational rules.
 344:      */
 345:     public function relations(){
 346:         return array(
 347:             'user' => array(self::HAS_ONE, 'User', array ('username' => 'username'))
 348:         );
 349:     }
 350: 
 351:     /**
 352:      * @return array customized attribute labels (name=>label)
 353:      */
 354:     public function attributeLabels(){
 355:         return array(
 356:             'id' => Yii::t('profile', 'ID'),
 357:             'fullName' => Yii::t('profile', 'Full Name'),
 358:             'username' => Yii::t('profile', 'Username'),
 359:             'officePhone' => Yii::t('profile', 'Office Phone'),
 360:             'extension' => Yii::t('profile','Extension'),
 361:             'cellPhone' => Yii::t('profile', 'Cell Phone'),
 362:             'emailAddress' => Yii::t('profile', 'Email Address'),
 363:             'notes' => Yii::t('profile', 'Notes'),
 364:             'status' => Yii::t('profile', 'Status'),
 365:             'tagLine' => Yii::t('profile', 'Tag Line'),
 366:             'lastUpdated' => Yii::t('profile', 'Last Updated'),
 367:             'updatedBy' => Yii::t('profile', 'Updated By'),
 368:             'avatar' => Yii::t('profile', 'Avatar'),
 369:             'allowPost' => Yii::t('profile', 'Allow users to post on your profile?'),
 370:             'disablePhoneLinks' => Yii::t('profile', 'Disable phone field links?'),
 371:             'disableTimeInTitle' => Yii::t('profile','Disable timer display in page title?'),
 372:             'disableNotifPopup' => Yii::t('profile', 'Disable notifications pop-up?'),
 373:             'language' => Yii::t('profile', 'Language'),
 374:             'timeZone' => Yii::t('profile', 'Time Zone'),
 375:             'widgets' => Yii::t('profile', 'Widgets'),
 376:             // 'groupChat'=>Yii::t('profile','Enable group chat?'),
 377:             'widgetOrder' => Yii::t('profile', 'Widget Order'),
 378:             'widgetSettings' => Yii::t('profile', 'Widget Settings'),
 379:             'resultsPerPage' => Yii::t('profile', 'Results Per Page'),
 380:             /* 'menuTextColor' => Yii::t('profile', 'Menu Text Color'),
 381:               'menuBgColor' => Yii::t('profile', 'Menu Color'),
 382:               'menuTextColor' => Yii::t('profile', 'Menu Text Color'),
 383:               'pageHeaderBgColor' => Yii::t('profile', 'Page Header Color'),
 384:               'pageHeaderTextColor' => Yii::t('profile', 'Page Header Text Color'),
 385:               'activityFeedWidgetBgColor' => Yii::t('profile', 'Activity Feed Widget Background Color'),
 386:               'backgroundColor' => Yii::t('profile', 'Background Color'),
 387:               'backgroundTiling' => Yii::t('profile', 'Background Tiling'),
 388:               'pageOpacity' => Yii::t('profile', 'Page Opacity'), */
 389:             'startPage' => Yii::t('profile', 'Start Page'),
 390:             'showSocialMedia' => Yii::t('profile', 'Show Social Media'),
 391:             'showDetailView' => Yii::t('profile', 'Show Detail View'),
 392:             // 'showWorkflow'=>Yii::t('profile','Show Workflow'),
 393:             'gridviewSettings' => Yii::t('profile', 'Gridview Settings'),
 394:             'formSettings' => Yii::t('profile', 'Form Settings'),
 395:             'emailUseSignature' => Yii::t('profile', 'Email Signature'),
 396:             'emailSignature' => Yii::t('profile', 'My Signature'),
 397:             'enableFullWidth' => Yii::t('profile', 'Enable Full Width Layout'),
 398:             'googleId' => Yii::t('profile', 'Google ID'),
 399:             'address' => Yii::t('profile', 'Address'),
 400:         );
 401:     }
 402: 
 403:     /**
 404:      * Masks method in X2SmartSearchModelBehavior. Enables sorting by lastLogin and isActive.
 405:      */
 406:     public function getSort () {
 407:         $attributes = array();
 408:         foreach($this->owner->attributes as $name => $val) {
 409:             $attributes[$name] = array(
 410:                 'asc' => 't.'.$name.' ASC',
 411:                 'desc' => 't.'.$name.' DESC',
 412:             );
 413:         }
 414:         $attributes['lastLogin'] = array (
 415:             'asc' => '(SELECT lastLogin from x2_users '.
 416:                 'WHERE x2_users.username=t.username) ASC',
 417:             'desc' => '(SELECT lastLogin from x2_users '.
 418:                 'WHERE x2_users.username=t.username) DESC',
 419:         );
 420:         $attributes['isActive'] = array (
 421:             'asc' => 
 422:                 '(SELECT DISTINCT user '.
 423:                     'FROM x2_sessions '.
 424:                     'WHERE t.username=x2_sessions.user AND '.
 425:                         'x2_sessions.lastUpdated > '.(time () - 900).
 426:                 ') DESC ',
 427:             'desc' => 
 428:                 '(SELECT DISTINCT user '.
 429:                     'FROM x2_sessions '.
 430:                     'WHERE t.username=x2_sessions.user AND '.
 431:                         'x2_sessions.lastUpdated > '.(time () - 900).
 432:                 ') ASC',
 433:         );
 434:         return $attributes;
 435:     }
 436: 
 437:     /**
 438:      * Retrieves a list of models based on the current search/filter conditions.
 439:      * @return CActiveDataProvider the data provider that can return the models based on the search/filter conditions.
 440:      */
 441:     public function search($resultsPerPage=null, $uniqueId=null, $excludeAPI=false){
 442:         // Warning: Please modify the following code to remove attributes that
 443:         // should not be searched.
 444: 
 445:         $criteria = new CDbCriteria;
 446: 
 447:         $criteria->distinct = true;
 448:         $criteria->compare('id', $this->id);
 449:         $criteria->compare('fullName', $this->fullName, true);
 450:         $criteria->compare('username', $this->username, true);
 451:         $criteria->compare('username', '<>'.self::GUEST_PROFILE_USERNAME, true);
 452:         $criteria->compare('officePhone', $this->officePhone, true);
 453:         $criteria->compare('cellPhone', $this->cellPhone, true);
 454:         $criteria->compare('emailAddress', $this->emailAddress, true);
 455:         $criteria->compare('status', $this->status);
 456:         $criteria->compare('tagLine',$this->tagLine,true);
 457: 
 458:         // Filter on is active model property
 459:         if (!isset ($this->isActive)) { // invalid isActive value
 460:         } else if ($this->isActive) { // select all users with new session records
 461:             $criteria->join = 
 462:                 'JOIN x2_sessions ON x2_sessions.user=username and '.
 463:                 'x2_sessions.lastUpdated > "'.(time () - 900).'"';
 464:         } else { // select all users with old session records or no session records
 465:             $criteria->join = 
 466:                 'JOIN x2_sessions ON (x2_sessions.user=username and '.
 467:                 'x2_sessions.lastUpdated <= "'.(time () - 900).'") OR '.
 468:                 'username not in (select x2_sessions.user from x2_sessions as x2_sessions)';
 469:         }
 470: 
 471:         if ($excludeAPI) {
 472:             if ($criteria->condition !== '') {
 473:                 $criteria->condition .= ' AND username!=\'API\'';
 474:             } else { 
 475:                 $criteria->condition = 'username!=\'API\'';
 476:             }
 477:         }
 478: 
 479:         return $this->smartSearch ($criteria, $resultsPerPage);
 480:     }
 481: 
 482:     /**
 483:      * Sets a miscLayoutSetting JSON property to the specified value
 484:      *
 485:      * @param string $settingName The name of the JSON property
 486:      * @param string $settingValue The value that the JSON property will bet set to
 487:      */
 488:     public static function setMiscLayoutSetting (
 489:         $settingName, $settingValue, $suppressEcho=false) {
 490: 
 491:         $model = Profile::model ()->findByPk (Yii::app()->user->getId());
 492:         $settings = $model->miscLayoutSettings;
 493:         if (!in_array ($settingName, array_keys ($settings))) {
 494:             echo 'failure';
 495:             return;
 496:         }
 497:         $settings[$settingName] = $settingValue;
 498:         $model->miscLayoutSettings = $settings;
 499:         $echoVal = '';
 500:         if (!$model->save ()) {
 501:             //AuxLib::debugLog ('Error: setMiscLayoutSetting: failed to save model');
 502:             $echoVal = 'failure';
 503:         } else {
 504:             $echoVal = 'success';
 505:         }
 506: 
 507:         if (!$suppressEcho) echo $echoVal;
 508:     }
 509: 
 510:     public static function setDetailView($value){
 511:         $model = Profile::model()->findByPk(Yii::app()->user->getId()); // set user's preference for contact detail view
 512:         $model->showDetailView = ($value == 1) ? 1 : 0;
 513:         $model->upadte(array('showDetailView'));
 514:     }
 515: 
 516:     public static function getDetailView(){
 517:         $model = Profile::model()->findByPk(Yii::app()->user->getId()); // get user's preference for contact detail view
 518:         return $model->showDetailView;
 519:     }
 520: 
 521:     // public static function getSocialMedia() {
 522:     // $model = Profile::model()->findByPk(Yii::app()->user->getId());    // get user's preference for contact social media info
 523:     // return $model->showSocialMedia;
 524:     // }
 525: 
 526:     public function getSignature($html = false){
 527: 
 528:         $adminRule = Yii::app()->settings->emailUseSignature;
 529:         $userRule = $this->emailUseSignature;
 530:         $signature = '';
 531: 
 532:         switch($adminRule){
 533:             case 'admin': $signature = Yii::app()->settings->emailSignature;
 534:                 break;
 535:             case 'user':
 536:                 switch($userRule){
 537:                     case 'user': $signature = $signature = $this->emailSignature;
 538:                         break;
 539:                     case 'admin': Yii::app()->settings->emailSignature;
 540:                         break;
 541:                     case 'group': $signature == '';
 542:                         break;
 543:                     default: $signature == '';
 544:                 }
 545:                 break;
 546:             case 'group': $signature == '';
 547:                 break;
 548:             default: $signature == '';
 549:         }
 550: 
 551: 
 552:         $signature = preg_replace(
 553:                 array(
 554:             '/\{first\}/',
 555:             '/\{last\}/',
 556:             '/\{phone\}/',
 557:             '/\{group\}/',
 558:             '/\{email\}/',
 559:                 ), array(
 560:             $this->user->firstName,
 561:             $this->user->lastName,
 562:             $this->officePhone,
 563:             '',
 564:             $html ? CHtml::mailto($this->emailAddress) : $this->emailAddress,
 565:                 ), $signature
 566:         );
 567:         if($html){
 568:             $signature = Formatter::convertLineBreaks($signature);
 569:         }
 570: 
 571:         return $signature;
 572:     }
 573: 
 574:     public static function getResultsPerPage(){
 575:         if(!Yii::app()->user->isGuest)
 576:             $resultsPerPage = Yii::app()->params->profile->resultsPerPage;
 577:         // $model = Profile::model()->findByPk(Yii::app()->user->getId());    // get user's preferred results per page
 578:         // $resultsPerPage = $model->resultsPerPage;
 579: 
 580:         return empty($resultsPerPage) ? 15 : $resultsPerPage;
 581:     }
 582: 
 583:     public static function getPossibleResultsPerPage(){
 584:         return array(
 585:             10 => Yii::t('app', '{n} rows', array('{n}' => '10')),
 586:             20 => Yii::t('app', '{n} rows', array('{n}' => '20')),
 587:             30 => Yii::t('app', '{n} rows', array('{n}' => '30')),
 588:             40 => Yii::t('app', '{n} rows', array('{n}' => '40')),
 589:             50 => Yii::t('app', '{n} rows', array('{n}' => '50')),
 590:             75 => Yii::t('app', '{n} rows', array('{n}' => '75')),
 591:             100 => Yii::t('app', '{n} rows', array('{n}' => '100')),
 592:         );
 593:     }
 594: 
 595:     // lookup user's settings for a gridview (visible columns, column widths)
 596:     public static function getGridviewSettings($gvSettingsName = null){
 597:         if(!Yii::app()->user->isGuest)
 598:             // converts JSON string to assoc. array
 599:             $gvSettings = json_decode(Yii::app()->params->profile->gridviewSettings, true); 
 600:         if(isset($gvSettingsName)){
 601:             $gvSettingsName = strtolower($gvSettingsName);
 602:             if(isset($gvSettings[$gvSettingsName]))
 603:                 return $gvSettings[$gvSettingsName];
 604:             else
 605:                 return null;
 606:         } elseif(isset($gvSettings)){
 607:             return $gvSettings;
 608:         }else{
 609:             return null;
 610:         }
 611:     }
 612: 
 613:     // add/update settings for a specific gridview, or save all at once
 614:     public static function setGridviewSettings($gvSettings, $gvSettingsName = null){
 615:         if(!Yii::app()->user->isGuest){
 616:             if(isset($gvSettingsName)){
 617:                 $fullGvSettings = Profile::getGridviewSettings();
 618:                 $fullGvSettings[strtolower($gvSettingsName)] = $gvSettings;
 619:                 // encode array in JSON
 620:                 Yii::app()->params->profile->gridviewSettings = json_encode($fullGvSettings); 
 621:             }else{
 622:                 // encode array in JSON
 623:                 Yii::app()->params->profile->gridviewSettings = json_encode($gvSettings); 
 624:             }
 625:             return Yii::app()->params->profile->update(array('gridviewSettings'));
 626:         }else{
 627:             return null;
 628:         }
 629:     }
 630: 
 631:     // lookup user's settings for a gridview (visible columns, column widths)
 632:     public static function getFormSettings($formName = null){
 633:         if(!Yii::app()->user->isGuest){
 634:             $formSettings = json_decode(Yii::app()->params->profile->formSettings, true); // converts JSON string to assoc. array
 635:             if($formSettings == null)
 636:                 $formSettings = array();
 637:             if(isset($formName)){
 638:                 $formName = strtolower($formName);
 639:                 if(isset($formSettings[$formName]))
 640:                     return $formSettings[$formName];
 641:                 else
 642:                     return array();
 643:             } else{
 644:                 return $formSettings;
 645:             }
 646:         }else{
 647:             return array();
 648:         }
 649:     }
 650: 
 651:     // add/update settings for a specific form, or save all at once
 652:     public static function setFormSettings($formSettings, $formName = null){
 653:         if(isset($formName)){
 654:             $fullFormSettings = Profile::getFormSettings();
 655:             $fullFormSettings[strtolower($formName)] = $formSettings;
 656:             Yii::app()->params->profile->formSettings = json_encode($fullFormSettings); // encode array in JSON
 657:         }else{
 658:             Yii::app()->params->profile->formSettings = json_encode($formSettings); // encode array in JSON
 659:         }
 660:         return Yii::app()->params->profile->update(array('formSettings'));
 661:     }
 662: 
 663:     public static function getWidgets(){
 664: 
 665:         if(Yii::app()->user->isGuest) // no widgets if the user isn't logged in
 666:             return array();
 667:         // $model = Profile::model('Profile')->findByPk(Yii::app()->user->getId());
 668:         $model = Yii::app()->params->profile;
 669:         if(!isset($model)){
 670:             $model = Profile::model()->findByPk(Yii::app()->user->getId());
 671:         }
 672: 
 673:         $registeredWidgets = array_keys(Yii::app()->params->registeredWidgets);
 674: 
 675:         $widgetNames = ($model->widgetOrder == '') ? array() : explode(":", $model->widgetOrder);
 676:         $visibility = ($model->widgets == '') ? array() : explode(":", $model->widgets);
 677:         $widgetList = array();
 678:         $updateRecord = false;
 679: 
 680:         for($i = 0; $i < count($widgetNames); $i++){
 681: 
 682:             if(!in_array($widgetNames[$i], $registeredWidgets)){ // check the main cfg file
 683:                 unset($widgetNames[$i]);       // if widget isn't listed,
 684:                 unset($visibility[$i]);        // remove it from database fields
 685:                 $updateRecord = true;
 686:             }else{
 687:                 $widgetList[$widgetNames[$i]] = array(
 688:                     'id' => 'widget_'.$widgetNames[$i], 
 689:                     'visibility' => isset ($visibility[$i]) ? $visibility[$i] : 1,
 690:                     'params' => array());
 691:             }
 692:         }
 693: 
 694:         foreach($registeredWidgets as $class){   // check list of widgets in main cfg file
 695:             if(!in_array($class, array_keys($widgetList))){        // if they aren't in the list,
 696:                 $widgetList[$class] = array(
 697:                     'id' => 'widget_'.$class, 'visibility' => 1,
 698:                     'params' => array()); // add them at the bottom
 699: 
 700:                 $widgetNames[] = $class; // add new widgets to widgetOrder array
 701:                 $visibility[] = 1;   // and visibility array
 702:                 $updateRecord = true;
 703:             }
 704:         }
 705: 
 706:         if($updateRecord){
 707:             $model->widgetOrder = implode(':', $widgetNames); // update database fields
 708:             $model->widgets = implode(':', $visibility);   // if there are new widgets
 709:             $model->update(array('widgetOrder', 'widgets'));
 710:         }
 711: 
 712:         return $widgetList;
 713:     }
 714: 
 715:     public static function getWidgetSettings(){
 716:         if(Yii::app()->user->isGuest) // no widgets if the user isn't logged in
 717:             return array();
 718: 
 719:         // if widget settings haven't been set, give them default values
 720:         if(Yii::app()->params->profile->widgetSettings == null){
 721:             $widgetSettings = self::getDefaultWidgetSettings();
 722: 
 723:             Yii::app()->params->profile->widgetSettings = json_encode($widgetSettings);
 724:             Yii::app()->params->profile->update(array('widgetSettings'));
 725:         }
 726: 
 727:         $widgetSettings = json_decode(Yii::app()->params->profile->widgetSettings);
 728: 
 729:         if(!isset($widgetSettings->MediaBox)){
 730:             $widgetSettings->MediaBox = array('mediaBoxHeight' => 150, 'hideUsers' => array());
 731:             Yii::app()->params->profile->widgetSettings = json_encode($widgetSettings);
 732:             Yii::app()->params->profile->update(array('widgetSettings'));
 733:         }
 734: 
 735:         return json_decode(Yii::app()->params->profile->widgetSettings);
 736:     }
 737: 
 738:     /**
 739:     * get an array of default widget values
 740:     * @return Array of default values for widgets
 741:     *
 742:     **/
 743:     public static function getDefaultWidgetSettings(){
 744:         return  array(
 745:                 'ChatBox' => array(
 746:                     'chatboxHeight' => 300,
 747:                     'chatmessageHeight' => 50,
 748:                 ),
 749:                 'NoteBox' => array(
 750:                     'noteboxHeight' => 200,
 751:                     'notemessageHeight' => 50,
 752:                 ),
 753:                 'DocViewer' => array(
 754:                     'docboxHeight' => 200,
 755:                 ),
 756:                 'TopSites' => array(
 757:                     'topsitesHeight' => 200,
 758:                     'urltitleHeight' => 10,
 759:                 ),
 760:                 'MediaBox' => array(
 761:                     'mediaBoxHeight' => 150,
 762:                     'hideUsers' => array(),
 763:                 ),
 764:                 'TimeZone' => array(
 765:                     'clockType' => 'analog'
 766:                 ),
 767:                 'SmallCalendar' => array(
 768:                     'justMe' => 'false'
 769:                 ),
 770:                 'FilterControls' => array(
 771:                     'order' => array()
 772:                 )
 773:             );
 774:     }
 775: 
 776:     /**
 777:     * Method to change a specific value in a widgets settings
 778:     * @param string    $widget Name of widget
 779:     * @param string    $setting Name of setting within the widget
 780:     * @param variable  $value to insert into the setting  
 781:     * @return boolean  false if profile did not exist
 782:     */
 783:     public static function changeWidgetSetting($widget, $setting, $value){
 784:         $profile = Yii::app()->params->profile;
 785:         if(isset($profile)){
 786:             $widgetSettings = self::getWidgetSettings();
 787: 
 788:             if(!isset($widgetSettings->$widget))
 789:                 self::getWidgetSetting($widget);
 790: 
 791: 
 792:             $widgetSettings->$widget->$setting = $value;
 793:             
 794:             Yii::app()->params->profile->widgetSettings = CJSON::encode($widgetSettings);
 795:             Yii::app()->params->profile->update(array('widgetSettings'));
 796:             return true;
 797:         }
 798: 
 799:         return false;
 800:     }
 801: 
 802:     /**
 803:     * Safely retrieves the settings of a widget, and pulls from the default if the setting does not exist
 804:     * @param string $widget The settings to return.
 805:     * @param string $setting Optional. 
 806:     * @return Object widget settings object
 807:     * @return String widget settings string (if $setting is set)
 808:     */
 809:     public static function getWidgetSetting($widget, $setting=null){
 810:         $widgetSettings = self::getWidgetSettings();
 811: 
 812:         // Check if the widget setting exists
 813:         $defaultSettings = self::getDefaultWidgetSettings();
 814:         if(!isset($widgetSettings->$widget)){
 815:             $widgetSettings->$widget = $defaultSettings[$widget];
 816:             Yii::app()->params->profile->widgetSettings = json_encode($widgetSettings);
 817:             Yii::app()->params->profile->update(array('widgetSettings'));
 818:             $widgetSettings = self::getWidgetSettings();
 819: 
 820:         // Check if the setting exists
 821:         } else if( isset($setting) && !isset($widgetSettings->$widget->$setting)){
 822:             $widgetSettings->$widget->$setting = $defaultSettings[$widget][$setting];
 823:             Yii::app()->params->profile->widgetSettings = json_encode($widgetSettings);
 824:             Yii::app()->params->profile->update(array('widgetSettings'));
 825:             $widgetSettings = self::getWidgetSettings();
 826:         }
 827: 
 828:         if( !isset($setting) )
 829:             return $widgetSettings->$widget;
 830:         else
 831:             return $widgetSettings->$widget->$setting;
 832:     }
 833: 
 834:     public function getLink(){
 835: 
 836:         $noSession = Yii::app()->params->noSession;
 837:         if(!$noSession){
 838:             if($this->id == Yii::app()->user->id)
 839:                 return CHtml::link(Yii::t('app', 'your feed'), array($this->baseRoute.'/'.$this->id));
 840:             else
 841:                 return CHtml::link(Yii::t('app', '{name}\'s feed', array('{name}' => $this->fullName)), array($this->baseRoute.'/'.$this->id));
 842:         } else{
 843:             return CHtml::link($this->fullName, Yii::app()->absoluteBaseUrl.'/index.php'.$this->baseRoute.'/'.$this->id);
 844:         }
 845:     }
 846: 
 847:     public function syncActionToGoogleCalendar($action, $ajax=false){
 848:         try{ // catch google exceptions so the whole app doesn't crash if google has a problem syncing
 849:             $admin = Yii::app()->settings;
 850:             if($admin->googleIntegration){
 851:                 if(isset($this->syncGoogleCalendarId) && $this->syncGoogleCalendarId){
 852: //                    // Google Calendar Libraries
 853: //                    $timezone = date_default_timezone_get();
 854: //                    require_once "protected/extensions/google-api-php-client/src/Google_Client.php";
 855: //                    require_once "protected/extensions/google-api-php-client/src/contrib/Google_Service_Calendar.php";
 856: //                    date_default_timezone_set($timezone);
 857: //
 858: //                    $client = new Google_Client();
 859: //                    $client->setClientId($admin->googleClientId);
 860: //                    $client->setClientSecret($admin->googleClientSecret);
 861: //                    //$client->setDeveloperKey($admin->googleAPIKey);
 862: //                    $client->setAccessToken($this->syncGoogleCalendarAccessToken);
 863: //                    $googleCalendar = new Google_Service_Calendar($client);
 864:                     $auth = new GoogleAuthenticator();
 865:                     $googleCalendar = $auth->getCalendarService();
 866: 
 867:                     // check if the access token needs to be refreshed
 868:                     // note that the google library automatically refreshes the access token if 
 869:                     // we need a new one,
 870:                     // we just need to check if this happened by calling a google api function that 
 871:                     // requires authorization,
 872:                     // and, if the access token has changed, save this new access token
 873:                     if(!$googleCalendar){
 874:                         $redirectUrl = $auth->getAuthorizationUrl('calendar');
 875:                         if ($ajax) {
 876:                             echo CJSON::encode (array ('redirect' => $redirectUrl));
 877:                             Yii::app()->end ();
 878:                         } else {
 879:                             Yii::app()->controller->redirect($redirectUrl);
 880:                         }
 881:                     }
 882: //                    if($this->syncGoogleCalendarAccessToken != $client->getAccessToken()){
 883: //                        $this->syncGoogleCalendarAccessToken = $client->getAccessToken();
 884: //                        $this->update(array('syncGoogleCalendarAccessToken'));
 885: //                    }
 886: 
 887:                     $summary = $action->actionDescription;
 888:                     if($action->associationType == 'contacts' || $action->associationType == 'contact')
 889:                         $summary = $action->associationName.' - '.$action->actionDescription;
 890: 
 891:                     $event = new Google_Service_Calendar_Event();
 892:                     $event->setSummary($summary);
 893:                     if(empty($action->dueDate)){
 894:                         $action->dueDate = time();
 895:                     }
 896:                     if($action->allDay){
 897:                         $start = new Google_Service_Calendar_EventDateTime();
 898:                         $start->setDate(date('Y-m-d', $action->dueDate));
 899:                         $event->setStart($start);
 900: 
 901:                         if(!$action->completeDate)
 902:                             $action->completeDate = $action->dueDate;
 903:                         $end = new Google_Service_Calendar_EventDateTime();
 904:                         $end->setDate(date('Y-m-d', $action->completeDate + 86400));
 905:                         $event->setEnd($end);
 906:                     } else{
 907:                         $start = new Google_Service_Calendar_EventDateTime();
 908:                         $start->setDateTime(date('c', $action->dueDate));
 909:                         $event->setStart($start);
 910: 
 911:                         if(!$action->completeDate)
 912:                             $action->completeDate = $action->dueDate; // if no end time specified, make event 1 hour long
 913:                         $end = new Google_Service_Calendar_EventDateTime();
 914:                         $end->setDateTime(date('c', $action->completeDate));
 915:                         $event->setEnd($end);
 916:                     }
 917: 
 918:                     if($action->color && $action->color != '#3366CC'){
 919:                         $colorTable = array(
 920:                             10 => 'Green',
 921:                             11 => 'Red',
 922:                             6 => 'Orange',
 923:                             8 => 'Black',
 924:                         );
 925:                         if(($key = array_search($action->color, $colorTable)) != false)
 926:                             $event->setColorId($key);
 927:                     }
 928: 
 929:                     $newEvent = $googleCalendar->events->insert($this->syncGoogleCalendarId, $event);
 930:                     $action->syncGoogleCalendarEventId = $newEvent['id'];
 931:                     $action->save();
 932:                 }
 933:             }
 934:         }catch(Exception $e){
 935:             if(isset($auth)){
 936:                 $auth->flushCredentials();
 937:             }
 938:         }
 939:     }
 940: 
 941:     public function updateGoogleCalendarEvent($action){
 942:         try{ // catch google exceptions so the whole app doesn't crash if google has a problem syncing
 943:             $admin = Yii::app()->settings;
 944:             if($admin->googleIntegration){
 945:                 if(isset($this->syncGoogleCalendarId) && $this->syncGoogleCalendarId){
 946: //                    // Google Calendar Libraries
 947: //                    $timezone = date_default_timezone_get();
 948: //                    require_once "protected/extensions/google-api-php-client/src/Google_Client.php";
 949: //                    require_once "protected/extensions/google-api-php-client/src/contrib/Google_Service_Calendar.php";
 950: //                    date_default_timezone_set($timezone);
 951: //
 952: //                    $client = new Google_Client();
 953: //                    $client->setClientId($admin->googleClientId);
 954: //                    $client->setClientSecret($admin->googleClientSecret);
 955: //                    //$client->setDeveloperKey($admin->googleAPIKey);
 956: //                    $client->setAccessToken($this->syncGoogleCalendarAccessToken);
 957: //                    $client->setUseObjects(true); // return objects instead of arrays
 958: //                    $googleCalendar = new Google_Service_Calendar($client);
 959:                     $auth = new GoogleAuthenticator();
 960:                     $googleCalendar = $auth->getCalendarService();
 961: 
 962:                     // check if the access token needs to be refreshed
 963:                     // note that the google library automatically refreshes the access token if we need a new one,
 964:                     // we just need to check if this happend by calling a google api function that requires authorization,
 965:                     // and, if the access token has changed, save this new access token
 966:                     $testCal = $googleCalendar->calendars->get($this->syncGoogleCalendarId);
 967: //                    if($this->syncGoogleCalendarAccessToken != $client->getAccessToken()){
 968: //                        $this->syncGoogleCalendarAccessToken = $client->getAccessToken();
 969: //                        $this->update(array('syncGoogleCalendarAccessToken'));
 970: //                    }
 971: 
 972:                     $summary = $action->actionDescription;
 973:                     if($action->associationType == 'contacts' || $action->associationType == 'contact')
 974:                         $summary = $action->associationName.' - '.$action->actionDescription;
 975: 
 976:                     $event = $googleCalendar->events->get($this->syncGoogleCalendarId, $action->syncGoogleCalendarEventId);
 977:                     if(is_array($event)){
 978:                         $event = new Google_Service_Calendar_Event($event);
 979:                     }
 980:                     $event->setSummary($summary);
 981:                     if(empty($action->dueDate)){
 982:                         $action->dueDate = time();
 983:                     }
 984:                     if($action->allDay){
 985:                         $start = new Google_Service_Calendar_EventDateTime();
 986:                         $start->setDate(date('Y-m-d', $action->dueDate));
 987:                         $event->setStart($start);
 988: 
 989:                         if(!$action->completeDate)
 990:                             $action->completeDate = $action->dueDate;
 991:                         $end = new Google_Service_Calendar_EventDateTime();
 992:                         $end->setDate(date('Y-m-d', $action->completeDate + 86400));
 993:                         $event->setEnd($end);
 994:                     } else{
 995:                         $start = new Google_Service_Calendar_EventDateTime();
 996:                         $start->setDateTime(date('c', $action->dueDate));
 997:                         $event->setStart($start);
 998: 
 999:                         if(!$action->completeDate)
1000:                             $action->completeDate = $action->dueDate; // if no end time specified, make event 1 hour long
1001:                         $end = new Google_Service_Calendar_EventDateTime();
1002:                         $end->setDateTime(date('c', $action->completeDate));
1003:                         $event->setEnd($end);
1004:                     }
1005: 
1006:                     if($action->color && $action->color != '#3366CC'){
1007:                         $colorTable = array(
1008:                             10 => 'Green',
1009:                             11 => 'Red',
1010:                             6 => 'Orange',
1011:                             8 => 'Black',
1012:                         );
1013:                         if(($key = array_search($action->color, $colorTable)) != false)
1014:                             $event->setColorId($key);
1015:                     }
1016: 
1017:                     $newEvent = $googleCalendar->events->update($this->syncGoogleCalendarId, $action->syncGoogleCalendarEventId, $event);
1018:                 }
1019:             }
1020:         }catch(Exception $e){
1021: 
1022:         }
1023:     }
1024: 
1025:     public function deleteGoogleCalendarEvent($action){
1026:         try{ // catch google exceptions so the whole app doesn't crash if google has a problem syncing
1027:             $admin = Yii::app()->settings;
1028:             $credentials = Yii::app()->settings->getGoogleIntegrationCredentials ();
1029:             if($admin->googleIntegration && $credentials){
1030:                 if(isset($this->syncGoogleCalendarId) && $this->syncGoogleCalendarId){
1031:                     // Google Calendar Libraries
1032:                     $timezone = date_default_timezone_get();
1033:                     require_once 'protected/integration/Google/google-api-php-client/src/Google/autoload.php';
1034:                     date_default_timezone_set($timezone);
1035: 
1036:                     $client = new Google_Client();
1037:                     $client->setClientId($credentials['clientId']);
1038:                     $client->setClientSecret($credentials['clientSecret']);
1039:                     //$client->setDeveloperKey($admin->googleAPIKey);
1040:                     $client->setAccessToken($this->syncGoogleCalendarAccessToken);
1041:                     $googleCalendar = new Google_Service_Calendar($client);
1042: 
1043:                     $googleCalendar->events->delete($this->syncGoogleCalendarId, $action->syncGoogleCalendarEventId);
1044:                 }
1045:             }
1046:         }catch(Exception $e){
1047:             // We may want to look into handling this better, or bugs will cause silent failures.
1048:         }
1049:     }
1050: 
1051:     /**
1052:      * Initializes widget layout. The layout is a set of associative arrays with the following 
1053:      * format:
1054:      * array (
1055:      * 'left'=> array()
1056:      *  'content' => array(
1057:      *    'widget1'=> array(
1058:      *      'name' => 'widget name',
1059:      *    )
1060:      *  )
1061:      * 'right' => array()
1062:      * )
1063:      *
1064:      * The layout should be json encoded and saved in profile layout property.
1065:      *
1066:      * @return array
1067:      */
1068:     function initLayout(){
1069:         $layout = array(
1070:             'left' => array(
1071:                 'ProfileInfo' => array(
1072:                     'title' => 'Profile Info',
1073:                     'minimize' => false,
1074:                 ),
1075:                 'EmailInboxMenu' => array(
1076:                     'title' => 'Inbox Menu',
1077:                     'minimize' => false,
1078:                 ),
1079:                 'ActionMenu' => array(
1080:                     'title' => 'Actions',
1081:                     'minimize' => false,
1082:                 ),
1083:                 'TopContacts' => array(
1084:                     'title' => 'Top Contacts',
1085:                     'minimize' => false,
1086:                 ),
1087:                 'RecentItems' => array(
1088:                     'title' => 'Recently Viewed',
1089:                     'minimize' => false,
1090:                 ),
1091:                 'ActionTimer' => array(
1092:                     'title' => 'Action Timer',
1093:                     'minimize' => true,
1094:                 ),
1095:                 'UserCalendars' => array(
1096:                     'title' => 'User Calendars',
1097:                     'minimize' => false,
1098:                 ),
1099:                 'CalendarFilter' => array(
1100:                     'title' => 'Filter',
1101:                     'minimize' => false,
1102:                 ),
1103:                 'GroupCalendars' => array(
1104:                     'title' => 'Group Calendars',
1105:                     'minimize' => false,
1106:                 ),
1107:                 'FilterControls' => array(
1108:                     'title' => 'Filter Controls',
1109:                     'minimize' => false,
1110:                 ),
1111:                 'SimpleFilterControlEventTypes' => array(
1112:                     'title' => 'Event Types',
1113:                     'minimize' => false,
1114:                 ),
1115:             ),
1116:             'right' => array(
1117:                 'SmallCalendar' => array(
1118:                     'title' => 'Small Calendar',
1119:                     'minimize' => false,
1120:                 ),
1121:                 'ChatBox' => array(
1122:                     'title' => 'Activity Feed',
1123:                     'minimize' => false,
1124:                 ),
1125:                 'OnlineUsers' => array(
1126:                     'title' => 'Active Users',
1127:                     'minimize' => false,
1128:                 ),
1129:                 'TagCloud' => array(
1130:                     'title' => 'Tag Cloud',
1131:                     'minimize' => false,
1132:                 ),
1133:                 'TimeZone' => array(
1134:                     'title' => 'Clock',
1135:                     'minimize' => false,
1136:                 ),
1137:                 'SmallCalendar' => array(
1138:                     'title' => 'Calendar',
1139:                     'minimize' => false,
1140:                 ),
1141:                 'QuickContact' => array(
1142:                     'title' => 'Quick Contact',
1143:                     'minimize' => false,
1144:                 ),
1145:                 'MediaBox' => array(
1146:                     'title' => 'Files',
1147:                     'minimize' => false,
1148:                 ),
1149:             ),
1150:             'hiddenRight' => array(
1151:                 'ActionMenu' => array(
1152:                     'title' => 'My Actions',
1153:                     'minimize' => false,
1154:                 ),
1155:                 'MessageBox' => array(
1156:                     'title' => 'Message Board',
1157:                     'minimize' => false,
1158:                 ),
1159:                 'NoteBox' => array(
1160:                     'title' => 'Note Pad',
1161:                     'minimize' => false,
1162:                 ),
1163:                 'DocViewer' => array(
1164:                     'title' => 'Doc Viewer',
1165:                     'minimize' => false,
1166:                 ),
1167:                 'TopSites' => array(
1168:                     'title' => 'Top Sites',
1169:                     'minimize' => false,
1170:                 ),
1171:             ),
1172:         );
1173:         if(Yii::app()->contEd('pro')){
1174:             if(file_exists('protected/config/proWidgets.php')){
1175:                 foreach(include('protected/config/proWidgets.php') as $loc=>$data){
1176:                     if (isset ($layout[$loc]))
1177:                         $layout[$loc] = array_merge($layout[$loc],$data);
1178:                 }
1179:             }
1180:         }
1181:         return $layout;
1182:     }
1183: 
1184: 
1185:     /**
1186:      * Private helper function to update users layout elements to match the set of layout
1187:      * elements specified in initLayout ().
1188:      */
1189:     private function addRemoveLayoutElements($position, &$layout, $initLayout){
1190:         $changed = false;
1191:         if (!isset ($layout[$position])) {
1192:             $changed = true;
1193:             $layout[$position] = array ();
1194:         }
1195:         if (!isset ($layout['hiddenRight'])) {
1196:             $changed = true;
1197:             $layout['hiddenRight'] = array ();
1198:         }
1199: 
1200:         if ($position === 'right') {
1201:             $initLayoutWidgets = array_merge($initLayout[$position], $initLayout['hiddenRight']);
1202:             $layoutWidgets = array_merge($layout[$position], $layout['hiddenRight']);
1203:             $initLayoutWidgetsHidden = $initLayout['hiddenRight'];
1204:             $hiddenPostion = 'hiddenRight';
1205:         } else {
1206:             $initLayoutWidgets = $initLayout[$position];
1207:             $initLayoutWidgetsHidden = array ();
1208:             $hiddenPostion = $position;
1209:             $layoutWidgets = $layout[$position];
1210:         }
1211: 
1212:         // add new widgets
1213:         $arrayDiff =
1214:                 array_diff(array_keys($initLayoutWidgets), array_keys($layoutWidgets));
1215: 
1216:         foreach($arrayDiff as $elem){
1217:             if (isset ($initLayoutWidgetsHidden[$elem])) {
1218:                 $insertAt = $hiddenPostion;
1219:             } else {
1220:                 $insertAt = $position;
1221:             }
1222:             // unshift key-value pair
1223:             $layout[$insertAt] = array(
1224:                 $elem => $initLayoutWidgets[$elem]) + $layout[$insertAt];
1225:             $changed = true;
1226:         }
1227: 
1228:         // remove obsolete widgets
1229:         $arrayDiff =
1230:                 array_diff(array_keys($layoutWidgets), array_keys($initLayoutWidgets));
1231:         foreach($arrayDiff as $elem){
1232:             if(in_array ($elem, array_keys ($layout[$position]))) {
1233:                 unset($layout[$position][$elem]);
1234:                 $changed = true;
1235:             } else if($position === 'right' && 
1236:                 in_array ($elem, array_keys ($layout['hiddenRight']))) {
1237: 
1238:                 unset($layout['hiddenRight'][$elem]);
1239:                 $changed = true;
1240:             }
1241:         }
1242: 
1243:         // ensure that widget properties are the same as those in the default layout
1244:         foreach($layout[$position] as $name=>$arr){
1245:             if (in_array ($name, array_keys ($initLayoutWidgets)) &&
1246:                 $initLayoutWidgets[$name]['title'] !== $arr['title']) {
1247: 
1248:                 $layout[$position][$name]['title'] = $initLayoutWidgets[$name]['title'];
1249:                 $changed = true;
1250:             }
1251:         }
1252: 
1253:         if ($position === 'right') {
1254:             foreach($layout['hiddenRight'] as $name=>$arr){
1255:                 if (in_array ($name, array_keys ($initLayoutWidgets)) &&
1256:                     $initLayoutWidgets[$name]['title'] !== $arr['title']) {
1257: 
1258:                     $layout['hiddenRight'][$name]['title'] = 
1259:                         $initLayoutWidgets[$name]['title'];
1260:                     $changed = true;
1261:                 }
1262:             }
1263:         }
1264: 
1265:         if($changed){
1266:             $this->layout = json_encode($layout);
1267:             $this->update(array('layout'));
1268:         }
1269:     }
1270: 
1271:     /**
1272:      * Returns the layout for the user's widgets as an associative array.
1273:      *
1274:      * @return array
1275:      */
1276:     public function getLayout(){
1277:         $layout = $this->getAttribute('layout');
1278: 
1279:         $initLayout = $this->initLayout();
1280: 
1281:         if(!$layout){ // layout hasn't been initialized?
1282:             $layout = $initLayout;
1283:             $this->layout = json_encode($layout);
1284:             $this->update(array('layout'));
1285:         }else{
1286:             $layout = json_decode($layout, true); // json to associative array
1287:             if (!is_array ($layout)) $layout = array ();
1288: 
1289:             $this->addRemoveLayoutElements('left', $layout, $initLayout);
1290:             $this->addRemoveLayoutElements('right', $layout, $initLayout);
1291:         }
1292: 
1293:         return $layout;
1294:     }
1295: 
1296:     public function getHiddenProfileWidgetMenu () {
1297:         $profileWidgetLayout = $this->profileWidgetLayout;
1298: 
1299:         $hiddenProfileWidgetsMenu = '';
1300:         $hiddenProfile = false;
1301:         $hiddenWidgets = array ();
1302:         foreach($profileWidgetLayout as $name => $widgetSettings){
1303:             $hidden = $widgetSettings['hidden'];
1304:             $softDeleted = $widgetSettings['softDeleted'];
1305:             if ($hidden && !$softDeleted) {
1306:                 $hiddenWidgets[$name] = Yii::t('app',$widgetSettings['label']);
1307:                 $hiddenProfile = true;
1308:             }
1309:         }
1310:         $hiddenWidgets = ArrayUtil::asorti ($hiddenWidgets);
1311:         foreach ($hiddenWidgets as $name => $label) {
1312:             $hiddenProfileWidgetsMenu .= 
1313:                 '<li>
1314:                     <span class="x2-hidden-widgets-menu-item profile-widget" id="'.$name.'">'.
1315:                         CHtml::encode ($label).
1316:                     '</span>
1317:                 </li>';
1318:         }
1319:         $menu = '<div id="x2-hidden-profile-widgets-menu-container" style="display:none;">';
1320:         $menu .= '<ul id="x2-hidden-profile-widgets-menu" class="x2-hidden-widgets-menu-section">';
1321:         $menu .= $hiddenProfileWidgetsMenu;
1322:         $menu .= '<li><span class="no-hidden-profile-widgets-text" '.
1323:                  ($hiddenProfile ? 'style="display:none;"' : '').'>'.
1324:                  Yii::t('app', 'No Hidden Widgets').
1325:                  '</span></li>';
1326:         $menu .= '</ul>';
1327:         $menu .= '</div>';
1328:         return $menu;
1329:     }
1330: 
1331:     /**
1332:      *  Returns an html list of hidden widgets used in the Widget Menu
1333:      */
1334:     public function getWidgetMenu(){
1335:         $layout = $this->getLayout();
1336:         $widgetType = Yii::app()->controller instanceof TopicsController ?
1337:             'topics' : 'recordView';
1338:         $layoutName = $widgetType.'WidgetLayout';
1339:         $recordViewWidgetLayout = $this->$layoutName;
1340: 
1341:         $hiddenRecordViewWidgetMenu = '';
1342:         foreach ($recordViewWidgetLayout as $widgetClass => $settings) {
1343:             if ($settings['hidden']) {
1344:                 $hiddenRecordViewWidgetMenu .=
1345:                     '<li>
1346:                         <span class="x2-hidden-widgets-menu-item '.$widgetType.'-widget" 
1347:                           id="'.$widgetClass.'">'.
1348:                             CHtml::encode ($settings['label']).
1349:                         '</span>
1350:                     </li>';
1351:             }
1352:         }
1353: 
1354:         // used to determine where section dividers should be placed
1355:         $hiddenCenter = $hiddenRecordViewWidgetMenu !== '';
1356:         $hiddenRight = !empty ($layout['hiddenRight']);
1357: 
1358:         $menu = '<div id="x2-hidden-widgets-menu">';
1359:         $menu .= '<ul id="x2-hidden-recordView-widgets-menu" 
1360:             class="x2-hidden-widgets-menu-section">';
1361:         $menu .= $hiddenRecordViewWidgetMenu;
1362:         $menu .= '</ul>';
1363:         $menu .= '<ul id="x2-hidden-right-widgets-menu" class="x2-hidden-widgets-menu-section">';
1364:         $menu .= '<li '.(($hiddenCenter && $hiddenRight) ? '' : 'style="display: none;"').
1365:             'class="x2-hidden-widgets-menu-divider"></li>';
1366:         foreach($layout['hiddenRight'] as $name => $widget){
1367:             $menu .= '<li><span class="x2-hidden-widgets-menu-item widget-right" id="'.$name.'">'.
1368:                 $widget['title'].'</span></li>';
1369:         }
1370:         $menu .= '</ul>';
1371:         $menu .= '</div>';
1372: 
1373:         return $menu;
1374:     }
1375: 
1376:     /**
1377:      * Saves a layout to the user's profile as a json string
1378:      *
1379:      * @param array $layout
1380:      */
1381:     public function saveLayout($layout){
1382:         $this->layout = json_encode($layout);
1383:         $this->update(array('layout'));
1384:     }
1385: 
1386:     /**
1387:      * Renders the avatar image with max dimension 95x95
1388:      * @param int $id the profile id 
1389:      */
1390:     public static function renderFullSizeAvatar ($id, $dimensionLimit=95) {
1391:         if ($id instanceof Profile) {
1392:             $model = $id;
1393:         } else {
1394:             $model = Profile::model ()->findByPk ($id);
1395:         }
1396:         if (isset($model->avatar) && $model->avatar != '' && !file_exists($model->avatar)
1397:                 && strpos($model->avatar, 'uploads') !== false && strpos($model->avatar, 'protected') === false) {
1398:             $path = explode(DIRECTORY_SEPARATOR, $model->avatar);
1399:             $oldPathIndex = array_search('uploads',$path);
1400:             array_splice($path, $oldPathIndex+1, 0, 'protected');
1401:             $newPath = implode(DIRECTORY_SEPARATOR, $path);
1402:             if(file_exists($newPath)){
1403:                 $model->avatar = $newPath;
1404:                 $model->update(array('avatar'));
1405:             }
1406:         }
1407:         if(isset($model->avatar) && $model->avatar!='' && file_exists($model->avatar)) {
1408:             $imgSize = @getimagesize($model->avatar);
1409:             if(!$imgSize)
1410:                 $imgSize = array(45,45);
1411: 
1412:             $maxDimension = max($imgSize[0],$imgSize[1]);
1413: 
1414:             $scaleFactor = 1;
1415:             if($maxDimension > $dimensionLimit)
1416:                 $scaleFactor = $dimensionLimit / $maxDimension;
1417: 
1418:             $imgSize[0] = round($imgSize[0] * $scaleFactor);
1419:             $imgSize[1] = round($imgSize[1] * $scaleFactor);
1420:             return Profile::renderAvatarImage($id, $imgSize[0], $imgSize[1], array (
1421:                 'class' => 'avatar-image'
1422:             ));
1423:         } else {
1424:             return X2Html::fa ('user', array(
1425:                 'class' => 'avatar-image default-avatar',
1426:                 'style' => "font-size: ${dimensionLimit}px",
1427:             )); 
1428:             // echo '<img id="avatar-image" width="'.$dimensionLimit.'" height="'.$dimensionLimit.'" src='.
1429:                 // Yii::app()->request->baseUrl."/uploads/default.png".'>';
1430:         }
1431:     }
1432: 
1433:     /**
1434:      * Renders the avatar image with max dimension 95x95
1435:      * @param int $id the profile id 
1436:      */
1437:     public static function renderEditableAvatar ($id) {
1438:         $userId = Yii::app()->user->id;
1439: 
1440:         Yii::app()->controller->renderPartial('editableAvatar',
1441:             array('id' => $id, 'editable' => $id == $userId)
1442:         );
1443:     }
1444:     
1445:     public static function renderAvatarImage($id, $width, $height, array $htmlOptions = array ()){
1446:         $model = Profile::model ()->findByPk ($id);
1447:         $file = Yii::app()->file->set($model->avatar);
1448:         if ($file->exists) {
1449:             return CHtml::tag ('img', X2Html::mergeHtmlOptions (array (
1450:                 'id'=>"avatar-image",
1451:                 'class'=>"avatar-upload", 
1452:                 'width'=>$width, 
1453:                 'height'=>$height,
1454:                 'src'=>"data:image/x-icon;base64,".base64_encode($file->getContents()),
1455:             ), $htmlOptions));
1456:         }
1457:     }
1458: 
1459:     public function getLastLogin () {
1460:         return $this->user['lastLogin'];
1461:     }
1462: 
1463:      
1464: 
1465:     /**
1466:      * Return theme after checking for an enforced default 
1467:      */
1468:     public function getTheme () {
1469:         $admin = Yii::app()->settings;
1470:          
1471:         return $this->theme;
1472:     }
1473:     
1474:     public function setLoginSound($soundId){
1475:         $this->theme = array_merge($this->theme, array('loginSound'=>$soundId));
1476:     }
1477:     
1478:     public function setNotificationSound($soundId){
1479:         $this->theme = array_merge($this->theme, array('notificationSound'=>$soundId));
1480:     }
1481: 
1482:     /**
1483:      * Get the default email template for the specified module 
1484:      * @param string $moduleName
1485:      * @return mixed null if the module has no default template, the id of the default template
1486:      *  otherwise
1487:      */
1488:     public function getDefaultEmailTemplate ($moduleName) {
1489:         $defaultEmailTemplates = CJSON::decode ($this->defaultEmailTemplates);
1490:         if (isset ($defaultEmailTemplates[$moduleName])) {
1491:             return $defaultEmailTemplates[$moduleName];
1492:         } else {
1493:             return null;
1494:         }
1495:     }
1496: 
1497:     /**
1498:      * @return array usernames of users available to receive leads
1499:      */
1500:     public function getUsernamesOfAvailableUsers () {
1501:         return array_map (function ($row) {
1502:             return $row['username'];
1503:         }, Yii::app()->db->createCommand ("
1504:             select username from x2_profile 
1505:             where leadRoutingAvailability=1
1506:         ")->queryAll ());
1507:     }
1508: 
1509:     
1510: 
1511:     /**
1512:      * @return Profile 
1513:      */
1514:     public function getGuestProfile () {
1515:         return $this->findByAttributes (array ('username' => self::GUEST_PROFILE_USERNAME)); 
1516:     }
1517: 
1518:     /**
1519:      * @param string $name name of settings class
1520:      * @return Settings 
1521:      */
1522:     private $_widgetLayouts = array (
1523:         'ProfileWidgetLayout' => null,
1524:          
1525:         'RecordViewWidgetLayout' => null,
1526:         'TopicsWidgetLayout' => null,
1527:     );
1528:     public function getWidgetLayout ($name) {
1529:         if (!$this->_widgetLayouts[$name]) {
1530:             $attributes = array ( 
1531:                 'recordType' => 'Profile',
1532:                 'recordId' => $this->id,
1533:                 'isDefault' => 1,
1534:                 'embeddedModelName' => $name,
1535:             );
1536:             $model = Settings::model ()->findByAttributes ($attributes);
1537:             if (!$model) {
1538:                 $model = new Settings;
1539:                 $model->setAttributes ($attributes, false);
1540:                 $model->unpackAll ();
1541:                 $model->save ();
1542:             }
1543:             $this->_widgetLayouts[$name] = $model;
1544:         }
1545:         return $this->_widgetLayouts[$name];
1546:     }
1547: 
1548: }
1549: 
X2CRM Documentation API documentation generated by ApiGen 2.8.0