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

  • ControllerPermissionsBehavior
  • ModelPermissionsBehavior
  • X2ControllerPermissionsBehavior
  • X2PermissionsBehavior
  • 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.util.AuxLib');
 38: 
 39: /**
 40:  * CModelBehavior class for permissions lookups on classes.
 41:  *
 42:  * X2PermissionsBehavior is a CModelBehavior which allows consistent lookup of
 43:  * access levels and whether or not a user is allowed to view or edit a record.
 44:  *
 45:  * @property string $assignmentAttr Name of the attribute to use for permissions
 46:  * @property string $visibilityAttr Name of the attribute to use for visibility setting
 47:  * @package application.components.permissions
 48:  * @author Jake Houser <jake@x2engine.com>, Demitri Morgan <demitri@x2engine.com>
 49:  * TODO: replace hard-coded references to ", " delimeter with Fields::MULTI_ASSIGNMENT_DELIM
 50:  */
 51: class X2PermissionsBehavior extends ModelPermissionsBehavior {
 52: 
 53:     /**
 54:      * The access level for administrators.
 55:      *
 56:      * All records, public and private, will be included in indexes and searches.
 57:      */
 58:     const QUERY_ALL = 3;
 59: 
 60:     /**
 61:      * The access level for users granted general access.
 62:      *
 63:      * All records marked public or viewable to groupmates (providing the user
 64:      * in question shares a group in common with the assignee(s)) will be
 65:      * included in indexes and searches.
 66:      */
 67:     const QUERY_PUBLIC = 2;
 68: 
 69:     /**
 70:      * The access level for users granted "private" access.
 71:      *
 72:      * Only records assigned to the user in question, or assigned to the user's
 73:      * groups, will be included.
 74:      */
 75:     const QUERY_SELF = 1;
 76: 
 77:     /**
 78:      * The access level for users granted no access.
 79:      *
 80:      * No records will be retrieved.
 81:      */
 82:     const QUERY_NONE = 0;
 83: 
 84:     /**
 85:      * This visibility value implies "private"; ordinarily visible only to
 86:      * assignee(s)/owner(s) of the record
 87:      */
 88:     const VISIBILITY_PRIVATE = 0;
 89: 
 90:     /**
 91:      * This visibility setting implies the record is public/shared, and anyone
 92:      * can view.
 93:      */
 94:     const VISIBILITY_PUBLIC = 1;
 95: 
 96:     /**
 97:      * This visibility setting implies that the record is visible to the owners
 98:      * and other members of groups to which the owners belong ("groupmates").
 99:      */
100:     const VISIBILITY_GROUPS = 2;
101: 
102:     /**
103:      * Used to prefix sql parameters to prevent parameter name conflicts
104:      */
105:     const SQL_PARAMS_PREFIX = 'X2PermissionsBehavior';
106: 
107:     private $_assignmentAttr;
108:     private $_visibilityAttr;
109: 
110:     /**
111:      * "Caches" whether the assignment applies to a given user, for each user.
112:      *
113:      * Keyed with usernames; values are boolean for whether the assignment applies.
114:      * @var type
115:      */
116:     private $_isAssignedTo = array();
117: 
118:     /**
119:      * Similar to {@link _isAssignedTo} but for visibility, which also utilizes
120:      * the visibility setting on the model.
121:      * @var type
122:      */
123:     private $_isVisibleTo = array();
124: 
125:     public function clearCache () {
126:         $this->_isVisibleTo = $this->_isAssignedTo = array ();
127:     }
128: 
129:     /**
130:      * Returns a CDbCriteria containing record-level access conditions.
131:      * @return CDbCriteria
132:      */
133:     public function getAccessCriteria(
134:         $tableAlias = 't', $paramsNamespace = 'X2PermissionsBehavior', $showHidden = false) {
135: 
136:         $criteria = new CDbCriteria;
137:         $criteria->alias = $tableAlias;
138:         $accessLevel = $this->getAccessLevel();
139: 
140:         $conditions = $this->getAccessConditions(
141:                 $accessLevel, $tableAlias, $paramsNamespace, $showHidden);
142:         foreach ($conditions as $arr) {
143:             $criteria->addCondition($arr['condition'], $arr['operator']);
144:             if (!empty($arr['params']))
145:                 $criteria->params = array_merge($criteria->params, $arr['params']);
146:         }
147:         
148:         return $criteria;
149:     }
150: 
151:     /**
152:      * @return array access condition and parameters 
153:      */
154:     public function getAccessSQLCondition($tableAlias = 't') {
155:         $criteria = $this->getAccessCriteria($tableAlias);
156:         return array('(' . $criteria->condition . ')', $criteria->params);
157:     }
158: 
159:     /**
160:      * Returns a number from 0 to 3 representing the current user's access level using the Yii 
161:      * auth manager.
162:      * Assumes authItem naming scheme like "ContactsViewPrivate", etc.
163:      * This method probably ought to overridden, as there is no reliable way to determine the 
164:      * module a model "belongs" to.
165:      * @return integer The access level. 0=no access, 1=own records, 2=public records, 3=full access
166:      */
167:     public function getAccessLevel($uid=null) {
168:         $module = ucfirst($this->owner->module);
169: 
170:         if ($uid) {
171:         } elseif (Yii::app()->isInSession) { // Web request
172:             $uid = Yii::app()->user->id;
173:         } else { // User session not available; doing an operation through API or console
174:             $uid = Yii::app()->getSuID();
175:         }
176:         $accessLevel = self::QUERY_NONE;
177: 
178:         if (Yii::app()->params->isAdmin ||
179:                 Yii::app()->authManager->checkAccess($module . 'Admin', $uid)) {
180: 
181:             if ($accessLevel < self::QUERY_ALL)
182:                 $accessLevel = self::QUERY_ALL;
183:         }elseif (Yii::app()->authManager->checkAccess($module . 'ReadOnlyAccess', $uid)) {
184:             if ($accessLevel < self::QUERY_PUBLIC)
185:                 $accessLevel = self::QUERY_PUBLIC;
186:         }elseif (Yii::app()->authManager->checkAccess($module . 'PrivateReadOnlyAccess', $uid)) {
187:             if ($accessLevel < self::QUERY_SELF)
188:                 $accessLevel = self::QUERY_SELF;
189:         }
190: 
191:         // level 2 access only works if we consider visibility,
192:         $visibilityAttr = $this->getVisibilityAttr();
193:         if ($accessLevel === self::QUERY_PUBLIC && $visibilityAttr === false)
194:             $accessLevel = self::QUERY_ALL;  // so upgrade to full access
195: 
196:         return $accessLevel;
197:     }
198: 
199:     /**
200:      * Resolves/returns the assignment attribute to use in permission checks
201:      * @return type
202:      */
203:     public function getAssignmentAttr() {
204:         if (!isset($this->_assignmentAttr)) {
205:             $this->_assignmentAttr = false;
206:             if ($this->owner->hasAttribute('assignedTo')) {
207:                 return $this->_assignmentAttr = 'assignedTo';
208:             } elseif ($this->owner->hasAttribute('createdBy')) {
209:                 return $this->_assignmentAttr = 'createdBy';
210:             } elseif ($this->owner instanceof X2Model) {
211:                 $fields = $this->owner->getFields();
212:                 foreach ($fields as $field) {
213:                     // Use the first assignment field available:
214:                     if ($field->type == 'assignment') {
215:                         $assignAttr = $field->fieldName;
216:                         return $this->_assignmentAttr = $field->fieldName;
217:                     }
218:                 }
219:             }
220:         }
221:         return $this->_assignmentAttr;
222:     }
223: 
224:     /**
225:      * Resolves/returns the visibility attribute to use in permission checks
226:      */
227:     public function getVisibilityAttr() {
228:         if (!isset($this->_visibilityAttr)) {
229:             $this->_visibilityAttr = false;
230:             if ($this->owner->hasAttribute('visibility')) {
231:                 return $this->_visibilityAttr = 'visibility';
232:             } elseif ($this->owner instanceof X2Model) {
233:                 $fields = $this->owner->getFields();
234:                 foreach ($fields as $field) {
235:                     // Use the first assignment field available:
236:                     if ($field->type == 'visibility') {
237:                         $assignAttr = $field->fieldName;
238:                         return $this->_visibilityAttr = $field->fieldName;
239:                     }
240:                 }
241:             }
242:         }
243:         return $this->_visibilityAttr;
244:     }
245: 
246:     /**
247:      * Returns visibility dropdown menu options.
248:      * @return type
249:      */
250:     public static function getVisibilityOptions() {
251:         return array(
252:             self::VISIBILITY_PUBLIC => Yii::t('app', 'Public'),
253:             self::VISIBILITY_PRIVATE => Yii::t('app', 'Private'),
254:             self::VISIBILITY_GROUPS => Yii::t('app', 'User\'s Groups')
255:         );
256:     }
257: 
258:     /**
259:      * Generates SQL condition to filter out records the user doesn't have
260:      * permission to see.
261:      *
262:      * This method is used by the 'accessControl' filter.
263:      *
264:      * @param Integer $accessLevel The user's access level. 0=no access, 1=own
265:      *  records, 2=public records, 3=full access
266:      * @return String The SQL conditions
267:      */
268:     public function getAccessConditions(
269:         $accessLevel, $tableAlias = 't', $paramsNamespace = 'X2PermissionsBehavior',
270:         $showHidden = false) {
271: 
272:         $assignmentAttr = $this->getAssignmentAttr();
273:         $visibilityAttr = $this->getVisibilityAttr();
274:         $ret = array();
275:         $prefix = empty($tableAlias) ? '' : "$tableAlias.";
276: 
277:         switch ($accessLevel) {
278:             case self::QUERY_ALL:
279:                 // User can view everything
280:                 if (!$assignmentAttr || !$visibilityAttr || $showHidden) {
281:                     $ret[] = array('condition' => 'TRUE', 'operator' => 'AND', 'params' => array());
282:                 } else {
283:                     $ret[] = array(
284:                         'condition' =>
285:                         "NOT (" . $prefix . "$visibilityAttr=" . self::VISIBILITY_PRIVATE . " AND "
286:                         . $prefix . "$assignmentAttr='Anyone')",
287:                         'operator' => 'OR',
288:                         'params' => array());
289:                 }
290:                 break;
291:             case self::QUERY_PUBLIC:
292:                 // User can view any public (shared) record
293:                 if ($visibilityAttr != false) {
294:                     $ret[] = array(
295:                         'condition' => $prefix . "$visibilityAttr=" . self::VISIBILITY_PUBLIC,
296:                         'operator' => 'OR',
297:                         'params' => array()
298:                     );
299:                 }
300:                 // Made visible among the user(s)' groupmates via "User's Groups"
301:                 // visibility setting:
302:                 $groupmatesRegex = self::getGroupmatesRegex();
303:                 if (!empty($groupmatesRegex)) {
304:                     $ret[] = array(
305:                         'condition' =>
306:                         "(" . $prefix . "$visibilityAttr=" . self::VISIBILITY_GROUPS . ' ' .
307:                         "AND " . $prefix . "$assignmentAttr 
308:                                 REGEXP BINARY :" . $paramsNamespace . "groupmatesRegex)",
309:                         'operator' => 'OR',
310:                         'params' => array(
311:                             ':' . $paramsNamespace . 'groupmatesRegex' => $groupmatesRegex
312:                         ),
313:                     );
314:                 }
315:             // Continue to case for group visibility / assignment
316:             case self::QUERY_SELF:
317:                 // User can view records they (or one of their groups) own or
318:                 // have permission to view
319:                 if ($assignmentAttr) {
320:                     list($assignedToCondition, $params) = $this->getAssignedToCondition(false, $tableAlias, null, $paramsNamespace);
321:                     $ret[] = array(
322:                         'condition' => $assignedToCondition,
323:                         'operator' => 'OR',
324:                         'params' => $params
325:                     );
326:                 }
327:                 // Visible to user groups:
328:                 $groupRegex = self::getGroupIdRegex();
329:                 if (!empty($groupRegex)) {
330:                     $ret[] = array(
331:                         'condition' => "(" . $prefix . "$assignmentAttr REGEXP BINARY 
332:                             :" . $paramsNamespace . "visibilityGroupIdRegex)",
333:                         'operator' => 'OR',
334:                         'params' => array(
335:                             ':' . $paramsNamespace . 'visibilityGroupIdRegex' => $groupRegex
336:                         )
337:                     );
338:                 }
339:                 if ($assignmentAttr && $visibilityAttr) {
340:                     $ret[] = array(
341:                         'condition' =>
342:                         "NOT (" . $prefix . "$visibilityAttr=" . self::VISIBILITY_PRIVATE . " AND "
343:                         . $prefix . "$assignmentAttr='Anyone')",
344:                         'operator' => 'AND',
345:                         'params' => array());
346:                 }
347:                 break;
348:             case self::QUERY_NONE:  // can't view anything
349:             default:
350:                 $ret[] = array('condition' => 'FALSE', 'operator' => 'AND', 'params' => array());
351:         }
352:         return $ret;
353:     }
354: 
355:     /**
356:      * Checks assignment list, including membership to groups in assignment list
357:      *
358:      * @param string $username The username of the user for which to check assignment
359:      * @param bool $excludeAnyone If true, isAssignedTo will not return true if
360:      *  the record is assigned to anyone or no one.
361:      * @return bool true of action is assigned to specified user, false otherwise
362:      */
363:     public function isAssignedTo($username, $excludeAnyone = false) {
364:         if (isset($this->_isAssignedTo[$username][$excludeAnyone]))
365:             return $this->_isAssignedTo[$username][$excludeAnyone];
366:         if (!$this->assignmentAttr) // No way to determine assignment
367:             return true;
368: 
369:         // User model corresponding to the specified username
370:         $user = $username === Yii::app()->getSuName() ? 
371:             Yii::app()->getSuModel() : 
372:             User::model()->findByAttributes(array('username' => $username));
373: 
374:         $isAssignedTo = false;
375:         $assignees = explode(', ', $this->owner->getAttribute($this->assignmentAttr));
376:         $groupIds = array_filter($assignees, 'ctype_digit');
377:         $usernames = array_diff($assignees, $groupIds);
378: 
379:         // Check for individual assignment (or "anyone" if applicable):
380:         foreach ($usernames as $assignee) {
381:             if ($assignee === 'Anyone' || (sizeof($assignees) === 1 && $assignee === '')) {
382:                 if (!$excludeAnyone) {
383:                     $isAssignedTo = true;
384:                     break;
385:                 } else {
386:                     continue;
387:                 }
388:             } else if ($assignee === $username) {
389:                 $isAssignedTo = true;
390:                 break;
391:             }
392:         }
393: 
394:         // Check for group assignment:
395:         if (!$isAssignedTo && !empty($groupIds) && $user instanceof User) {
396:             $userGroupsAssigned = array_intersect($groupIds, Groups::getUserGroups($user->id));
397:             if (!empty($userGroupsAssigned)) {
398:                 $isAssignedTo = true;
399:             }
400:         }
401:         $this->_isAssignedTo[$username][$excludeAnyone] = $isAssignedTo;
402:         return $isAssignedTo;
403:     }
404: 
405:     public function getHiddenCondition ($tableAlias = 't') {
406:         $assignmentAttr = $this->getAssignmentAttr();
407:         $visibilityAttr = $this->getVisibilityAttr();
408:         if ($assignmentAttr && $visibilityAttr) {
409:             return "(NOT ($tableAlias.$assignmentAttr='Anyone' AND 
410:                 $tableAlias.$visibilityAttr = ".self::VISIBILITY_PRIVATE."))";
411:         } else {
412:             return 'TRUE';
413:         }
414:     }
415: 
416:     private function isHidden () {
417:         $assignmentAttr = $this->getAssignmentAttr();
418:         $visibilityAttr = $this->getVisibilityAttr();
419:         if ($assignmentAttr && $visibilityAttr) {
420:             if ($this->owner->$assignmentAttr === 'Anyone' && 
421:                 $this->owner->$visibilityAttr == self::VISIBILITY_PRIVATE) {
422: 
423:                 return true;
424:             }
425:         }
426:         return false;
427:     }
428: 
429:     /**
430:      * Uses the visibility attribute and the assignment of the model to determine
431:      * if a given named user has permission to view it.
432:      * 
433:      * @param User $user The user for which visibility is to be checked
434:      * @return type
435:      */
436:     public function isVisibleTo($user) {
437:         if ($user) {
438:             $username = $user->username;
439:             $uid = $user->id;
440:         } else {
441:             $username = 'Guest';
442:             $uid = null;
443:         }
444:         if (!isset($this->_isVisibleTo[$username])) {
445:             $accessLevel = $this->getAccessLevel($uid);
446: 
447:             $hasViewPermission = false;
448: 
449:             if (!$this->isHidden ()) {
450:                 switch ($accessLevel) {
451:                     case self::QUERY_ALL:
452:                         $hasViewPermission = true;
453:                         break;
454:                     case self::QUERY_PUBLIC:
455:                         if ($this->owner->getAttribute($this->visibilityAttr) ==
456:                             self::VISIBILITY_PUBLIC) {
457: 
458:                             $hasViewPermission = true;
459:                             break;
460:                         }
461:                         // Visible if marked with visibility "Users' Groups"
462:                         // and the current user has groups in common with
463:                         // assignees of the model:
464:                         if ($this->owner->getAttribute($this->visibilityAttr) == 
465:                                 self::VISIBILITY_GROUPS && 
466:                             (bool) $this->assignmentAttr && 
467:                             (bool) ($groupmatesRegex = self::getGroupmatesRegex()) && 
468:                             preg_match(
469:                                 '/' . $groupmatesRegex . '/', 
470:                                 $this->owner->getAttribute($this->assignmentAttr))) {
471: 
472:                             $hasViewPermission = true;
473:                             break;
474:                         }
475:                     case self::QUERY_SELF:
476:                         // Visible if assigned to current user
477:                         if ($this->isAssignedTo($username, true)) {
478:                             $hasViewPermission = true;
479:                             break;
480:                         }
481:                     case self::QUERY_NONE:
482:                         break;
483:                 }
484:             }
485:             $this->_isVisibleTo[$username] = $hasViewPermission;
486:         }
487:         return $this->_isVisibleTo[$username];
488:     }
489: 
490:     /**
491:      * Returns SQL condition which can be used to determine if an action is assigned to the
492:      *  current user.
493:      * @param bool $includeAnyone If true, SQL condition will evaluate to true for actions assigned
494:      *  to anyone or no one.
495:      * @return array array (<SQL condition string>, <array of parameters>)
496:      */
497:     public function getAssignedToCondition(
498:         $includeAnyone = true, $alias = null, $username = null,
499:         $paramsNamespace = 'X2PermissionsBehavior') {
500: 
501:         $username = $username === null ? Yii::app()->getSuName() : $username;
502:         $prefix = empty($alias) ? '' : "$alias.";
503:         $groupIdsRegex = self::getGroupIdRegex($username);
504:         $condition = "(" . ($includeAnyone ?
505:                         ($prefix . $this->assignmentAttr . "='Anyone' OR assignedTo='' OR ") : '') .
506:                 $prefix . $this->assignmentAttr .
507:                 " REGEXP BINARY :" . $paramsNamespace . "userNameRegex";
508:         $params = array(
509:             ':' . $paramsNamespace . 'userNameRegex' => self::getUserNameRegex($username),
510:         );
511:         if ($groupIdsRegex !== '') {
512:             $condition .= " OR $prefix" . $this->assignmentAttr .
513:                     " REGEXP BINARY :" . $paramsNamespace . "groupIdsRegex";
514:             $params[':' . $paramsNamespace . 'groupIdsRegex'] = $groupIdsRegex;
515:         }
516:         $condition .= ')';
517:         return array($condition, $params);
518:     }
519: 
520:     /**
521:      * Generates a display-friendly list of assignees
522:      * 
523:      * @param mixed $value If specified, use as the assignment instead of the
524:      *  current model's assignment field.
525:      */
526:     public function getAssigneeNames($value = false) {
527:         $assignment = !$value ? $this->owner->getAttribute($this->getAssignmentAttr()) : $value;
528:         $assignees = !is_array($assignment) ? explode(', ', $assignment) : $assignment;
529: 
530:         $groupIds = array_filter($assignees, 'ctype_digit');
531:         $userNames = array_diff($assignees, $groupIds);
532:         $userNameParam = AuxLib::bindArray($userNames);
533:         $userFullNames = !empty($userNames) ? array_map(function($u) {
534:                     return Formatter::fullName($u['firstName'], $u['lastName']);
535:                 }, Yii::app()->db->createCommand()->select('firstName,lastName')
536:                                 ->from(User::model()->tableName())
537:                                 ->where('username IN ' . AuxLib::arrToStrList(
538:                                                 array_keys($userNameParam)), $userNameParam)
539:                                 ->queryAll()) : array();
540:         $groupIdParam = AuxLib::bindArray($groupIds);
541:         $groupNames = !empty($groupIds) ? Yii::app()->db->createCommand()
542:                         ->select('name')->from(Groups::model()->tableName())
543:                         ->where('id IN ' . AuxLib::arrToStrList(array_keys($groupIdParam)), $groupIdParam)
544:                         ->queryColumn() : array();
545:         return array_merge($userFullNames, $groupNames);
546:     }
547: 
548:     /**
549:      * Determines all users to whom a record is assigned.
550:      * 
551:      * @param bool $getUsernamesFromGroups If true, usernames of all users in groups whose ids
552:      *  are in the assignedTo string will also be returned
553:      * @return array assignees of this action
554:      */
555:     public function getAssignees($getUsernamesFromGroups = false) {
556:         $assignment = $this->owner->getAttribute($this->getAssignmentAttr());
557:         $assignees = !is_array($assignment) ? explode(', ', $assignment) : $assignment;
558: 
559:         $assigneesNames = array();
560: 
561:         if ($getUsernamesFromGroups) {
562:             // Obtain usernames from the groups assignment table
563:             $groupIds = array_filter($assignees, 'ctype_digit');
564:             if (!empty($groupIds)) {
565: 
566:                 $groupIdParam = AuxLib::bindArray($groupIds);
567:                 $groupUsers = Yii::app()->db->createCommand()
568:                         ->select('username')
569:                         ->from('x2_group_to_user')
570:                         ->where('groupId IN ' .
571:                                 AuxLib::arrToStrList(array_keys($groupIdParam)), $groupIdParam)
572:                         ->queryColumn();
573:                 foreach ($groupUsers as $username)
574:                     $assigneesNames[] = $username;
575:             }
576:         }
577:         foreach ($assignees as $assignee) {
578:             if ($assignee === 'Anyone') {
579:                 continue;
580:             } else if (!ctype_digit($assignee)) {
581:                 // Not a group ID but a username
582:                 if (CActiveRecord::model('Profile')->exists('username=:u', array(
583:                             ':u' => $assignee))) {
584:                     $assigneesNames[] = $assignee;
585:                 }
586:             }
587:         }
588: 
589:         return array_unique($assigneesNames);
590:     }
591: 
592:     /**
593:      * Returns regex for performing SQL assignedTo field comparisons.
594:      * @return string This can be inserted (with parameter binding) into SQL queries to
595:      *  determine if an action is assigned to a given group.
596:      */
597:     public static function getGroupIdRegex($username = null) {
598:         if ($username !== null) {
599:             $user = User::model()->findByAttributes(array('username' => $username));
600:             if (!$user)
601:                 throw new CException('invalid username: ' . $username);
602:             $userId = $user->id;
603:         } else {
604:             $userId = Yii::app()->getSuId();
605:         }
606:         $groupIds = Groups::getUserGroups($userId);
607:         $groupIdRegex = '';
608:         $i = 0;
609:         foreach ($groupIds as $id) {
610:             if ($i++ > 0)
611:                 $groupIdRegex .= '|';
612:             $groupIdRegex .= '((^|, )' . $id . '($|,))';
613:         }
614:         return $groupIdRegex;
615:     }
616: 
617:     /**
618:      * Regular expression for matching against a list of users
619:      *
620:      * @param array $userNames
621:      */
622:     public static function getUsernameListRegex($usernames) {
623:         return '(^|, )(' . implode('|', $usernames) . ')($|, )';
624:     }
625: 
626:     public static function getGroupmatesRegex() {
627:         $groupmates = Groups::getGroupmates(Yii::app()->getSuId());
628:         return empty($groupmates) ? null : self::getUsernameListRegex($groupmates);
629:     }
630: 
631: }
632: 
633: ?>
634: 
X2CRM Documentation API documentation generated by ApiGen 2.8.0