1: <?php
  2:   3:   4:   5:   6:   7:   8:   9:  10:  11:  12:  13:  14:  15:  16:  17:  18:  19:  20:  21:  22:  23:  24:  25:  26:  27:  28:  29:  30:  31:  32:  33:  34:  35: 
 36: 
 37:  38:  39:  40:  41: 
 42: class X2List extends X2Model {
 43: 
 44:      45:  46:  47:  48:  49: 
 50:     public $criteriaInput;
 51: 
 52:     public $supportsWorkflow = false;
 53: 
 54:     private $_itemModel = null;
 55: 
 56:     private $_itemFields = array();
 57: 
 58:     private $_itemAttributeLabels = array();
 59: 
 60:     public static function model($className = __CLASS__){
 61:         return parent::model($className);
 62:     }
 63: 
 64:      65:  66:  67: 
 68:     public function tableName(){
 69:         return 'x2_lists';
 70:     }
 71: 
 72:     public function behaviors(){
 73:         return array(
 74:             'ERememberFiltersBehavior' => array(
 75:                 'class' => 'application.components.ERememberFiltersBehavior',
 76:                 'defaults' => array(),
 77:                 'defaultStickOnClear' => false
 78:             ),
 79:             'X2LinkableBehavior' => array(
 80:                 'class' => 'X2LinkableBehavior',
 81:                 'baseRoute' => '/contacts/contacts/list',
 82:                 'autoCompleteSource' => '/contacts/contacts/getLists',
 83:             ),
 84:             'X2PermissionsBehavior' => array(
 85:                 'class' => 'application.components.permissions.'.Yii::app()->params->modelPermissions
 86:             ),
 87:             'X2FlowTriggerBehavior' => array('class' => 'X2FlowTriggerBehavior'),
 88:         );
 89:     }
 90: 
 91:     public function rules(){
 92:         
 93:         
 94:         return array(
 95:             array('name, createDate, lastUpdated, modelName', 'required'),
 96:             array('id, count, visibility, createDate, lastUpdated', 'numerical', 'integerOnly' => true),
 97:             array('name, modelName', 'length', 'max' => 100),
 98:             array('description', 'length', 'max' => 250),
 99:             array('assignedTo, type, logicType', 'length', 'max' => 20),
100:             
101:             
102:             array('id, assignedTo, name, modelName, count, visibility, description, type, createDate, lastUpdated', 'safe', 'on' => 'search'),
103:         );
104:     }
105: 
106:     public function relations(){
107:         
108:         
109:         return array(
110:             'listItems' => array(self::HAS_MANY, 'X2ListItem', 'listId'),
111:             'campaign' => array(self::HAS_ONE, 'Campaign', array('listId' => 'nameId')),
112:             'criteria' => array(self::HAS_MANY,'X2ListCriterion','listId'),
113:         );
114:     }
115: 
116:     public function attributeLabels(){
117:         return array(
118:             'id' => 'ID',
119:             'assignedTo' => Yii::t('contacts', 'Owner'),
120:             'name' => Yii::t('contacts', 'Name'),
121:             'description' => Yii::t('contacts', 'Description'),
122:             'type' => Yii::t('contacts', 'Type'),
123:             'logicType' => Yii::t('contacts', 'Logic Type'),
124:             'modelName' => Yii::t('contacts', 'Record Type'),
125:             'visibility' => Yii::t('contacts', 'Visibility'),
126:             'count' => Yii::t('contacts', 'Members'),
127:             'createDate' => Yii::t('contacts', 'Create Date'),
128:             'lastUpdated' => Yii::t('contacts', 'Last Updated'),
129:         );
130:     }
131: 
132:     133: 134: 135: 
136:     public static function getComparisonList(){
137:         return array(
138:             '=' => Yii::t('contacts', 'equals'),
139:             '>' => Yii::t('contacts', 'greater than'),
140:             '<' => Yii::t('contacts', 'less than'),
141:             '<>' => Yii::t('contacts', 'not equal to'),
142:             'contains' => Yii::t('contacts', 'contains'),
143:             'noContains' => Yii::t('contacts', 'does not contain'),
144:             'empty' => Yii::t('contacts', 'empty'),
145:             'notEmpty' => Yii::t('contacts', 'not empty'),
146:             'list' => Yii::t('contacts', 'in list'),
147:             'notList' => Yii::t('contacts', 'not in list'),
148:         );
149:     }
150: 
151:     public function getDefaultRoute(){
152:         return '/contacts/contacts/list';
153:     }
154: 
155:     public function getDisplayName ($plural=true, $ofModule=true) {
156:         return Yii::t('contacts', '{contact} Lists|{contact} List', array(
157:             (int) $plural,
158:             '{contact}' => Modules::displayName(false, 'Contacts'),
159:         ));
160:     }
161: 
162:     public function createLink(){
163:         if(isset($this->id))
164:             return CHtml::link($this->name, array($this->getDefaultRoute(), 'id' => $this->id));
165:         else
166:             return $this->name;
167:     }
168: 
169:     170: 171: 
172:     public function afterDelete(){
173:         CActiveRecord::model('X2ListItem')->deleteAllByAttributes(array('listId' => $this->id)); 
174: 
175:         parent::afterDelete();
176:     }
177: 
178:     179: 180: 181: 
182:     public function search(){
183:         
184:         
185: 
186:         $criteria = new CDbCriteria;
187: 
188:         $criteria->compare('id', $this->id, true);
189:         $criteria->compare('name', $this->name, true);
190:         $criteria->compare('description', $this->description, true);
191:         $criteria->compare('type', $this->type, true);
192:         $criteria->compare('logicType', $this->logicType, true);
193:         $criteria->compare('modelName', $this->modelName, true);
194:         $criteria->compare('createDate', $this->createDate, true);
195:         $criteria->compare('lastUpdated', $this->lastUpdated, true);
196: 
197:         return new CActiveDataProvider(get_class($this), array(
198:                     'criteria' => $criteria,
199:                 ));
200:     }
201: 
202:     
203:     public function getItemFields(){
204:         if(empty($this->_itemFields)){
205:             if(!isset($this->_itemModel) && class_exists($this->modelName))
206:                 $this->_itemModel = new $this->modelName;
207:             $this->_itemFields = $this->_itemModel->fields;
208:         }
209:         return $this->_itemFields;
210:     }
211: 
212:     
213:     public function getItemAttributeLabels(){
214:         if(empty($this->_itemAttributeLabels)){
215:             if(!isset($this->_itemModel) && class_exists($this->modelName))
216:                 $this->_itemModel = new $this->modelName;
217:             $this->_itemAttributeLabels = $this->_itemModel->attributeLabels();
218:         }
219:         return $this->_itemAttributeLabels;
220:     }
221: 
222:     public static function load($id){
223:         if(!Yii::app()->params->isAdmin){
224:             $condition = 't.visibility="1" OR t.assignedTo="Anyone"  OR t.assignedTo="'.Yii::app()->user->getName().'"';
225:             
226:             $groupLinks = Yii::app()->db->createCommand()->select('groupId')->from('x2_group_to_user')->where('userId='.Yii::app()->user->getId())->queryColumn();
227:             if(!empty($groupLinks))
228:                 $condition .= ' OR t.assignedTo IN ('.implode(',', $groupLinks).')';
229: 
230:             $condition .= 'OR (t.visibility=2 AND t.assignedTo IN
231:                  (SELECT username FROM x2_group_to_user WHERE groupId IN
232:                      (SELECT groupId FROM x2_group_to_user WHERE userId='.Yii::app()->user->getId().')))';
233:         } else{
234:             $condition = '';
235:         }
236:         return self::model()->findByPk((int) $id, $condition);
237:     }
238: 
239:     public function calculateCount () {
240:         $criteria = $this->queryCriteria ();
241:         return Contacts::model ()->count ($criteria);
242:     }
243: 
244: 
245:     246: 247: 248: 
249:     public function queryCriteria($useAccessRules = true){
250:         $search = new CDbCriteria;
251: 
252:         if($this->type == 'dynamic'){
253:             $tagJoinCount = 0;
254:             $logicMode = $this->logicType;
255:             $criteria = X2Model::model('X2ListCriterion')
256:                 ->findAllByAttributes(array('listId' => $this->id, 'type' => 'attribute'));
257:             foreach($criteria as $criterion){
258:                 
259:                 $dateType = false;
260:                 
261:                 foreach(X2Model::model($this->modelName)->fields as $field){
262:                     if($field->fieldName == $criterion->attribute){
263:                         switch($field->type){
264:                             case 'date':
265:                             case 'dateTime':
266:                                 if(ctype_digit((string) $criterion->value) || 
267:                                    (substr($criterion->value, 0, 1) == '-' && 
268:                                     ctype_digit((string) substr($criterion->value, 1)))) {
269:                                     $criterion->value = (int) $criterion->value;
270:                                 } else {
271:                                     $criterion->value = strtotime($criterion->value);
272:                                 }
273:                                 $dateType = true;
274:                                 break;
275:                             case 'boolean':
276:                             case 'visibility':
277:                                 $criterion->value = in_array(
278:                                     strtolower($criterion->value), 
279:                                     array('1', 'yes', 'y', 't', 'true')) ? 1 : 0;
280:                                 break;
281:                         }
282:                         break;
283:                     }
284:                 }
285: 
286:                 if($criterion->attribute == 'tags' && $criterion->value){
287:                     
288:                     $tags = explode(',', preg_replace('/\s?,\s?/', ',', trim($criterion->value))); 
289:                     for($i = 0; $i < count($tags); $i++){
290:                         if(empty($tags[$i])){
291:                             unset($tags[$i]);
292:                             $i--;
293:                             continue;
294:                         }else{
295:                             if($tags[$i][0] != '#')
296:                                 $tags[$i] = '#'.$tags[$i];
297:                             $tags[$i] = 'x2_tags.tag = "'.$tags[$i].'"';
298:                         }
299:                     }
300:                     $tagCondition = implode(' OR ', $tags);
301:                     $search->join = 'LEFT JOIN x2_tags ON t.id = x2_tags.itemId';
302:                     $search->addCondition("x2_tags.id IS NOT NULL AND x2_tags.type='$this->modelName' AND " ."($tagCondition)", $logicMode);
303:                 } else if($dateType){
304:                     
305:                     $thisDay = $criterion->value;
306:                     $nextDay = $criterion->value + 86400;
307:                     switch($criterion->comparison){
308:                         case '=':
309:                             $subSearch = new CDbCriteria();
310:                             $subSearch->compare('t.'.$criterion->attribute, '>='.$thisDay, false, 'AND');
311:                             $subSearch->compare('t.'.$criterion->attribute, '<'.$nextDay, false, 'AND');
312:                             $search->mergeWith($subSearch, $logicMode);
313:                             break;
314:                         case '<>':
315:                             $subSearch = new CDbCriteria();
316:                             $subSearch->compare('t.'.$criterion->attribute, '<'.$thisDay, false, 'OR');
317:                             $subSearch->compare('t.'.$criterion->attribute, '>='.$nextDay, false, 'OR');
318:                             $search->mergeWith($subSearch, $logicMode);
319:                             break;
320:                         case '>':
321:                             $search->compare('t.'.$criterion->attribute, '>='.$thisDay, true, $logicMode);
322:                             break;
323:                         case '<':
324:                             $search->compare('t.'.$criterion->attribute, '<'.$thisDay, true, $logicMode);
325:                             break;
326:                         case 'notEmpty':
327:                             $search->addCondition('t.'.$criterion->attribute.' IS NOT NULL AND '.'t.'.$criterion->attribute.'!=""', $logicMode);
328:                             break;
329:                         case 'empty':
330:                             $search->addCondition('('.'t.'.$criterion->attribute.'="" OR '.'t.'.$criterion->attribute.' IS NULL)', $logicMode);
331:                             break;
332:                         
333:                         
334:                         
335:                         
336:                         
337:                     }
338:                 }else{
339:                     switch($criterion->comparison){
340:                         case '=':
341:                             $search->compare('t.'.$criterion->attribute, $criterion->value, false, $logicMode);
342:                             break;
343:                         case '>':
344:                             $search->compare('t.'.$criterion->attribute, '>='.$criterion->value, true, $logicMode);
345:                             break;
346:                         case '<':
347:                             $search->compare('t.'.$criterion->attribute, '<='.$criterion->value, true, $logicMode);
348:                             break;
349:                         case '<>': 
350:                             $search->addCondition('('.'t.'.$criterion->attribute.' IS NULL OR '.'t.'.$criterion->attribute.'!='.CDbCriteria::PARAM_PREFIX.CDbCriteria::$paramCount.')', $logicMode);
351:                             $search->params[CDbCriteria::PARAM_PREFIX.CDbCriteria::$paramCount++] = $criterion->value;
352:                             break;
353:                         case 'notEmpty':
354:                             $search->addCondition('t.'.$criterion->attribute.' IS NOT NULL AND '.'t.'.$criterion->attribute.'!=""', $logicMode);
355:                             break;
356:                         case 'empty':
357:                             $search->addCondition('('.'t.'.$criterion->attribute.'="" OR '.'t.'.$criterion->attribute.' IS NULL)', $logicMode);
358:                             break;
359:                         case 'list':
360:                             $search->addInCondition('t.'.$criterion->attribute, explode(',', $criterion->value), $logicMode);
361:                             break;
362:                         case 'notList':
363:                             $search->addNotInCondition('t.'.$criterion->attribute, explode(',', $criterion->value), $logicMode);
364:                             break;
365:                         case 'noContains':
366:                             $search->compare('t.'.$criterion->attribute, '<>'.$criterion->value, true, $logicMode);
367:                             break;
368:                         case 'contains':
369:                         default:
370:                             $search->compare('t.'.$criterion->attribute, $criterion->value, true, $logicMode);
371:                     }
372:                 }
373:             }
374:         }else{
375:             $search->join = 'JOIN x2_list_items ON t.id = x2_list_items.contactId';
376:             $search->addCondition('x2_list_items.listId='.$this->id);
377:         }
378: 
379:         if($useAccessRules){
380:             $accessCriteria = X2Model::model('Contacts')->getAccessCriteria(); 
381:             $accessCriteria->mergeWith($search, 'AND');
382:             return $accessCriteria;
383:         }else{
384:             return $search;
385:         }
386:     }
387: 
388:     389: 390: 391: 
392:     public function queryCommand($useAccessRules = true){
393:         $tableSchema = X2Model::model($this->modelName)->getTableSchema();
394:         return $this->getCommandBuilder()->createFindCommand($tableSchema, $this->queryCriteria($useAccessRules));
395:     }
396: 
397:     398: 399: 400: 
401:     public function dataProvider($pageSize = null, $sort = null){
402:         if(!isset($sort))
403:             $sort = array();
404:         return new CActiveDataProvider($this->modelName, array(
405:                     'criteria' => $this->queryCriteria(),
406:                     'pagination' => array(
407:                         'pageSize' => isset($pageSize) ? $pageSize : Profile::getResultsPerPage(),
408:                     ),
409:                     'sort' => $sort
410:                 ));
411:     }
412: 
413:     414: 415: 416: 417: 418: 419: 
420:     public static function getVcrLinks(&$dataProvider, $modelId){
421: 
422:         $criteria = $dataProvider->criteria;
423: 
424:         $tableSchema = X2Model::model($dataProvider->modelClass)->getTableSchema();
425:         if($tableSchema === null)
426:             return false;
427: 
428:         
429:         $criteria->select = 't.id';
430: 
431:         
432:         foreach(explode(',', $criteria->order) as $token){
433: 
434:             
435:             $token = preg_replace('/\s|asc|desc/i', '', $token);
436:             if($token !== '' && $token !== 'id' && $token != 't.id'){
437:                 if(strpos($token, '.') != 1){
438:                     $criteria->select .= ',t.'.$token;
439:                 }else{
440:                     $criteria->select .= ','.$token;
441:                 }
442:             }
443:         }
444: 
445:         
446:         if(!preg_match('/\bid\b/', $criteria->order)){
447:             if(!empty($criteria->order))
448:                 $criteria->order .= ',';
449:             $criteria->order .= 't.id DESC';
450:         }
451: 
452:         
453:         $searchConditions = Yii::app()->db->getCommandBuilder()
454:             ->createFindCommand($tableSchema, $criteria)->getText();
455:         
456:         
457:         458: 459: 460: 461: 462: 463: 464: 465: 466: 467: 468: 469: 
470:         $varPrefix = '@'; 
471:         $varName = $varPrefix.'rownum';
472:         $varText = 'SET '.$varName.' = 0'; 
473:         Yii::app()->db->createCommand()
474:                 ->setText($varText)
475:                 ->execute();
476:         $subQuery = Yii::app()->db->createCommand()
477:                 ->select('*, ('.$varName.':='.$varName.'+1) r')
478:                 ->from('('.$searchConditions.') t1')
479:                 ->getText();
480:         $rowNumberQuery = Yii::app()->db->createCommand()
481:                 ->select('(r-1)')
482:                 ->from('('.$subQuery.') t2')
483:                 ->where('t2.id=:t2_id');
484:         
485: 
486: 
487: 
488: 
489: 
490: 
491: 
492:         
493:         $rowNumberQuery->params = array_merge(array(':t2_id'=>$modelId),$criteria->params);
494:         $rowNumber = $rowNumberQuery->queryScalar();
495: 
496:         if($rowNumber === false){ 
497:             return false;
498:         }else{
499: 
500:             $criteria->select = '*'; 
501: 
502:             if($rowNumber == 0){ 
503:                 $criteria->offset = 0;
504:                 $criteria->limit = 2;
505:                 $vcrIndex = 0;
506:             }else{
507:                 $criteria->offset = $rowNumber - 1;
508:                 $criteria->limit = 3;
509:                 $vcrIndex = 1;  
510:             }
511: 
512:             $vcrModels = Yii::app()->db->getCommandBuilder()
513:                             ->createFindCommand($tableSchema, $criteria)->queryAll();
514:             $count = $dataProvider->getTotalItemCount();
515: 
516:             $vcrData = array();
517:             $vcrData['index'] = $rowNumber + 1;
518:             $vcrData['count'] = $dataProvider->getTotalItemCount();
519: 
520:             521: 522: 523: 524: 525: 526: 527: 528: 529: 
530:             if($vcrIndex > 0 && isset($vcrModels[0])){ 
531:                 $vcrData['prev'] = CHtml::link(
532:                     '<', array('view', 'id' => $vcrModels[0]['id']), 
533:                     array('title' => $vcrModels[0]['name'], 'class' => 'x2-button'));
534:             }else{
535:                 $vcrData['prev'] = CHtml::link(
536:                     '<', 'javascript:void(0);', array('class' => 'x2-button disabled'));
537:             }
538: 
539:             if(count($vcrModels) - 1 > $vcrIndex){ 
540:                 $vcrData['next'] = CHtml::link(
541:                     '>', array('view', 'id' => $vcrModels[$vcrIndex + 1]['id']), 
542:                     array('title' => $vcrModels[$vcrIndex + 1]['name'], 'class' => 'x2-button'));
543:             }else{
544:                 $vcrData['next'] = CHtml::link(
545:                     '>', 'javascript:void(0);', array('class' => 'x2-button disabled'));
546:             }
547: 
548:             return $vcrData;
549:         }
550:     }
551: 
552:     553: 554: 555: 556: 
557:     public function statusDataProvider($pageSize = null){
558:         $tbl = X2Model::model($this->modelName)->tableName();
559:         $lstTbl = X2ListItem::model()->tableName();
560:         if($this->type == 'dynamic'){
561:             $criteria = $this->queryCriteria();
562:             $count = X2Model::model($this->modelName)->count($criteria);
563:             $sql = $this->getCommandBuilder()->createFindCommand($tbl, $criteria)->getText();
564:             $params = $criteria->params;
565:         }else{ 
566:             $count = X2ListItem::model()->count('listId=:listId', array('listId' => $this->id));
567:             $sql = "SELECT t.*, c.* FROM {$lstTbl} as t LEFT JOIN {$tbl} as c ON t.contactId=c.id WHERE t.listId=:listId;";
568:             $params = array('listId' => $this->id);
569:         }
570:         return new CSqlDataProvider($sql, array(
571:                     'totalItemCount' => $count,
572:                     'params' => $params,
573:                     'pagination' => array(
574:                         'pageSize' => isset($pageSize) ? $pageSize : Profile::getResultsPerPage(),
575:                     ),
576:                     'sort' => array(
577:                         
578:                         'attributes' => array('name', 'email', 'phone', 'address'),
579:                         'defaultOrder' => 'lastUpdated DESC',
580:                     ),
581:                 ));
582:     }
583: 
584:     585: 586: 587: 588: 
589:     public function campaignDataProvider($pageSize = null){
590:         $criteria = X2Model::model('Campaign')->getAccessCriteria();
591:         $conditions =$criteria->condition;
592: 
593:         $params = array('listId' => $this->id);
594: 
595:         $count = Yii::app()->db->createCommand()
596:                 ->select('count(*)')
597:                 ->from(X2ListItem::model()->tableName().' as list')
598:                 ->leftJoin(X2Model::model($this->modelName)->tableName().' t', 'list.contactId=t.id')
599:                 ->where(
600:                     'list.listId=:listId AND ('.$conditions.')',
601:                     array_merge (array(
602:                         ':listId' => $this->id
603:                     ), $criteria->params))
604:                 ->queryScalar();
605: 
606:         $sql = Yii::app()->db->createCommand()
607:                 ->select('list.*, t.*')
608:                 ->from(X2ListItem::model()->tableName().' as list')
609:                 ->leftJoin(X2Model::model($this->modelName)->tableName().' t', 'list.contactId=t.id')
610:                 ->where(
611:                     'list.listId=:listId AND ('.$conditions.')')
612:                 ->getText();
613: 
614:         return new CSqlDataProvider($sql, array(
615:                     'params' => array_merge ($params, $criteria->params),
616:                     'totalItemCount' => $count,
617:                     'pagination' => array(
618:                         'pageSize' => !empty($pageSize) ? $pageSize : Profile::getResultsPerPage(),
619:                     ),
620:                     'sort' => array(
621:                         
622:                         'attributes' => array(
623:                             'name', 
624:                             'email', 
625:                             'phone', 
626:                             'address', 
627:                             'sent',
628:                             'opened',
629:                             'clicked',
630:                             'unsubscribed',
631:                             'doNotEmail',
632:                         ),
633:                         'defaultOrder' => 'opened DESC, sent DESC, name DESC',
634:                     ),
635:                 ));
636:     }
637: 
638:     639: 640: 641: 642: 
643:     public function statusCount($type){
644:         $whitelist = array('sent', 'opened', 'clicked', 'unsubscribed');
645:         if(!in_array($type, $whitelist)){
646:             return 0;
647:         }
648: 
649:         $lstTbl = X2ListItem::model()->tableName();
650:         $count = Yii::app()->db->createCommand(
651:                         'SELECT COUNT(*) FROM '.$lstTbl.' WHERE listId = :listid AND '.$type.' > 0')
652:                 ->queryScalar(array('listid' => $this->id));
653:         return $count;
654:     }
655: 
656:     657: 658: 659: 660: 661: 
662:     public function staticDuplicate(){
663:         $dup = new X2List();
664:         $dup->attributes = $this->attributes;
665:         $dup->id = null;
666:         $dup->nameId = null;
667:         $dup->type = 'static';
668:         $dup->createDate = $dup->lastUpdated = time();
669:         $dup->isNewRecord = true;
670:         if(!$dup->save())
671:             return;
672: 
673:         $count = 0;
674:         $listItemRecords = array();
675:         $params = array();
676:         if($this->type == 'dynamic'){
677:             $itemIds = $this->queryCommand(true)->select('id')->queryColumn();
678:             foreach($itemIds as $id){
679:                 $listItemRecords[] = '(NULL,:contactId'.$count.',:listId'.$count.',0)';
680:                 $params[':contactId'.$count] = $id;
681:                 $params[':listId'.$count] = $dup->id;
682:                 $count++;
683:             }
684:         }else{ 
685:             
686:             foreach($this->listItems as $listItem){
687:                 if(!empty($listItem->emailAddress)){
688:                     $itemSql = '(:email'.$count;
689:                     $params[':email'.$count] = $listItem->emailAddress;
690:                 }else{
691:                     $itemSql = '(NULL';
692:                 }
693:                 if(!empty($listItem->contactId)){
694:                     $itemSql .= ',:contactId'.$count;
695:                     $params[':contactId'.$count] = $listItem->contactId;
696:                 }else{
697:                     $itemSql .= ',NULL';
698:                 }
699:                 $itemSql .= ',:listId'.$count.',:unsubd'.$count.')';
700:                 $params[':listId'.$count] = $dup->id;
701:                 $params[':unsubd'.$count] = $listItem->unsubscribed;
702:                 $listItemRecords[] = $itemSql;
703:                 $count++;
704:             }
705:         }
706:         if(count($listItemRecords) == 0)
707:             return;
708:         $sql = 'INSERT into x2_list_items
709:             (emailAddress, contactId, listId, unsubscribed)
710:             VALUES '
711:                 .implode(',', $listItemRecords).';';
712:         $dup->count = $count;
713: 
714:         $transaction = Yii::app()->db->beginTransaction();
715:         try{
716:             Yii::app()->db->createCommand($sql)->execute($params);
717:             $transaction->commit();
718:         }catch(Exception $e){
719:             $transaction->rollBack();
720:             $dup->delete();
721:             Yii::log($e->getMessage(), 'error', 'application');
722:             $dup = null;
723:         }
724:         return $dup;
725:     }
726: 
727:     728: 729: 730: 
731:     public function addIds($ids){
732:         if($this->type !== 'static')
733:             return false;
734: 
735:         $ids = (array) $ids;
736: 
737:         $parameters = AuxLib::bindArray($ids, 'addIds');
738:         $existingIds = Yii::app()->db->createCommand()
739:                 ->select('contactId')
740:                 ->from('x2_list_items')
741:                 ->where('listId='.$this->id.' AND contactId IN('.implode(',', array_keys($parameters)).')', $parameters) 
742:                 ->queryColumn();
743: 
744:         foreach($ids as $id){
745:             if(in_array($id, $existingIds))
746:                 continue;
747:             $listItem = new X2ListItem();
748:             $listItem->listId = $this->id;
749:             $listItem->contactId = $id;
750:             $listItem->save();
751:         }
752: 
753:         $this->count = CActiveRecord::model('X2ListItem')->countByAttributes(array('listId' => $this->id));
754:         return $this->update(array('count'));
755:     }
756: 
757:     758: 759: 760: 761: 762: 
763:     public function processCriteria(){
764:         X2ListCriterion::model()->deleteAllByAttributes(array('listId' => $this->id)); 
765:         foreach(array('attribute', 'comparison', 'value') as $property){
766:             
767:             
768:             ${"{$property}s"} = $this->criteriaInput[$property];
769:         }
770:         $comparisonList = self::getComparisonList();
771:         $contactModel = Contacts::model();
772:         $fields = $contactModel->getFields(true);
773: 
774:         for($i = 0; $i < count($attributes); $i++){ 
775:             if((array_key_exists($attributes[$i], $contactModel->attributeLabels()) || $attributes[$i] == 'tags') && array_key_exists($comparisons[$i], $comparisonList)){
776:                 $fieldRef = isset($fields[$attributes[$i]]) ? $fields[$attributes[$i]] : null;
777:                 if($fieldRef instanceof Fields && $fieldRef->type == 'link'){
778:                     $nameList = explode(',', $values[$i]);
779:                     $namesParams = AuxLib::bindArray($nameList);
780:                     $namesIn = AuxLib::arrToStrList(array_keys($namesParams));
781:                     $lookupModel = X2Model::model(ucfirst($fieldRef->linkType));
782:                     $lookupModels = $lookupModel->findAllBySql(
783:                             'SELECT * FROM `'.$lookupModel->tableName().'` '
784:                             .'WHERE `name` IN '.$namesIn, $namesParams);
785:                     if(!empty($lookupModels)){
786:                         $values[$i] = implode(',', array_map(function($m){
787:                                     return $m->nameId;
788:                                 }, $lookupModels)); 
789:                     }
790:                 }
791:                 $criterion = new X2ListCriterion;
792:                 $criterion->listId = $this->id;
793:                 $criterion->type = 'attribute';
794:                 $criterion->attribute = $attributes[$i];
795:                 $criterion->comparison = $comparisons[$i];
796:                 $criterion->value = $values[$i];
797:                 $criterion->save();
798:             }
799:         }
800:     }
801: 
802:     803: 804: 805: 
806:     public function removeIds($ids){
807:         if($this->type !== 'static')
808:             return false;
809: 
810:         $criteria = new CDbCriteria();
811:         $criteria->compare('listId', $this->id);
812:         $criteria->addInCondition('contactId', (array) $ids);
813: 
814:         $model = CActiveRecord::model('X2ListItem');
815: 
816:         
817:         if(CActiveRecord::model('X2ListItem')->deleteAll($criteria)){
818:             $this->count = CActiveRecord::model('X2ListItem')->countByAttributes(array('listId' => $this->id));
819:             $this->update(array('count'));
820:             return true;
821:         }
822:         return false;
823:     }
824: 
825:     826: 827: 828: 829: 
830:     831: 832: 833: 834: 835: 
836: 
837:     public function hasRecord ($model) {
838:         if($this->modelName !== get_class($model))
839:             return false;
840:         $listCriteria = $this->queryCriteria(false); 
841:         $listCriteria->compare('t.id',$model->id);
842:         return $model->exists($listCriteria);        
843:     }
844: 
845:     public static function getRoute($id){
846:         if($id == 'all')
847:             return array('/contacts/contacts/index');
848:         else if($id == 'new')
849:             return array('/contacts/contacts/newContacts');
850:         else if(empty($id) || $id == 'my')
851:             return array('/contacts/contacts/myContacts');
852:         else
853:             return array('/contacts/contacts/list', 'id' => $id);
854:     }
855: 
856:     public static function getAllStaticListNames($controller){
857:         $listNames = array();
858: 
859:         
860:         foreach(X2List::model()->findAllByAttributes(array('type' => 'static')) as $list){
861:             if($controller->checkPermissions($list, 'edit')) 
862:                 $listNames[$list->id] = $list->name;
863:         }
864:         return $listNames;
865:     }
866: 
867:     public function setAttributes($values, $safeOnly = true){
868:         if($this->type == 'dynamic'){
869:             $this->criteriaInput = array();
870:             foreach(array('attribute', 'comparison', 'value') as $property){
871:                 if(isset($values[$property]))
872:                     $this->criteriaInput[$property] = $values[$property];
873:             }
874:             $criteria = array_combine ($this->criteriaInput['attribute'], $this->criteriaInput['value']);
875:             if (array_key_exists ('tags', $criteria) && empty($criteria['tags'])) {
876:                 $this->addError ('tags', Yii::t ('contacts', 'Tag list must be non-empty'));
877:             }
878:         }
879:         parent::setAttributes($values, $safeOnly);
880:     }
881: 
882:     public function afterSave(){
883:         if($this->type == 'dynamic' && isset($this->criteriaInput)) {
884:             $this->processCriteria();
885:         }
886:         return parent::afterSave();
887:     }
888: 
889:     890: 891: 
892:     public function filter (array $lists) {
893:         $filterAttrs = array ();
894:         foreach ($this->getAttributes () as $attr => $val) {
895:             if (isset ($val) && $val !== '') {
896:                 if ($attr === 'assignedTo') {
897:                     $filterAttrs[$attr] = $this->compareAssignment ($val);
898:                     if (is_array ($filterAttrs[$attr])) {
899:                         $filterAttrs[$attr] =  array_map (function ($elem) {
900:                             return strtolower ($elem); 
901:                         }, $filterAttrs[$attr]);
902:                     }
903:                 } else {
904:                     $filterAttrs[$attr] = $val;
905:                 }
906:             }
907:         }
908: 
909:         $filteredLists = array ();
910:         foreach ($lists as $list) {
911:             $pass = true;
912:             foreach ($filterAttrs as $attr => $val) {
913:                 if ($attr === 'assignedTo') {
914:                     if (!is_array ($val) ||
915:                         !in_array (strtolower ($list->$attr), $val)) {
916: 
917:                         $pass = false;
918:                         break;
919:                     }
920:                 } elseif (!preg_match ("/$val/i", (string) $list->$attr)) {
921:                     $pass = false;
922:                     break;
923:                 }
924:             }
925:             if ($pass) $filteredLists[] = $list;
926:         }
927:         return $filteredLists;
928:     }
929: 
930: }
931: