]> CyberLeo.Net >> Repos - Github/sugarcrm.git/blob - include/SearchForm/SugarSpot.php
Release 6.2.0
[Github/sugarcrm.git] / include / SearchForm / SugarSpot.php
1 <?php
2 if(!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point');
3 /*********************************************************************************
4  * SugarCRM Community Edition is a customer relationship management program developed by
5  * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc.
6  * 
7  * This program is free software; you can redistribute it and/or modify it under
8  * the terms of the GNU Affero General Public License version 3 as published by the
9  * Free Software Foundation with the addition of the following permission added
10  * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK
11  * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY
12  * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
13  * 
14  * This program is distributed in the hope that it will be useful, but WITHOUT
15  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
16  * FOR A PARTICULAR PURPOSE.  See the GNU Affero General Public License for more
17  * details.
18  * 
19  * You should have received a copy of the GNU Affero General Public License along with
20  * this program; if not, see http://www.gnu.org/licenses or write to the Free
21  * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
22  * 02110-1301 USA.
23  * 
24  * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road,
25  * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com.
26  * 
27  * The interactive user interfaces in modified source and object code versions
28  * of this program must display Appropriate Legal Notices, as required under
29  * Section 5 of the GNU Affero General Public License version 3.
30  * 
31  * In accordance with Section 7(b) of the GNU Affero General Public License version 3,
32  * these Appropriate Legal Notices must retain the display of the "Powered by
33  * SugarCRM" logo. If the display of the logo is not reasonably feasible for
34  * technical reasons, the Appropriate Legal Notices must display the words
35  * "Powered by SugarCRM".
36  ********************************************************************************/
37
38
39 class SugarSpot
40 {
41         /**
42          * Performs the search and returns the HTML widget containing the results
43          *
44          * @param  $query   string what we are searching for
45          * @param  $modules array  modules we are searching in
46          * @param  $offset  int    search result offset
47          * @return string HTML widget
48          */
49         public function searchAndDisplay(
50             $query,
51             $modules,
52             $offset = -1
53             )
54         {
55                 $query_encoded = urlencode($query);
56             $results = $this->_performSearch($query, $modules, $offset);
57
58                 $str = '<div id="SpotResults">';
59
60                 $actions=0;
61                 $foundData = false;
62                 foreach($results as $m=>$data){
63                         if(empty($data['data'])){
64                                 continue;
65                         }
66
67                         $foundData = true;
68
69                         $countRemaining = $data['pageData']['offsets']['total'] - count($data['data']);
70                         if($offset > 0) $countRemaining -= $offset;
71                         $more = '';
72                         $data['pageData']['offsets']['next']++;
73                         if($countRemaining > 0){
74                                 $more = <<<EOHTML
75 <small class='more' onclick="DCMenu.spotZoom('$query', '$m','{$data['pageData']['offsets']['next']}' )">($countRemaining {$GLOBALS['app_strings']['LBL_SEARCH_MORE']})</small>
76 EOHTML;
77                         }
78
79                         $modDisplayString = $m;
80                         if(isset($GLOBALS['app_list_strings']['moduleList'][$m]))
81                             $modDisplayString = $GLOBALS['app_list_strings']['moduleList'][$m];
82
83                         $str.= "<div>{$modDisplayString} $more</div>";
84                         $str.= '<ul>';
85                         foreach($data['data'] as $row){
86                                 $name = '';
87                                 
88                                 if(!empty($row['NAME'])){
89                                         $name = $row['NAME'];
90                                 } else if(!empty($row['DOCUMENT_NAME'])) {
91                                     $name = $row['DOCUMENT_NAME'];
92                                 } else {
93                                         foreach($row as $k=>$v){
94                                                 if(strpos($k, 'NAME') !== false && !empty($row[$k])){
95                                                         $name = $v;
96                                                         break;
97                                                 }
98                                         }
99
100                                         if(empty($name))
101                                         {
102                                                 foreach($row as $k=>$v){
103                                                         if(strpos($k, 'NAME') !== false){
104                                                                 $name = $v;
105                                                                 break;
106                                                         }
107                                                 }
108                                         }
109                                 }
110
111                                     $str .= <<<EOHTML
112 <li><a href="index.php?module={$data['pageData']['bean']['moduleDir']}&action=DetailView&record={$row['ID']}">$name</a></li>
113 EOHTML;
114                         }
115                         $str.= '</ul>';
116                 }
117
118                 if($foundData)
119                 {
120                         $str = <<<EOHTML
121                         <button onclick="document.location.href='index.php?module=Home&action=UnifiedSearch&search_form=false&advanced=false&query_string={$query_encoded}'">{$GLOBALS['app_strings']['LBL_EMAIL_SHOW_READ']}</button>
122                         <br><br>
123                         {$str}
124                         </div>
125                         <p>
126                         <button onclick="document.location.href='index.php?module=Home&action=UnifiedSearch&search_form=false&advanced=false&query_string={$query_encoded}'">{$GLOBALS['app_strings']['LBL_EMAIL_SHOW_READ']}</button>
127 EOHTML;
128                 } else {
129                         $str .= $GLOBALS['app_strings']['LBL_EMAIL_SEARCH_NO_RESULTS'];
130                         $str .= <<<EOHTML
131                         </div>
132                         <p>
133                         <button onclick="document.location.href='index.php?module=Home&action=UnifiedSearch&search_form=false&advanced=false&query_string={$query_encoded}'">{$GLOBALS['app_strings']['LBL_EMAIL_SHOW_READ']}</button>
134 EOHTML;
135
136                 }
137
138                 return $str;
139         }
140
141         /**
142          * Returns the array containing the $searchFields for a module.  This function
143          * first checks the default installation directories for the SearchFields.php file and then
144          * loads any custom definition (if found)
145          *
146          * @param  $moduleName String name of module to retrieve SearchFields entries for
147          * @return array of SearchFields
148          */
149         protected static function getSearchFields(
150             $moduleName
151             )
152         {
153                 $searchFields = array();
154
155                 if(file_exists("modules/{$moduleName}/metadata/SearchFields.php")) 
156                 {
157                     require("modules/{$moduleName}/metadata/SearchFields.php");
158                 }
159                 
160                 if(file_exists("custom/modules/{$moduleName}/metadata/SearchFields.php")) 
161                 {
162                     require("custom/modules/{$moduleName}/metadata/SearchFields.php");
163                 }
164                 
165                 return $searchFields;
166         }
167         
168
169         /**
170          * Get count from query
171          * @param SugarBean $seed
172          * @param string $main_query
173          */
174         protected function _getCount($seed, $main_query)
175         {
176 //        $count_query = $seed->create_list_count_query($main_query);
177                 $result = $seed->db->query("SELECT COUNT(*) as c FROM ($main_query) main");
178                 $row = $seed->db->fetchByAssoc($result);
179                 return isset($row['c'])?$row['c']:0;
180         }
181
182         /**
183          * Performs the search
184          *
185          * @param  $query   string what we are searching for
186          * @param  $modules array  modules we are searching in
187          * @param  $offset  int    search result offset
188          * @return array
189          */
190         protected function _performSearch(
191             $query,
192             $modules,
193             $offset = -1
194             )
195         {
196             if(empty($query)) return array();
197                 $primary_module='';
198                 $results = array();
199                 require_once 'include/SearchForm/SearchForm2.php' ;
200                 $where = '';
201         $searchEmail = preg_match('/^([^%]|%)*@([^%]|%)*$/', $query);
202
203         $limit = ( !empty($GLOBALS['sugar_config']['max_spotresults_initial']) ? $GLOBALS['sugar_config']['max_spotresults_initial'] : 5 );
204                 if($offset !== -1){
205                         $limit = ( !empty($GLOBALS['sugar_config']['max_spotresults_more']) ? $GLOBALS['sugar_config']['max_spotresults_more'] : 20 );
206                 }
207         $totalCounted = empty($GLOBALS['sugar_config']['disable_count_query']);
208         
209                         
210             foreach($modules as $moduleName){
211                     if (empty($primary_module))
212                     {
213                         $primary_module=$moduleName;
214                     } 
215
216                         $searchFields = SugarSpot::getSearchFields($moduleName);                                
217                         
218                         if (empty($searchFields[$moduleName]))
219                         {
220                                 continue;
221                         }
222
223                         $class = $GLOBALS['beanList'][$moduleName];
224                         $return_fields = array();
225                         $seed = new $class();
226             if(!$seed->ACLAccess('ListView')) continue;
227
228                         if ($class == 'aCase') {
229                             $class = 'Case';
230                         }
231                         
232                         foreach($searchFields[$moduleName] as $k=>$v){
233                                 $keep = false;
234                                 $searchFields[$moduleName][$k]['value'] = $query;
235
236                                 if(!empty($GLOBALS['dictionary'][$class]['unified_search'])){
237                                         if(empty($GLOBALS['dictionary'][$class]['fields'][$k]['unified_search'])){
238
239                                                 if(isset($searchFields[$moduleName][$k]['db_field'])){
240                                                         foreach($searchFields[$moduleName][$k]['db_field'] as $field){
241                                                                 if(!empty($GLOBALS['dictionary'][$class]['fields'][$field]['unified_search'])){
242                                                                         $keep = true;
243                                                                 }
244                                                         }
245                                                 }
246                                                 if(!$keep){
247                                                         if(strpos($k,'email') === false || !$searchEmail) {
248                                                                 unset($searchFields[$moduleName][$k]);
249                                                         }
250                                                 }
251                                         }else{
252                                             if($GLOBALS['dictionary'][$class]['fields'][$k]['type'] == 'int' && !is_numeric($query)) {
253                                                 unset($searchFields[$moduleName][$k]);
254                                             }
255                                         }
256                                 }else if(empty($GLOBALS['dictionary'][$class]['fields'][$k]) ){
257                                         //If module did not have unified_search defined, then check the exception for an email search before we unset
258                                         if(strpos($k,'email') === false || !$searchEmail)
259                                         {
260                                            unset($searchFields[$moduleName][$k]);
261                                         }
262                                 }else{
263                                         switch($GLOBALS['dictionary'][$class]['fields'][$k]['type']){
264                                                 case 'id':
265                                                 case 'date':
266                                                 case 'datetime':
267                                                 case 'bool':
268                                                         unset($searchFields[$moduleName][$k]);
269                                                         break;
270                                                 case 'int':
271                                                     if(!is_numeric($query)) {
272                                                         unset($searchFields[$moduleName][$k]);
273                                                         break;
274                                                     }
275                                         }
276                                 }
277                         }
278
279                         if (empty($searchFields[$moduleName])) continue;
280
281                         if(isset($seed->field_defs['name'])) {
282                             $return_fields['name'] = $seed->field_defs['name'];
283                         }
284
285                         foreach($seed->field_defs as $k => $v) {
286                             if(isset($seed->field_defs[$k]['type']) && ($seed->field_defs[$k]['type'] == 'name') && !isset($return_fields[$k])) {
287                                     $return_fields[$k] = $seed->field_defs[$k];
288                                 }
289                         }
290
291                         if(!isset($return_fields['name'])) {
292                             // if we couldn't find any name fields, try search fields that have name in it
293                             foreach($searchFields[$moduleName] as $k => $v) {
294                                 if(strpos($k, 'name') != -1 && isset($seed->field_defs[$k])
295                                     && !isset($seed->field_defs[$k]['source'])) {
296                                         $return_fields[$k] = $seed->field_defs[$k];
297                                         break;
298                                     }
299                             }
300                         }
301
302                         if(!isset($return_fields['name'])) {
303                             // last resort - any fields that have 'name' in their name
304                             foreach($seed->field_defs as $k => $v) {
305                                 if(strpos($k, 'name') != -1 && isset($seed->field_defs[$k])
306                                     && !isset($seed->field_defs[$k]['source'])) {
307                                         $return_fields[$k] = $seed->field_defs[$k];
308                                         break;
309                                     }
310                             }
311                         }
312
313                         if(!isset($return_fields['name'])) {
314                             // FAIL: couldn't find id & name for the module
315                             $GLOBALS['log']->error("Unable to find name for module $moduleName");
316                             continue;
317                         }
318
319                         if(isset($return_fields['name']['fields'])) {
320                             // some names are composite
321                             foreach($return_fields['name']['fields'] as $field) {
322                                 $return_fields[$field] = $seed->field_defs[$field];
323                             }
324                         }
325
326
327                         $searchForm = new SearchForm ( $seed, $moduleName ) ;
328                         $searchForm->setup (array ( $moduleName => array() ) , $searchFields , '' , 'saved_views' /* hack to avoid setup doing further unwanted processing */ ) ;
329                         $where_clauses = $searchForm->generateSearchWhere() ;
330                         
331                         if(empty($where_clauses)) {
332                             continue;
333                         }
334                         if(count($where_clauses) > 1) {
335                             $query_parts =  array();
336
337                             $ret_array_start = $seed->create_new_list_query('', '', $return_fields, array(), 0, '', true, $seed, true);
338                 $search_keys = array_keys($searchFields[$moduleName]);
339
340                 foreach($where_clauses as $n => $clause) {
341                                 $allfields = $return_fields;
342                                 $skey = $search_keys[$n];
343                                 if(isset($seed->field_defs[$skey])) {
344                         // Joins for foreign fields aren't produced unless the field is in result, hence the merge
345                                     $allfields[$skey] = $seed->field_defs[$skey];
346                                 }
347                     $ret_array = $seed->create_new_list_query('', $clause, $allfields, array(), 0, '', true, $seed, true);
348                     $query_parts[] = $ret_array_start['select'] . $ret_array['from'] . $ret_array['where'] . $ret_array['order_by'];
349                 }
350                 $main_query = "(".join(") UNION (", $query_parts).")";
351                         } else {
352                 foreach($searchFields[$moduleName] as $k=>$v){
353                     if(isset($seed->field_defs[$k])) {
354                                     $return_fields[$k] = $seed->field_defs[$k];
355                     }
356                             }
357                             $ret_array = $seed->create_new_list_query('', $where_clauses[0], $return_fields, array(), 0, '', true, $seed, true);
358                         $main_query = $ret_array['select'] . $ret_array['from'] . $ret_array['where'] . $ret_array['order_by'];
359                         }
360
361                         $totalCount = null;
362                     if($limit < -1) {
363                             $result = $seed->db->query($main_query);
364                     } else {
365                             if($limit == -1) {
366                                     $limit = $GLOBALS['sugar_config']['list_max_entries_per_page'];
367                 }
368
369                 if($offset == 'end') {
370                             $totalCount = $this->_getCount($seed, $main_query);
371                             if($totalCount) {
372                             $offset = (floor(($totalCount -1) / $limit)) * $limit;
373                             } else {
374                                 $offset = 0;
375                             }
376                 }
377                 $result = $seed->db->limitQuery($main_query, $offset, $limit + 1);
378                     }
379
380             $data = array();
381             $count = 0;
382             while($count < $limit && ($row = $seed->db->fetchByAssoc($result))) {
383                         $temp = clone $seed;
384                             $temp->setupCustomFields($temp->module_dir);
385                                 $temp->loadFromRow($row);
386                                 $data[] = $temp->get_list_view_data($return_fields);
387                                 $count++;
388                     }
389
390                 $nextOffset = -1;
391                 $prevOffset = -1;
392                 $endOffset = -1;
393
394                 if($count >= $limit) {
395                         $nextOffset = $offset + $limit;
396                 }
397
398                 if($offset > 0) {
399                         $prevOffset = $offset - $limit;
400                         if($prevOffset < 0) $prevOffset = 0;
401                 }
402
403                 if( $count >= $limit && $totalCounted){
404                     if(!isset($totalCount)) {
405                             $totalCount  = $this->_getCount($seed, $main_query);
406                     }
407                 } else {
408                     $totalCount = $count + $offset;
409                 }
410
411             $pageData['offsets'] = array( 'current'=>$offset, 'next'=>$nextOffset, 'prev'=>$prevOffset, 'end'=>$endOffset, 'total'=>$totalCount, 'totalCounted'=>$totalCounted);
412                     $pageData['bean'] = array('objectName' => $seed->object_name, 'moduleDir' => $seed->module_dir);
413
414                     $results[$moduleName] = array("data" => $data, "pageData" => $pageData);
415                 }
416         return $results;
417         }
418
419         /**
420      * Function used to walk the array and find keys that map the queried string.
421      * if both the pattern and module name is found the promote the string to thet top.
422      */
423     protected function _searchKeys(
424         $item1,
425         $key,
426         $patterns
427         )
428     {
429         //make the module name singular....
430         if ($patterns[1][strlen($patterns[1])-1] == 's') {
431             $patterns[1]=substr($patterns[1],0,(strlen($patterns[1])-1));
432         }
433
434         $module_exists = stripos($key,$patterns[1]); //primary module name.
435         $pattern_exists = stripos($key,$patterns[0]); //pattern provided by the user.
436         if ($module_exists !== false and $pattern_exists !== false)  {
437             $GLOBALS['matching_keys']= array_merge(array(array('NAME'=>$key, 'ID'=>$key, 'VALUE'=>$item1)),$GLOBALS['matching_keys']);
438         }
439         else {
440             if ($pattern_exists !== false) {
441                 $GLOBALS['matching_keys'][]=array('NAME'=>$key, 'ID'=>$key, 'VALUE'=>$item1);
442             }
443         }
444     }
445 }