/
var
/
www
/
html
/
sugar9
/
include
/
SearchForm
/
Upload File
HOME
<?php /* * Your installation or use of this SugarCRM file is subject to the applicable * terms available at * http://support.sugarcrm.com/Resources/Master_Subscription_Agreements/. * If you do not agree to all of the applicable terms or do not have the * authority to bind the entity as an authorized representative, then do not * install or use this SugarCRM file. * * Copyright (C) SugarCRM Inc. All rights reserved. */ use Sugarcrm\Sugarcrm\Security\InputValidation\InputValidation; use Sugarcrm\Sugarcrm\Security\InputValidation\Request; /** * Old search form * @api */ class SearchForm { /** * SearchForm Template to use (xtpl) * @var string */ var $tpl; /** * SearchField meta data array to use. Populated from moduleDir/metadata/SearchFields * @var array */ var $searchFields; /** * Seed bean to use * @var bean */ var $bean; /** * Module the search from is for * @var string */ var $module; /** * meta data for the tabs to display * @var array */ var $tabs; /** * XTPL object * @var object */ var $xtpl; /** * Use to determine whether or not to show the saved search options * @var boolean */ var $showSavedSearchOptions = true; /** * @var Request */ protected $request; /** * loads SearchFields MetaData, sets member variables * * @param string $module moduleDir * @param bean $seedBean seed bean to use * @param string $tpl template to use, defaults to moduleDir/SearchForm.html * */ public function __construct($module, $seedBean, $tpl = null) { global $app_strings; $this->module = $module; $this->request = InputValidation::getService(); $searchFields = SugarAutoLoader::loadSearchFields($module); $this->searchFields = $searchFields[$module]; if(empty($tpl)) { if(!empty($GLOBALS['layout_edit_mode'])){ $this->tpl = sugar_cached('studio/custom/working/modules/' . $module . '/SearchForm.html'); } else { $this->tpl = get_custom_file_if_exists('modules/' . $module . '/SearchForm.html'); } } else { $this->tpl = $tpl; } $this->bean = $seedBean; $this->tabs = array(array('title' => $app_strings['LNK_BASIC_SEARCH'], 'link' => $module . '|basic_search', 'key' => $module . '|basic_search'), array('title' => $app_strings['LNK_ADVANCED_SEARCH'], 'link' => $module . '|advanced_search', 'key' => $module . '|advanced_search')); if (file_exists('modules/'.$this->module.'/index.php')) { $this->tabs[] = array('title' => $app_strings['LNK_SAVED_VIEWS'], 'link' => $module . '|saved_views', 'key' => $module . '|saved_views'); } } /** * Populate the searchFields from an array * * @param array $array array to search through * @param string $switchVar variable to use in switch statement * @param bool $addAllBeanFields true to process at all bean fields */ function populateFromArray(&$array, $switchVar = null, $addAllBeanFields = true) { //CL Bug:33176 if(empty($array['searchFormTab']) && empty($switchVar)) { $array['searchFormTab'] = 'advanced_search'; } if(!empty($array['searchFormTab']) || !empty($switchVar)) { $arrayKeys = array_keys($array); $searchFieldsKeys = array_keys($this->searchFields); if(empty($switchVar)) $switchVar = $array['searchFormTab']; switch($switchVar) { case 'basic_search': foreach($this->searchFields as $name => $params) { if(isset($array[$name . '_basic'])) { $this->searchFields[$name]['value'] = is_string($array[$name . '_basic'])?trim($array[$name . '_basic']):$array[$name . '_basic']; } } if($addAllBeanFields) { foreach ($this->bean->field_defs as $key => $params) { if(in_array($key . '_basic' , $arrayKeys) && !in_array($key, $searchFieldsKeys)) { $this->searchFields[$key] = array('query_type' => 'default', 'value' => $array[$key . '_basic']); } } } break; case 'advanced_search': foreach($this->searchFields as $name => $params) { if(isset($array[$name])) { $this->searchFields[$name]['value'] = is_string($array[$name])?trim($array[$name]):$array[$name]; } } if((empty($array['massupdate']) || $array['massupdate'] == 'false') && $addAllBeanFields) { foreach ($this->bean->field_defs as $key => $params) { if(in_array($key, $arrayKeys) && !in_array($key, $searchFieldsKeys)) { $this->searchFields[$key] = array('query_type' => 'default', 'value' => $array[$key]); } } } break; case 'saved_views': foreach($this->searchFields as $name => $params) { if(isset($array[$name . '_basic'])) { // save basic first $this->searchFields[$name]['value'] = $array[$name . '_basic']; } if(isset($array[$name])) { // overwrite by advanced if available $this->searchFields[$name]['value'] = $array[$name]; } } if($addAllBeanFields) { foreach ($this->bean->field_defs as $key => $params) { if(!in_array($key, $searchFieldsKeys)) { if(in_array($key . '_basic', $arrayKeys) ) { $this->searchFields[$key] = array('query_type' => 'default', 'value' => $array[$key . '_basic']); } if(in_array($key, $arrayKeys)) { $this->searchFields[$key] = array('query_type' => 'default', 'value' => $array[$key]); } } } } } } } /** * Populate the searchFields from $_REQUEST * * @param string $switchVar variable to use in switch statement * @param bool $addAllBeanFields true to process at all bean fields */ function populateFromRequest($switchVar = null, $addAllBeanFields = true) { $this->populateFromArray($_REQUEST, $switchVar, $addAllBeanFields); } /** * Converts column name and value to upper case for case insensitive search if needed. * @param string $subquery eg, 'select * from t where c like' * @param string $value * @return string */ protected function getLikeSubquery($subquery, $value, $likechar = '%') { if ($this->bean->db->supports('case_insensitive') && preg_match('/(.*\S)\s+(\S+)\s+like$/i', trim($subquery), $matches)) { return $matches[1]. ' ' . $this->seed->db->getLikeSQL($matches[2], "$value$likechar"); } else { return "$subquery ".$this->bean->db->quoted("$value$likechar"); } } /** * The fuction will returns an array of filter conditions. * */ function generateSearchWhere($add_custom_fields = false, $module='') { global $timedate; $where_clauses = array(); foreach($this->searchFields as $field=>$parms) { $customField = false; // Jenny - Bug 7462: We need a type check here to avoid database errors // when searching for numeric fields. This is a temporary fix until we have // a generic search form validation mechanism. $type = !empty($this->bean->field_defs[$field]['type']) ? $this->bean->field_defs[$field]['type'] : ''; if (!empty($this->bean->field_defs[$field]['source']) && $this->bean->field_defs[$field]['source'] == 'custom_fields') { $customField = true; } if ($type == 'int') { if (!empty($parms['value'])) { $tempVal = explode(',', $parms['value']); $newVal = ''; foreach($tempVal as $key => $val) { if (!empty($newVal)) $newVal .= ','; if(!empty($val) && !(is_numeric($val))) $newVal .= -1; else $newVal .= $val; } $parms['value'] = $newVal; } } // do not include where clause for custom fields with checkboxes that are unchecked elseif($type == 'bool' && empty($parms['value']) && $customField) { continue; } elseif($type == 'bool' && !empty($parms['value'])){ if ($parms['value'] == 'on'){ $parms['value'] = 1; } } if(isset($parms['value']) && $parms['value'] != "") { $operator = 'like'; if(!empty($parms['operator'])) { $operator = strtolower($parms['operator']); } if(is_array($parms['value'])) { $field_value = ''; // If it is a custom field of multiselect we have to do some special processing if ($customField && !empty($this->bean->field_defs[$field]['isMultiSelect'])) { $operator = 'custom_enum'; $db_field = $this->bean->table_name . "_cstm." . $field; foreach($parms['value'] as $key => $val) { if($val != ' ' and $val != '') { $qVal = $GLOBALS['db']->quote($val); if (!empty($field_value)) { $field_value .= ' or '; } $field_value .= "$db_field like '$qVal' or $db_field like '%$qVal^%' or $db_field like '%^$qVal%' or $db_field like '%^$qVal^%'"; } } } else { $operator = $operator != 'subquery' ? 'in' : $operator; foreach($parms['value'] as $key => $val) { if($val != ' ' and $val != '') { if (!empty($field_value)) { $field_value .= ','; } $field_value .= "'" . $GLOBALS['db']->quote($val) . "'"; } } } } else { $field_value = $parms['value']; } //set db_fields array. if(!isset($parms['db_field'])) { $parms['db_field'] = array($field); } if(isset($parms['my_items']) and $parms['my_items'] == true) { global $current_user; $field_value = $current_user->id; $operator = '='; } $where = ''; $itr = 0; if($field_value != '') { foreach ($parms['db_field'] as $db_field) { if (strstr($db_field, '.') === false) { if(!$customField){ $db_field = $this->bean->table_name . "." . $db_field; }else{ $db_field = $this->bean->table_name . "_cstm." . $db_field; } } if($type == 'date') { // The regular expression check is to circumvent special case YYYY-MM $operator = '='; if(preg_match('/^\d{4}.\d{1,2}$/', $field_value) == 0) { $db_field = $this->bean->db->convert($db_field, "date_format", "%Y-%m"); } else { $field_value = $timedate->to_db_date($field_value, false); $db_field = $this->bean->db->convert($db_field, "date_format", "%Y-%m-%d"); } } if($type == 'datetime'|| $type == 'datetimecombo') { $dates = $timedate->getDayStartEndGMT($field_value); $field_value = array($this->bean->db->convert($dates["start"], "datetime"), $this->bean->db->convert($dates["end"], "datetime")); $operator = 'between'; } if($this->bean->db->supports('case_sensitive') && isset($parms['query_type']) && $parms['query_type'] == 'case_insensitive') { $db_field = 'upper(' . $db_field . ")"; $field_value = strtoupper($field_value); } $itr++; if(!empty($where)) { $where .= " OR "; } switch($operator) { case 'subquery': $in = 'IN'; if ( isset($parms['subquery_in_clause']) ) { if ( !is_array($parms['subquery_in_clause']) ) { $in = $parms['subquery_in_clause']; } elseif ( isset($parms['subquery_in_clause'][$field_value]) ) { $in = $parms['subquery_in_clause'][$field_value]; } } $sq = $parms['subquery']; if(is_array($sq)){ $and_or = ' AND '; if (isset($sq['OR'])){ $and_or = ' OR '; } $first = true; foreach($sq as $q){ if(empty($q) || strlen($q)<2) continue; if(!$first){ $where .= $and_or; } $where .= " {$db_field} $in (".$this->getLikeSubquery($q, $field_value).") "; $first = false; } }elseif(!empty($parms['query_type']) && $parms['query_type'] == 'format'){ $stringFormatParams = array(0 => $field_value, 1 => $GLOBALS['current_user']->id); $where .= "{$db_field} $in (".string_format($parms['subquery'], $stringFormatParams).")"; }else{ $where .= "{$db_field} $in (".$this->getLikeSubquery($parms['subquery'] , $field_value).")"; } break; case 'like': $where .= $this->bean->db->getLikeSQL($db_field, "$field_value%"); break; case 'in': $where .= $db_field . " in (".$field_value.')'; break; case '=': $where .= $db_field . " = ".$this->bean->db->quoted($field_value); break; case 'between': if(!is_array($field_value)) { $field_value = explode('<>', $field_value); } $where .= "(". $db_field . " >= ".$this->bean->db->quoted($field_value[0]) . " AND " .$db_field . " <= ".$this->bean->db->quoted($field_value[1]).")"; break; } } } if(!empty($where)) { if($itr > 1) { array_push($where_clauses, '( '.$where.' )'); } else { array_push($where_clauses, $where); } } } } return $where_clauses; } /** * displays the tabs (top of the search form) * * @param string $currentKey key in $this->tabs to show as the current tab * * @return string html */ function displayTabs($currentKey) { $GLOBALS['log']->debug('SearchForm.php->displayTabs(): tabs='.print_r($this->tabs,true)); $tabPanel = new SugarWidgetTabs($this->tabs, $currentKey, 'SUGAR.searchForm.searchFormSelect'); if(isset($_REQUEST['saved_search_select']) && $_REQUEST['saved_search_select']!='_none') { $saved_search = BeanFactory::newBean('SavedSearch'); $saved_search->retrieveSavedSearch($_REQUEST['saved_search_select']); } $str = $tabPanel->display(); $params = array(); foreach(array('displayColumns', 'hideTabs', 'orderBy', 'sortOrder') as $param) { $value = $this->request->getValidInputRequest($param); if (!empty($value)) { $params[$param] = $value; } elseif (!empty($saved_search->contents[$param])) { $params[$param] = $saved_search->contents[$param]; } } $str .= '<script>$.extend(SUGAR.savedViews, '.json_encode($params).');</script>'; return $str; } /** * sets up the search forms, populates the preset values * */ function setup() { global $mod_strings, $app_strings, $app_list_strings, $theme, $timedate; $GLOBALS['log']->debug('SearchForm.php->setup()'); $this->xtpl = new XTemplate($this->tpl); $this->xtpl->assign("MOD", $mod_strings); $this->xtpl->assign("APP", $app_strings); $this->xtpl->assign("THEME", $theme); $this->xtpl->assign("CALENDAR_DATEFORMAT", $timedate->get_cal_date_format()); $this->xtpl->assign("USER_DATEFORMAT", '('. $timedate->get_user_date_format().')'); foreach($this->searchFields as $name => $params) { if(isset($params['template_var'])) $templateVar = $params['template_var']; else $templateVar = strtoupper($name); if(isset($params['value'])) { // populate w/ preselected values if(isset($params['options'])) { $options = $app_list_strings[$params['options']]; if(isset($params['options_add_blank']) && $params['options_add_blank']) array_unshift($options, ''); $this->xtpl->assign($templateVar, get_select_options_with_id($options, $params['value'])); } else { if(isset($params['input_type'])) { switch($params['input_type']) { case 'checkbox': // checkbox input if($params['value'] == 'on' || $params['value']) $this->xtpl->assign($templateVar, 'checked'); break; } } else {// regular text input if(is_array($params['value'])) { $value = array_map('to_html', $params['value']); } else if(is_string($params['value'])) { $value = to_html($params['value']); } $this->xtpl->assign($templateVar, $value); } } } else { // populate w/o preselected values if(isset($params['options'])) { $options = $app_list_strings[$params['options']]; if(isset($params['options_add_blank']) && $params['options_add_blank']) array_unshift($options, ''); $this->xtpl->assign($templateVar, get_select_options_with_id($options, '')); } } } if (!empty($_REQUEST['assigned_user_id'])) $this->xtpl->assign("USER_FILTER", get_select_options_with_id(get_user_array(FALSE), $_REQUEST['assigned_user_id'])); else $this->xtpl->assign("USER_FILTER", get_select_options_with_id(get_user_array(FALSE), '')); // handle my items only if(isset($this->searchFields['current_user_only']) && isset($this->searchFields['current_user_only']['value'])) $this->xtpl->assign("CURRENT_USER_ONLY", "checked"); } /** * displays the search form header * * @param string $view which view is currently being displayed * */ function displayHeader($view) { global $current_user; $GLOBALS['log']->debug('SearchForm.php->displayHeader()'); $header_text = ''; $module = $this->request->getValidInputRequest('module', 'Assert\Mvc\ModuleName'); $action = $this->request->getValidInputRequest('action'); if(is_admin($current_user) && $module != 'DynamicLayout' && !empty($_SESSION['editinplace'])){ $header_text = "<a href='index.php?action=index&module=DynamicLayout&from_action=SearchForm&from_module=".htmlspecialchars($module, ENT_QUOTES, 'UTF-8')."'>".SugarThemeRegistry::current()->getImage("EditLayout","border='0' align='bottom'",null,null,'.gif','Edit Layout')."</a>"; } echo $header_text . $this->displayTabs($this->module . '|' . $view); echo "<form name='search_form' class='search_form'>" . "<input type='hidden' name='searchFormTab' value='{$view}'/>" . "<input type='hidden' name='module' value='".htmlspecialchars($module, ENT_QUOTES, 'UTF-8')."'/>" . "<input type='hidden' name='action' value='".htmlspecialchars($action, ENT_QUOTES, 'UTF-8')."'/>" . "<input type='hidden' name='query' value='true'/>"; } /** * displays the search form body, for example if basic_search is being displayed, then the function call would be * displayWithHeaders('basic_search', $htmlForBasicSearchBody) { * * @param string $view which view is currently being displayed * @param string $basic_search_text body of the basic search tab * @param string $advanced_search_text body of the advanced search tab * @param string $saved_views_text body of the saved views tab * */ function displayWithHeaders($view, $basic_search_text = '', $advanced_search_text = '', $saved_views_text = '') { $GLOBALS['log']->debug('SearchForm.php->displayWithHeaders()'); $this->displayHeader($view); echo "<div id='{$this->module}basic_searchSearchForm' " . (($view == 'basic_search') ? '' : "style='display: none'") . ">" . $basic_search_text . "</div>"; echo "<div id='{$this->module}advanced_searchSearchForm' " . (($view == 'advanced_search') ? '' : "style='display: none'") . ">" . $advanced_search_text . "</div>"; echo "<div id='{$this->module}saved_viewsSearchForm' " . (($view == 'saved_views') ? '' : "style='display: none'") . ">" . $saved_views_text . "</div>"; echo $this->getButtons(); echo '</form>'; } /** * displays the basic search form body * * @param bool $header display this with headers * @param bool $return echo or return the html * * @return string html of contents */ function displayBasic($header = true, $return = false) { global $current_user; $this->bean->custom_fields->populateAllXTPL($this->xtpl, 'search' ); $this->xtpl->parse("main"); if(!empty($GLOBALS['layout_edit_mode'])){ $this->xtpl->parse("advanced"); } $text = $this->xtpl->text("main"); if(!empty($GLOBALS['layout_edit_mode'])){ $text .= $this->xtpl->text("advanced"); } if($header && empty($GLOBALS['layout_edit_mode'])) { $this->displayWithHeaders('basic_search', $text); } else { if($return) return $text; else echo $text; } } /** * displays the advanced search form body * * @param bool $header display this with headers * @param bool $return echo or return the html * * @return string html of contents */ function displayAdvanced($header = true, $return = false, $listViewDefs='', $lv='') { global $current_user, $current_language; $GLOBALS['log']->debug('SearchForm.php->displayAdvanced()'); $this->bean->custom_fields->populateAllXTPL($this->xtpl, 'search' ); if(!empty($listViewDefs) && !empty($lv)){ $GLOBALS['log']->debug('SearchForm.php->displayAdvanced(): showing saved search'); $savedSearch = BeanFactory::newBean('SavedSearch'); $savedSearch->init($listViewDefs[$this->module], $lv->data['pageData']['ordering']['orderBy'], $lv->data['pageData']['ordering']['sortOrder']); $this->xtpl->assign('SAVED_SEARCH', $savedSearch->getForm($this->module, false)); $this->xtpl->assign('MOD_SAVEDSEARCH', return_module_language($current_language, 'SavedSearch')); $this->xtpl->assign('ADVANCED_SEARCH_IMG', SugarThemeRegistry::current()->getImageURL('advanced_search.gif')); //this determines whether the saved search subform should be rendered open or not if(isset($_REQUEST['showSSDIV']) && $_REQUEST['showSSDIV']=='yes'){ $this->xtpl->assign('SHOWSSDIV', 'yes'); $this->xtpl->assign('DISPLAYSS', ''); }else{ $this->xtpl->assign('SHOWSSDIV', 'no'); $this->xtpl->assign('DISPLAYSS', 'display:none'); } } $this->xtpl->parse("advanced"); $text = $this->xtpl->text("advanced"); if($header) { $this->displayWithHeaders('advanced_search', '', $text); } else { if($return) return $text; else echo $text; } } /** * displays the saved views form body * * @param bool $header display this with headers * @param bool $return echo or return the html * * @return string html of contents */ function displaySavedViews($listViewDefs, $lv, $header = true, $return = false) { global $current_user; $savedSearch = BeanFactory::newBean('SavedSearch'); $savedSearch->init($listViewDefs[$this->module], $lv->data['pageData']['ordering']['orderBy'], $lv->data['pageData']['ordering']['sortOrder']); if($header) { $this->displayWithHeaders('saved_views', $this->displayBasic(false, true), $this->displayAdvanced(false, true), $savedSearch->getForm($this->module)); echo '<script>SUGAR.savedViews.handleForm();</script>'; } else { echo $savedSearch->getForm($this->module, false); } } /** * get the search buttons * * @return string html of contents */ function getButtons() { global $app_strings; $SAVED_SEARCHES_OPTIONS = ''; $savedSearch = BeanFactory::newBean('SavedSearch'); $SAVED_SEARCHES_OPTIONS = $savedSearch->getSelect($this->module); $str = "<input tabindex='2' title='{$app_strings['LBL_SEARCH_BUTTON_TITLE']}' onclick='SUGAR.savedViews.setChooser()' class='button' type='submit' name='button' value='{$app_strings['LBL_SEARCH_BUTTON_LABEL']}' id='search_form_submit'/> "; $str .= "<input tabindex='2' title='{$app_strings['LBL_CLEAR_BUTTON_TITLE']}' onclick='SUGAR.searchForm.clear_form(this.form); return false;' class='button' type='button' name='clear' value=' {$app_strings['LBL_CLEAR_BUTTON_LABEL']} ' id='search_form_clear'/>"; if(!empty($SAVED_SEARCHES_OPTIONS) && $this->showSavedSearchOptions){ $str .= " <span class='white-space'> | <b>{$app_strings['LBL_SAVED_SEARCH_SHORTCUT']}</b> {$SAVED_SEARCHES_OPTIONS} <span id='go_btn_span' style='display:none'><input tabindex='2' title='go_select' id='go_select' onclick='SUGAR.searchForm.clear_form(this.form);' class='button' type='button' name='go_select' value=' {$app_strings['LBL_GO_BUTTON_LABEL']} '/></span> </span> </form>"; } $str .= " <script> function toggleInlineSearch(){ if (document.getElementById('inlineSavedSearch').style.display == 'none'){ document.getElementById('showSSDIV').value = 'yes' document.getElementById('inlineSavedSearch').style.display = ''; document.getElementById('up_down_img').src='".SugarThemeRegistry::current()->getImageURL('basic_search.gif')."'; document.getElementById('up_down_img').setAttribute('alt','".$GLOBALS['app_strings']['LBL_ALT_HIDE_OPTIONS']."'); }else{ document.getElementById('up_down_img').src='".SugarThemeRegistry::current()->getImageURL('advanced_search.gif')."'; document.getElementById('up_down_img').setAttribute('alt','".$GLOBALS['app_strings']['LBL_ALT_SHOW_OPTIONS']."'); document.getElementById('showSSDIV').value = 'no'; document.getElementById('inlineSavedSearch').style.display = 'none'; } } </script> "; return $str; } }