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: 
 43: class SearchController extends x2base {
 44: 
 45:      46:  47:  48:  49: 
 50:     public function accessRules(){
 51:         return array(
 52:             array('allow', 
 53:                 'actions' => array('search', 'buildIndex'),
 54:                 'users' => array('@'),
 55:             ),
 56:             array('deny', 
 57:                 'users' => array('*'),
 58:             ),
 59:         );
 60:     }
 61: 
 62:     public function filters(){
 63:         return array(
 64:             'setPortlets',
 65:             'accessControl',
 66:         );
 67:     }
 68: 
 69:      70:  71: 
 72:     public function actionBuildIndex(){
 73: 
 74:         $contact = new Contacts;
 75:         $fieldData = $contact->getFields();
 76: 
 77: 
 78:         
 79:         $fields = array();
 80:         for($i = 0; $i < count($fieldData); $i++){
 81:             if(in_array($fieldData[$i]->type, array('dropdown', 'text', 'varchar', 'assignment'))
 82:                     && !in_array($fieldData[$i]->fieldName, array('firstName', 'lastName', 'updatedBy', 'priority', 'id'))
 83:             ){ 
 84:                 
 85:                 if($fieldData[$i]->relevance == 'High')
 86:                     $relevance = 3;
 87:                 elseif($fieldData[$i]->relevance == 'Medium')
 88:                     $relevance = 2;
 89:                 else
 90:                     $relevance = 1;
 91: 
 92:                 $fields[$fieldData[$i]->fieldName] = array(
 93:                     'type' => $fieldData[$i]->type,
 94:                     'linkType' => $fieldData[$i]->linkType,
 95:                     'relevance' => $relevance
 96:                 );
 97:             }
 98:         }
 99: 
100:         $t0 = microtime(true);
101: 
102: 
103:         $totalCount = Yii::app()->db->createCommand('SELECT count(*) from x2_contacts;')->queryScalar();
104: 
105:         $dataProvider = new CSqlDataProvider('SELECT '.implode(',', array_merge(array_keys($fields), array('id', 'visibility'))).' FROM x2_contacts', array(
106:                     
107:                     
108:                     
109:                     'totalItemCount' => $totalCount,
110:                     'sort' => array('defaultOrder' => 'id ASC'),
111:                     'pagination' => array(
112:                         'pageSize' => 500,
113:                     ),
114:                 ));
115:         $dataProvider->getData();
116: 
117: 
118:         $pages = $dataProvider->pagination->getPageCount();
119:         echo $pages.' pages.<br>';
120:         $searchTerms = array();
121: 
122:         
123: 
124:         ob_end_flush();
125: 
126:         $keys = array();
127:         $tokenChars = " \n\r\t!$%^&*()_+-=~[]{}\\|:;'\",.<>?/`‘’•–—“”";
128:         $noiseWords = array(
129:             'a', 'about', 'after', 'all', 'also', 'an', 'and', 'another', 'any', 'are', 'arent', 'as', 'at', 'back', 'be', 'because', 'been', 'before',
130:             'being', 'between', 'both', 'but', 'by', 'came', 'can', 'cant', 'come', 'contact', 'contacts', 'contacted', 'could', 'data', 'did', 'didnt',
131:             'do', 'dont', 'does', 'doesnt', 'each', 'for', 'from', 'get', 'go', 'going', 'goes', 'got', 'has', 'hasnt', 'had', 'hadnt', 'he', 'hes', 'his',
132:             'hed', 'have', 'havent', 'her', 'hers', 'here', 'heres', 'him', 'himself', 'how', 'i', 'if', 'in', 'into', 'is', 'it', 'its', 'like', 'make',
133:             'made', 'makes', 'many', 'me', 'might', 'mightnt', 'more', 'most', 'much', 'must', 'mustnt', 'my', 'mine', 'never', 'no', 'now', 'not', 'of',
134:             'on', 'only', 'onto', 'or', 'other', 'our', 'out', 'over', 'said', 'same', 'see', 'she', 'shes', 'should', 'shouldnt', 'since', 'some', 'still',
135:             'such', 'take', 'than', 'that', 'the', 'their', 'them', 'then', 'there', 'theres', 'these', 'they', 'theyre', 'this', 'those', 'through', 'to',
136:             'too', 'today', 'under', 'up', 'very', 'want', 'wants', 'wanted', 'was', 'wasnt', 'way', 'ways', 'we', 'well', 'were', 'what', 'whats', 'where',
137:             'which', 'while', 'who', 'why', 'will', 'with', 'would', 'wont', 'you', 'your', 'youre'
138:         );
139: 
140: 
141:         for($i = 1; $i <= $pages; ++$i){
142:             
143: 
144:             $links = array();
145: 
146:             $dataProvider->pagination->setCurrentPage($i);
147: 
148:             foreach($dataProvider->getData($i > 1) as $record){
149:                 
150:                 foreach($fields as $fieldName => &$field){
151:                     
152: 
153:                     if(!empty($record[$fieldName])){
154:                         
155:                         $token = strtok(preg_replace('/(?<=\w)\'(?=\w)/u', '', $record[$fieldName]), $tokenChars);
156:                         while($token !== false){
157:                             $token = strtolower($token);
158: 
159:                             if(strlen($token) <= 50 && !in_array($token, $noiseWords)){
160:                                 $links[] = array(
161:                                     $token,
162:                                     'Contacts',
163:                                     $record['id'],
164:                                     $field['relevance'],
165:                                     $record['assignedTo'],
166:                                     $record['visibility']
167:                                 );
168:                             }
169:                             $token = strtok($tokenChars);
170:                         }
171:                     }
172:                 }
173:                 unset($field);
174:             }
175: 
176:             $sql = 'INSERT INTO x2_search (keyword, modelType, modelId, relevance, assignedTo, visibility) VALUES ';
177:             for($j = 0; $j < count($links); ++$j){
178:                 $sql .= '(?,?,?,?,?,?)';
179:                 if($j < count($links) - 1)
180:                     $sql .= ',';
181:             }
182: 
183:             
184:             
185:             
186: 
187:             $query = Yii::app()->db->createCommand($sql);
188:             for($j = 0; $j < count($links); ++$j){
189:                 $query = $query->bindValues(array(
190:                     6 * $j + 1 => $links[$j][0],
191:                     6 * $j + 2 => $links[$j][1],
192:                     6 * $j + 3 => $links[$j][2],
193:                     6 * $j + 4 => $links[$j][3],
194:                     6 * $j + 5 => $links[$j][4],
195:                     6 * $j + 6 => $links[$j][5]
196:                         ));
197:             }
198:             
199:             
200:             $query->execute();
201: 
202:             
203:             echo "Page $i...done<br>";
204:             flush();
205:         }
206: 
207:         
208: 
209:         echo 'Time: '.(microtime(true) - $t0).'<br>';
210:     }
211: 
212:     public function actionFastSearch(){
213: 
214:     }
215: 
216:     217: 218: 219: 220: 
221:     public function actionSearch(){
222:         ini_set('memory_limit', -1);
223: 
224:         $term = isset($_GET['term']) ? $_GET['term'] : "";
225:         if (empty($term)) {
226:             $dataProvider = new CArrayDataProvider(array());
227:             Yii::app()->user->setFlash ('error', Yii::t('app', "Search term cannot be empty."));
228:             $this->render('search', array(
229:                 'dataProvider' => $dataProvider,
230:             ));
231:         } else {
232: 
233:             if(substr($term, 0, 1) != "#"){
234:     
235:                 $modules = Modules::model()->findAllByAttributes(array('searchable' => 1));
236:                 $comparisons = array();
237:                 $other = array();
238:                 foreach($modules as $module){
239:                     $module->name == 'products' ? $type = ucfirst('Product') : $type = ucfirst($module->name);
240:                     $module->name == 'quotes' ? $type = ucfirst('Quote') : $type = $type;
241:                     $module->name == 'opportunities' ? $type = ucfirst('Opportunity') : $type = $type;
242:                     $criteria = new CDbCriteria();
243:                     $fields = Fields::model()->findAllByAttributes(array('modelName' => $type, 'searchable' => 1));
244:                     $temp = array();
245:                     $fieldNames = array();
246:                     if(count($fields) < 1){
247:                         $criteria->compare('id', '<0', true, 'AND');
248:                     }
249:                     foreach($fields as $field){
250:                         $temp[] = $field->id;
251:                         $fieldNames[] = $field->fieldName;
252:                         $criteria->compare($field->fieldName, $term, true, "OR");
253:                         if($field->type == 'phone'){
254:                             $tempPhone = preg_replace('/\D/', '', $term);
255:                             $phoneLookup = PhoneNumber::model()->findByAttributes(array('modelType' => $field->modelName, 'number' => $tempPhone, 'fieldName' => $field->fieldName));
256:                             if(isset($phoneLookup)){
257:                                 $criteria->compare('id', $phoneLookup->modelId, true, "OR");
258:                             }
259:                         }
260:                     }
261:                     if(Yii::app()->user->getName() != 'admin' && X2Model::model($type)->hasAttribute('visibility') && X2Model::model($type)->hasAttribute('assignedTo')){
262:                         $condition = 'visibility="1" OR (assignedTo="Anyone" AND visibility!="0")  OR assignedTo="'.Yii::app()->user->getName().'"';
263:                         
264:                         $groupLinks = Yii::app()->db->createCommand()->select('groupId')->from('x2_group_to_user')->where('userId='.Yii::app()->user->getId())->queryColumn();
265:                         if(!empty($groupLinks))
266:                             $condition .= ' OR assignedTo IN ('.implode(',', $groupLinks).')';
267:     
268:                         $condition .= 'OR (visibility=2 AND assignedTo IN
269:                             (SELECT username FROM x2_group_to_user WHERE groupId IN
270:                                 (SELECT groupId FROM x2_group_to_user WHERE userId='.Yii::app()->user->getId().')))';
271:                         $criteria->addCondition($condition);
272:                     }
273:                     if($module->name == 'actions'){
274:                         $criteria->with = array('actionText');
275:                         $criteria->compare('actionText.text', $term, true, "OR");
276:                     }
277:                     if(class_exists($type)){
278:                         $arr = X2Model::model($type)->findAll($criteria);
279:                         $comparisons[$type] = $temp;
280:                         $other[$type] = $arr;
281:                     }
282:                 }
283:                 $high = array();
284:                 $medium = array();
285:                 $low = array();
286:     
287:                 $userHigh = array();
288:                 $userMedium = array();
289:                 $userLow = array();
290:     
291:                 $records = array();
292:                 $userRecords = array();
293:     
294:                 $regEx = "/".preg_quote($term, '/')."/i";
295:     
296:                 foreach($other as $key => $recordType){
297:                     $fieldList = $comparisons[$key];
298:                     foreach($recordType as $otherRecord){
299:                         if($key == 'Actions'){
300:                             if($otherRecord->hasAttribute('assignedTo') && $otherRecord->assignedTo == Yii::app()->user->getName())
301:                                 $userHigh[] = $otherRecord;
302:                             else
303:                                 $high[] = $otherRecord;
304:                         }else{
305:                             foreach($fieldList as $field){
306:                                 $fieldRecord = Fields::model()->findByPk($field);
307:                                 $fieldName = $fieldRecord->fieldName;
308:                                 if(preg_match($regEx, $otherRecord->$fieldName) > 0){
309:                                     switch($fieldRecord->relevance){
310:                                         case "High":
311:                                             if(!in_array($otherRecord, $high, true) && !in_array($otherRecord, $medium, true) && !in_array($otherRecord, $low, true) &&
312:                                                     !in_array($otherRecord, $userHigh, true) && !in_array($otherRecord, $userMedium, true) && !in_array($otherRecord, $userLow, true)){
313:                                                 if($otherRecord->hasAttribute('assignedTo') && $otherRecord->assignedTo == Yii::app()->user->getName())
314:                                                     $userHigh[] = $otherRecord;
315:                                                 else
316:                                                     $high[] = $otherRecord;
317:                                             }
318:                                             break;
319:                                         case "Medium":
320:                                             if(!in_array($otherRecord, $high, true) && !in_array($otherRecord, $medium, true) && !in_array($otherRecord, $low, true) &&
321:                                                     !in_array($otherRecord, $userHigh, true) && !in_array($otherRecord, $userMedium, true) && !in_array($otherRecord, $userLow, true)){
322:                                                 if($otherRecord->hasAttribute('assignedTo') && $otherRecord->assignedTo == Yii::app()->user->getName())
323:                                                     $userMedium[] = $otherRecord;
324:                                                 else
325:                                                     $medium[] = $otherRecord;
326:                                             }
327:                                             break;
328:                                         case "Low":
329:                                             if(!in_array($otherRecord, $high, true) && !in_array($otherRecord, $medium, true) && !in_array($otherRecord, $low, true) &&
330:                                                     !in_array($otherRecord, $userHigh, true) && !in_array($otherRecord, $userMedium, true) && !in_array($otherRecord, $userLow, true)){
331:                                                 if($otherRecord->hasAttribute('assignedTo') && $otherRecord->assignedTo == Yii::app()->user->getName())
332:                                                     $userLow[] = $otherRecord;
333:                                                 else
334:                                                     $low[] = $otherRecord;
335:                                             }
336:                                             break;
337:                                         default:
338:                                             if($otherRecord->hasAttribute('assignedTo') && $otherRecord->assignedTo == Yii::app()->user->getName())
339:                                                 $userLow[] = $otherRecord;
340:                                             else
341:                                                 $low[] = $otherRecord;
342:                                     }
343:                                 }elseif($fieldRecord->type == 'phone'){
344:                                     $tempPhone = preg_replace('/\D/', '', $term);
345:     
346:                                     if(strlen($tempPhone) == 10){
347:                                         $phoneLookup = PhoneNumber::model()->findByAttributes(array('modelType' => $fieldRecord->modelName, 'number' => $tempPhone, 'fieldName' => $fieldName));
348:                                         if(!in_array($otherRecord, $high, true) && !in_array($otherRecord, $medium, true) && !in_array($otherRecord, $low, true) &&
349:                                                 !in_array($otherRecord, $userHigh, true) && !in_array($otherRecord, $userMedium, true) && !in_array($otherRecord, $userLow, true)){
350:                                             if(isset($phoneLookup) && $otherRecord->id == $phoneLookup->modelId){
351:                                                 if($otherRecord->hasAttribute('assignedTo') && $otherRecord->assignedTo == Yii::app()->user->getName())
352:                                                     $userHigh[] = $otherRecord;
353:                                                 else
354:                                                     $high[] = $otherRecord;
355:                                             }
356:                                         }
357:                                     }
358:                                 }
359:                             }
360:                         }
361:                     }
362:                 }
363:                 $records = array_merge($high, $medium);
364:                 $records = array_merge($records, $low);
365:     
366:                 $userRecords = array_merge($userHigh, $userMedium);
367:                 $userRecords = array_merge($userRecords, $userLow);
368:     
369:                 $records = array_merge($userRecords, $records);
370:     
371:                 $records = Record::convert($records, false);
372:                 if(count($records) == 1){
373:                     
374:                     
375:                     
376:                     
377:                     if(!empty($records[0]['#recordUrl'])) {
378:                         $this->redirect($records[0]['#recordUrl']);
379:                     }
380:                 }
381:                 $dataProvider = new CArrayDataProvider($records, array(
382:                             'id' => 'id',
383:                             'pagination' => array(
384:                                 'pageSize' => Profile::getResultsPerPage(),
385:                             ),
386:                         ));
387:     
388:                 $this->render('search', array(
389:                     'records' => $records,
390:                     'dataProvider' => $dataProvider,
391:                     'term' => $term,
392:                 ));
393:             }else{
394:                 Yii::app()->user->setState('vcr-list', $term);
395:                 $_COOKIE['vcr-list'] = $term;
396:                 $tagQuery = "
397:                     SELECT * 
398:                     FROM x2_tags
399:                     WHERE tag=:tag
400:                     group BY tag, type, itemId";
401:                 $params = array (':tag' => $term);
402: 
403:                 
404:                 $sql = Yii::app()->db->createCommand ($tagQuery);
405:                 $totalItemCount = Yii::app()->db->createCommand ("
406:                     SELECT count(*)
407:                     FROM ($tagQuery) as t1;
408:                 ")->queryScalar ($params);
409: 
410:                 $results = new CSqlDataProvider ($sql, array (
411:                     'totalItemCount' => $totalItemCount,
412:                     'sort' => array(
413:                         'defaultOrder' => 'timestamp DESC',
414:                     ),
415:                     'pagination' => array(
416:                         'pageSize' => Profile::getResultsPerPage(),
417:                     ),
418:                     'params' => $params,
419:                 ));
420:                 $this->render('searchTags', array(
421:                     'tags' => $results,
422:                     'term' => $term,
423:                 ));
424:             }
425:         }
426:     }
427: 
428: }
429: 
430: ?>
431: