%PDF- %PDF-
| Direktori : /var/www/crm/include/SearchForm/ |
| Current File : /var/www/crm/include/SearchForm/SugarSpot.php |
<?php
//if(!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point');
/*********************************************************************************
* SugarCRM Community Edition is a customer relationship management program developed by
* SugarCRM, Inc. Copyright (C) 2004-2012 SugarCRM Inc.
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU Affero General Public License version 3 as published by the
* Free Software Foundation with the addition of the following permission added
* to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK
* IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY
* OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
* details.
*
* You should have received a copy of the GNU Affero General Public License along with
* this program; if not, see http://www.gnu.org/licenses or write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301 USA.
*
* You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road,
* SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com.
*
* The interactive user interfaces in modified source and object code versions
* of this program must display Appropriate Legal Notices, as required under
* Section 5 of the GNU Affero General Public License version 3.
*
* In accordance with Section 7(b) of the GNU Affero General Public License version 3,
* these Appropriate Legal Notices must retain the display of the "Powered by
* SugarCRM" logo. If the display of the logo is not reasonably feasible for
* technical reasons, the Appropriate Legal Notices must display the words
* "Powered by SugarCRM".
********************************************************************************/
/**
* Global search
* @api
*/
class SugarSpot
{
protected $module = "";
/**
* @param string $current_module
*/
public function __construct($current_module = "")
{
$this->module = $current_module;
}
/**
* searchAndDisplay
*
* Performs the search and returns the HTML widget containing the results
*
* @param $query string what we are searching for
* @param $modules array modules we are searching in
* @param $offset int search result offset
* @return string HTML code containing results
*
* @deprecated deprecated since 6.5
*/
public function searchAndDisplay($query, $modules, $offset=-1)
{
$query_encoded = urlencode($query);
$formattedResults = $this->formatSearchResultsToDisplay($query, $modules, $offset);
$displayMoreForModule = $formattedResults['displayMoreForModule'];
$displayResults = $formattedResults['displayResults'];
$ss = new Sugar_Smarty();
$ss->assign('displayResults', $displayResults);
$ss->assign('displayMoreForModule', $displayMoreForModule);
$ss->assign('appStrings', $GLOBALS['app_strings']);
$ss->assign('appListStrings', $GLOBALS['app_list_strings']);
$ss->assign('queryEncoded', $query_encoded);
$template = 'include/SearchForm/tpls/SugarSpot.tpl';
if(file_exists('custom/include/SearchForm/tpls/SugarSpot.tpl'))
{
$template = 'custom/include/SearchForm/tpls/SugarSpot.tpl';
}
return $ss->fetch($template);
}
protected function formatSearchResultsToDisplay($query, $modules, $offset=-1)
{
$results = $this->_performSearch($query, $modules, $offset);
$displayResults = array();
$displayMoreForModule = array();
//$actions=0;
foreach($results as $m=>$data)
{
if(empty($data['data']))
{
continue;
}
$countRemaining = $data['pageData']['offsets']['total'] - count($data['data']);
if($offset > 0)
{
$countRemaining -= $offset;
}
if($countRemaining > 0)
{
$displayMoreForModule[$m] = array('query'=>$query,
'offset'=>$data['pageData']['offsets']['next']++,
'countRemaining'=>$countRemaining);
}
foreach($data['data'] as $row)
{
$name = '';
//Determine a name to use
if(!empty($row['NAME']))
{
$name = $row['NAME'];
}
else if(!empty($row['DOCUMENT_NAME']))
{
$name = $row['DOCUMENT_NAME'];
}
else
{
$foundName = '';
foreach($row as $k=>$v)
{
if(strpos($k, 'NAME') !== false)
{
if(!empty($row[$k]))
{
$name = $v;
break;
}
else if(empty($foundName))
{
$foundName = $v;
}
}
}
if(empty($name))
{
$name = $foundName;
}
}
$displayResults[$m][$row['ID']] = $name;
}
}
return array('displayResults' => $displayResults, 'displayMoreForModule' => $displayMoreForModule);
}
/**
* Returns the array containing the $searchFields for a module. This function
* first checks the default installation directories for the SearchFields.php file and then
* loads any custom definition (if found)
*
* @param $moduleName String name of module to retrieve SearchFields entries for
* @return array of SearchFields
*/
protected static function getSearchFields( $moduleName )
{
$searchFields = array();
if(file_exists("modules/{$moduleName}/metadata/SearchFields.php"))
{
require("modules/{$moduleName}/metadata/SearchFields.php");
}
if(file_exists("custom/modules/{$moduleName}/metadata/SearchFields.php"))
{
require("custom/modules/{$moduleName}/metadata/SearchFields.php");
}
return $searchFields;
}
/**
* Get count from query
* @param SugarBean $seed
* @param string $main_query
*/
protected function _getCount($seed, $main_query)
{
$result = $seed->db->query("SELECT COUNT(*) as c FROM ($main_query) main");
$row = $seed->db->fetchByAssoc($result);
return isset($row['c'])?$row['c']:0;
}
/**
* Determine which modules should be searched against.
*
* @return array
*/
protected function getSearchModules()
{
$usa = new UnifiedSearchAdvanced();
$unified_search_modules_display = $usa->getUnifiedSearchModulesDisplay();
// load the list of unified search enabled modules
$modules = array();
//check to see if the user has customized the list of modules available to search
$users_modules = $GLOBALS['current_user']->getPreference('globalSearch', 'search');
if(!empty($users_modules))
{
// use user's previous selections
foreach ($users_modules as $key => $value )
{
if (isset($unified_search_modules_display[$key]) && !empty($unified_search_modules_display[$key]['visible']))
{
$modules[$key] = $key;
}
}
}
else
{
foreach($unified_search_modules_display as $key=>$data)
{
if (!empty($data['visible']))
{
$modules[$key] = $key;
}
}
}
// make sure the current module appears first in the list
if(isset($modules[$this->module]))
{
unset($modules[$this->module]);
$modules = array_merge(array($this->module=>$this->module),$modules);
}
return $modules;
}
/**
* Perform a search
*
* @param $query string what we are searching for
* @param $offset int search result offset
* @return array
*/
public function search($query, $offset = -1, $limit = 20, $options = array())
{
if( isset($options['modules']) && !empty($options['modules']) )
$modules = $options['modules'];
else
$modules = $this->getSearchModules();
return $this->_performSearch($query, $modules, $offset, $limit);
}
/**
* _performSearch
*
* Performs the search from the global search field.
*
* @param $query string what we are searching for
* @param $modules array modules we are searching in
* @param $offset int search result offset
* @param $limit int search limit
* @return array
*/
protected function _performSearch($query, $modules, $offset = -1, $limit = 20)
{
if(empty($query)) return array();
$primary_module='';
$results = array();
require_once 'include/SearchForm/SearchForm2.php' ;
$where = '';
$searchEmail = preg_match('/^([^%]|%)*@([^%]|%)*$/', $query);
// bug49650 - strip out asterisks from query in case
// user thinks asterisk is a wildcard value
$query = str_replace( '*' , '' , $query );
$limit = !empty($GLOBALS['sugar_config']['max_spotresults_initial']) ? $GLOBALS['sugar_config']['max_spotresults_initial'] : 5;
if($offset !== -1){
$limit = !empty($GLOBALS['sugar_config']['max_spotresults_more']) ? $GLOBALS['sugar_config']['max_spotresults_more'] : 20;
}
$totalCounted = empty($GLOBALS['sugar_config']['disable_count_query']);
foreach($modules as $moduleName)
{
if (empty($primary_module))
{
$primary_module=$moduleName;
}
$searchFields = SugarSpot::getSearchFields($moduleName);
if (empty($searchFields[$moduleName]))
{
continue;
}
$class = $GLOBALS['beanList'][$moduleName];
$return_fields = array();
$seed = new $class();
if(!$seed->ACLAccess('ListView')) continue;
if ($class == 'aCase')
{
$class = 'Case';
}
foreach($searchFields[$moduleName] as $k=>$v)
{
$keep = false;
$searchFields[$moduleName][$k]['value'] = $query;
if(!empty($searchFields[$moduleName][$k]['force_unifiedsearch']))
{
continue;
}
if(!empty($GLOBALS['dictionary'][$class]['unified_search'])){
if(empty($GLOBALS['dictionary'][$class]['fields'][$k]['unified_search'])){
if(isset($searchFields[$moduleName][$k]['db_field']))
{
foreach($searchFields[$moduleName][$k]['db_field'] as $field)
{
if(!empty($GLOBALS['dictionary'][$class]['fields'][$field]['unified_search']))
{
if(isset($GLOBALS['dictionary'][$class]['fields'][$field]['type']))
{
if(!$this->filterSearchType($GLOBALS['dictionary'][$class]['fields'][$field]['type'], $query))
{
unset($searchFields[$moduleName][$k]);
continue;
}
}
$keep = true;
}
} //foreach
}
# Bug 42961 Spot search for custom fields
if (!$keep && (isset($v['force_unifiedsearch']) == false || $v['force_unifiedsearch'] != true))
{
if(strpos($k,'email') === false || !$searchEmail) {
unset($searchFields[$moduleName][$k]);
}
}
}else{
if($GLOBALS['dictionary'][$class]['fields'][$k]['type'] == 'int' && !is_numeric($query)) {
unset($searchFields[$moduleName][$k]);
}
}
}else if(empty($GLOBALS['dictionary'][$class]['fields'][$k]) ){
//If module did not have unified_search defined, then check the exception for an email search before we unset
if(strpos($k,'email') === false || !$searchEmail)
{
unset($searchFields[$moduleName][$k]);
}
}else if(!$this->filterSearchType($GLOBALS['dictionary'][$class]['fields'][$k]['type'], $query)){
unset($searchFields[$moduleName][$k]);
}
} //foreach
//If no search field criteria matched then continue to next module
if (empty($searchFields[$moduleName]))
{
continue;
}
if (empty($searchFields[$moduleName])) continue;
if(isset($seed->field_defs['name']))
{
$return_fields['name'] = $seed->field_defs['name'];
}
foreach($seed->field_defs as $k => $v)
{
if(isset($seed->field_defs[$k]['type']) && ($seed->field_defs[$k]['type'] == 'name') && !isset($return_fields[$k]))
{
$return_fields[$k] = $seed->field_defs[$k];
}
}
if(!isset($return_fields['name']))
{
// if we couldn't find any name fields, try search fields that have name in it
foreach($searchFields[$moduleName] as $k => $v)
{
if(strpos($k, 'name') != -1 && isset($seed->field_defs[$k]) && !isset($seed->field_defs[$k]['source']))
{
$return_fields[$k] = $seed->field_defs[$k];
break;
}
}
}
if(!isset($return_fields['name']))
{
// last resort - any fields that have 'name' in their name
foreach($seed->field_defs as $k => $v)
{
if(strpos($k, 'name') != -1 && isset($seed->field_defs[$k])
&& !isset($seed->field_defs[$k]['source'])) {
$return_fields[$k] = $seed->field_defs[$k];
break;
}
}
}
if(!isset($return_fields['name']))
{
// FAIL: couldn't find id & name for the module
$GLOBALS['log']->error("Unable to find name for module $moduleName");
continue;
}
if(isset($return_fields['name']['fields']))
{
// some names are composite
foreach($return_fields['name']['fields'] as $field)
{
$return_fields[$field] = $seed->field_defs[$field];
}
}
$searchForm = new SearchForm ( $seed, $moduleName ) ;
$searchForm->setup (array ( $moduleName => array() ) , $searchFields , '' , 'saved_views' /* hack to avoid setup doing further unwanted processing */ ) ;
$where_clauses = $searchForm->generateSearchWhere() ;
if(empty($where_clauses))
{
continue;
}
if(count($where_clauses) > 1)
{
$query_parts = array();
$ret_array_start = $seed->create_new_list_query('', '', $return_fields, array(), 0, '', true, $seed, true);
$search_keys = array_keys($searchFields[$moduleName]);
foreach($where_clauses as $n => $clause)
{
$allfields = $return_fields;
$skey = $search_keys[$n];
if(isset($seed->field_defs[$skey]))
{
// Joins for foreign fields aren't produced unless the field is in result, hence the merge
$allfields[$skey] = $seed->field_defs[$skey];
}
$ret_array = $seed->create_new_list_query('', $clause, $allfields, array(), 0, '', true, $seed, true);
$query_parts[] = $ret_array_start['select'] . $ret_array['from'] . $ret_array['where'] . $ret_array['order_by'];
}
$main_query = "(".join(") UNION (", $query_parts).")";
}
else
{
foreach($searchFields[$moduleName] as $k=>$v)
{
if(isset($seed->field_defs[$k]))
{
$return_fields[$k] = $seed->field_defs[$k];
}
}
$ret_array = $seed->create_new_list_query('', $where_clauses[0], $return_fields, array(), 0, '', true, $seed, true);
$main_query = $ret_array['select'] . $ret_array['from'] . $ret_array['where'] . $ret_array['order_by'];
}
$totalCount = null;
if($limit < -1)
{
$result = $seed->db->query($main_query);
}
else
{
if($limit == -1)
{
$limit = $GLOBALS['sugar_config']['list_max_entries_per_page'];
}
if($offset == 'end')
{
$totalCount = $this->_getCount($seed, $main_query);
if($totalCount)
{
$offset = (floor(($totalCount -1) / $limit)) * $limit;
} else
{
$offset = 0;
}
}
$result = $seed->db->limitQuery($main_query, $offset, $limit + 1);
}
$data = array();
$count = 0;
while($count < $limit && ($row = $seed->db->fetchByAssoc($result)))
{
$temp = clone $seed;
$temp->setupCustomFields($temp->module_dir);
$temp->loadFromRow($row);
$data[] = $temp->get_list_view_data($return_fields);
$count++;
}
$nextOffset = -1;
$prevOffset = -1;
$endOffset = -1;
if($count >= $limit)
{
$nextOffset = $offset + $limit;
}
if($offset > 0)
{
$prevOffset = $offset - $limit;
if($prevOffset < 0) $prevOffset = 0;
}
if( $count >= $limit && $totalCounted)
{
if(!isset($totalCount))
{
$totalCount = $this->_getCount($seed, $main_query);
}
} else
{
$totalCount = $count + $offset;
}
$pageData['offsets'] = array( 'current'=>$offset, 'next'=>$nextOffset, 'prev'=>$prevOffset, 'end'=>$endOffset, 'total'=>$totalCount, 'totalCounted'=>$totalCounted);
$pageData['bean'] = array('objectName' => $seed->object_name, 'moduleDir' => $seed->module_dir);
$results[$moduleName] = array("data" => $data, "pageData" => $pageData);
}
return $results;
}
/**
* Function used to walk the array and find keys that map the queried string.
* if both the pattern and module name is found the promote the string to thet top.
*/
protected function _searchKeys($item1, $key, $patterns)
{
//make the module name singular....
if ($patterns[1][strlen($patterns[1])-1] == 's')
{
$patterns[1]=substr($patterns[1],0,(strlen($patterns[1])-1));
}
$module_exists = stripos($key,$patterns[1]); //primary module name.
$pattern_exists = stripos($key,$patterns[0]); //pattern provided by the user.
if ($module_exists !== false and $pattern_exists !== false)
{
$GLOBALS['matching_keys']= array_merge(array(array('NAME'=>$key, 'ID'=>$key, 'VALUE'=>$item1)),$GLOBALS['matching_keys']);
}
else
{
if ($pattern_exists !== false)
{
$GLOBALS['matching_keys'][]=array('NAME'=>$key, 'ID'=>$key, 'VALUE'=>$item1);
}
}
}
/**
* filterSearchType
*
* This is a private function to determine if the search type field should be filtered out based on the query string value
*
* @param String $type The string value of the field type (e.g. phone, date, datetime, int, etc.)
* @param String $query The search string value sent from the global search
* @return boolean True if the search type fits the query string value; false otherwise
*/
protected function filterSearchType($type, $query)
{
switch($type)
{
case 'id':
case 'date':
case 'datetime':
case 'bool':
return false;
break;
case 'int':
if(!is_numeric($query)) {
return false;
}
break;
case 'phone':
//For a phone search we require at least three digits
if(!preg_match('/[0-9]{3,}/', $query))
{
return false;
}
case 'decimal':
case 'float':
if(!preg_match('/[0-9]/', $query))
{
return false;
}
break;
}
return true;
}
}