Issues (4069)

Security Analysis    not enabled

This project does not seem to handle request data directly as such no vulnerable execution paths were found.

  Cross-Site Scripting
Cross-Site Scripting enables an attacker to inject code into the response of a web-request that is viewed by other users. It can for example be used to bypass access controls, or even to take over other users' accounts.
  File Exposure
File Exposure allows an attacker to gain access to local files that he should not be able to access. These files can for example include database credentials, or other configuration files.
  File Manipulation
File Manipulation enables an attacker to write custom data to files. This potentially leads to injection of arbitrary code on the server.
  Object Injection
Object Injection enables an attacker to inject an object into PHP code, and can lead to arbitrary code execution, file exposure, or file manipulation attacks.
  Code Injection
Code Injection enables an attacker to execute arbitrary code on the server.
  Response Splitting
Response Splitting can be used to send arbitrary responses.
  File Inclusion
File Inclusion enables an attacker to inject custom files into PHP's file loading mechanism, either explicitly passed to include, or for example via PHP's auto-loading mechanism.
  Command Injection
Command Injection enables an attacker to inject a shell command that is execute with the privileges of the web-server. This can be used to expose sensitive data, or gain access of your server.
  SQL Injection
SQL Injection enables an attacker to execute arbitrary SQL code on your database server gaining access to user data, or manipulating user data.
  XPath Injection
XPath Injection enables an attacker to modify the parts of XML document that are read. If that XML document is for example used for authentication, this can lead to further vulnerabilities similar to SQL Injection.
  LDAP Injection
LDAP Injection enables an attacker to inject LDAP statements potentially granting permission to run unauthorized queries, or modify content inside the LDAP tree.
  Header Injection
  Other Vulnerability
This category comprises other attack vectors such as manipulating the PHP runtime, loading custom extensions, freezing the runtime, or similar.
  Regex Injection
Regex Injection enables an attacker to execute arbitrary code in your PHP process.
  XML Injection
XML Injection enables an attacker to read files on your local filesystem including configuration files, or can be abused to freeze your web-server process.
  Variable Injection
Variable Injection enables an attacker to overwrite program variables with custom data, and can lead to further vulnerabilities.
Unfortunately, the security analysis is currently not available for your project. If you are a non-commercial open-source project, please contact support to gain access.

include/SearchForm/SearchForm2.php (21 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
/*********************************************************************************
3
 * SugarCRM Community Edition is a customer relationship management program developed by
4
 * SugarCRM, Inc. Copyright (C) 2004-2013 SugarCRM Inc.
5
6
 * SuiteCRM is an extension to SugarCRM Community Edition developed by Salesagility Ltd.
7
 * Copyright (C) 2011 - 2014 Salesagility Ltd.
8
 *
9
 * This program is free software; you can redistribute it and/or modify it under
10
 * the terms of the GNU Affero General Public License version 3 as published by the
11
 * Free Software Foundation with the addition of the following permission added
12
 * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK
13
 * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY
14
 * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
15
 *
16
 * This program is distributed in the hope that it will be useful, but WITHOUT
17
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
18
 * FOR A PARTICULAR PURPOSE.  See the GNU Affero General Public License for more
19
 * details.
20
 *
21
 * You should have received a copy of the GNU Affero General Public License along with
22
 * this program; if not, see http://www.gnu.org/licenses or write to the Free
23
 * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
24
 * 02110-1301 USA.
25
 *
26
 * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road,
27
 * SW2-130, Cupertino, CA 95014, USA. or at email address [email protected].
28
 *
29
 * The interactive user interfaces in modified source and object code versions
30
 * of this program must display Appropriate Legal Notices, as required under
31
 * Section 5 of the GNU Affero General Public License version 3.
32
 *
33
 * In accordance with Section 7(b) of the GNU Affero General Public License version 3,
34
 * these Appropriate Legal Notices must retain the display of the "Powered by
35
 * SugarCRM" logo and "Supercharged by SuiteCRM" logo. If the display of the logos is not
36
 * reasonably feasible for  technical reasons, the Appropriate Legal Notices must
37
 * display the words  "Powered by SugarCRM" and "Supercharged by SuiteCRM".
38
 ********************************************************************************/
39
40
41 1
require_once('include/tabs.php');
42 1
require_once('include/ListView/ListViewSmarty.php');
43 1
require_once('include/TemplateHandler/TemplateHandler.php');
44 1
require_once('include/EditView/EditView2.php');
45
46
47
 class SearchForm{
0 ignored issues
show
Comprehensibility Best Practice introduced by
The type SearchForm has been defined more than once; this definition is ignored, only the first definition in include/SearchForm/SearchForm.php (L46-711) is considered.

This check looks for classes that have been defined more than once.

If you can, we would recommend to use standard object-oriented programming techniques. For example, to avoid multiple types, it might make sense to create a common interface, and then multiple, different implementations for that interface.

This also has the side-effect of providing you with better IDE auto-completion, static analysis and also better OPCode caching from PHP.

Loading history...
48
 	var $seed = null;
49
 	var $module = '';
50
 	var $action = 'index';
51
 	var $searchdefs = array();
52
 	var $listViewDefs = array();
53
 	var $lv;
54
 	var $th;
55
    var $tpl;
56
    var $view = 'SearchForm';
57
    var $displayView = 'basic_search';
58
    var $formData;
59
    var $fieldDefs;
60
    var $customFieldDefs;
61
    var $tabs;
62
    var $parsedView = 'basic';
63
    //may remove
64
    var $searchFields;
65
    var $displaySavedSearch = true;
66
    //show the advanced tab
67
    var $showAdvanced = true;
68
    //show the basic tab
69
    var $showBasic = true;
70
    //array of custom tab to show declare in searchdefs (no custom tab if false)
71
    var $showCustom = false;
72
    // nb of tab to show
73
    var $nbTabs = 0;
74
    // hide saved searches drop and down near the search button
75
    var $showSavedSearchesOptions = true;
76
77
    var $displayType = 'searchView';
78
79
	/**
80
     * @var array
81
     */
82
    protected $options;
83
84 6
    public function __construct($seed, $module, $action = 'index', $options = array())
85
    {
86 6
 		$this->th = new TemplateHandler();
87 6
 		$this->th->loadSmarty();
88 6
		$this->seed = $seed;
89 6
		$this->module = $module;
90 6
		$this->action = $action;
91 6
        $this->tabs = array(array('title'  => $GLOBALS['app_strings']['LNK_BASIC_SEARCH'],
92 6
                            'link'   => $module . '|basic_search',
93 6
                            'key'    => $module . '|basic_search',
94 6
                            'name'   => 'basic',
95 6
                            'displayDiv'   => ''),
96 6
                      array('title'  => $GLOBALS['app_strings']['LNK_ADVANCED_SEARCH'],
97 6
                            'link'   => $module . '|advanced_search',
98 6
                            'key'    => $module . '|advanced_search',
99 6
                            'name'   => 'advanced',
100 6
                            'displayDiv'   => 'display:none'),
101
                       );
102 6
        $this->searchColumns = array () ;
103 6
        $this->setOptions($options);
0 ignored issues
show
The method setOptions() does not seem to exist on object<SearchForm>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
104 6
    }
105
106
    /**
107
     * @deprecated deprecated since version 7.6, PHP4 Style Constructors are deprecated and will be remove in 7.8, please update your code, use __construct instead
108
     */
109
    public function SearchForm($seed, $module, $action = 'index', $options = array()){
110
        $deprecatedMessage = 'PHP4 Style Constructors are deprecated and will be remove in 7.8, please update your code';
111
        if(isset($GLOBALS['log'])) {
112
            $GLOBALS['log']->deprecated($deprecatedMessage);
113
        }
114
        else {
115
            trigger_error($deprecatedMessage, E_USER_DEPRECATED);
116
        }
117
        self::__construct($seed, $module, $action, $options);
0 ignored issues
show
The call to SearchForm::__construct() has too many arguments starting with $options.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
118
    }
119
120
121 6
 	function setup($searchdefs, $searchFields = array(), $tpl, $displayView = 'basic_search', $listViewDefs = array()){
122 6
		$this->searchdefs =  $searchdefs[$this->module];
123 6
 		$this->tpl = $tpl;
124
 		//used by advanced search
125 6
 		$this->listViewDefs = $listViewDefs;
126 6
 		$this->displayView = $displayView;
127 6
 		$this->view = $this->view.'_'.$displayView;
128 6
 		$tokens = explode('_', $this->displayView);
129 6
 		$this->parsedView = $tokens[0];
130 6
                $this->searchFields = $searchFields[$this->module];
131 6
 		if($this->displayView != 'saved_views'){
132 6
 			$this->_build_field_defs();
0 ignored issues
show
The method _build_field_defs() does not seem to exist on object<SearchForm>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
133
 		}
134
135
136
        // Setup the tab array.
137 6
        $this->tabs = array();
138 6
        if($this->showBasic){
139 6
            $this->nbTabs++;
140 6
            $this->tabs[]=array('title'  => $GLOBALS['app_strings']['LNK_BASIC_SEARCH'],
141 6
                                'link'   => $this->module . '|basic_search',
142 6
                                'key'    => $this->module . '|basic_search',
143 6
                                'name'   => 'basic',
144 6
                                'displayDiv' => '');
145
        }
146 6
        if($this->showAdvanced){
147 6
            $this->nbTabs++;
148 6
            $this->tabs[]=array('title'  => $GLOBALS['app_strings']['LNK_ADVANCED_SEARCH'],
149 6
                                'link'   => $this->module . '|advanced_search',
150 6
                                'key'    => $this->module . '|advanced_search',
151 6
                                'name'   => 'advanced',
152 6
                                'displayDiv' => 'display:none');
153
        }
154 6
        if(isset($this->showCustom) && is_array($this->showCustom)){
155
            foreach($this->showCustom as $v){
156
                $this->nbTabs++;
157
                $this->tabs[]=array('title'  => $GLOBALS['app_strings']["LNK_" . strtoupper($v)],
158
                    'link'   => $this->module . '|' . $v,
159
                    'key'    => $this->module . '|' . $v,
160
                    'name'   => str_replace('_search','',$v),
161
                    'displayDiv' => 'display:none',);
162
            }
163
        }
164 6
 	}
165
166 4
 	function display($header = true){
167 4
    	global $theme, $timedate, $current_user;
168 4
 		$header_txt = '';
169 4
 		$footer_txt = '';
170 4
 		$return_txt = '';
171 4
		$this->th->ss->assign('module', $this->module);
172 4
		$this->th->ss->assign('action', $this->action);
173 4
		$this->th->ss->assign('displayView', $this->displayView);
174 4
		$this->th->ss->assign('APP', $GLOBALS['app_strings']);
175
		//Show the tabs only if there is more than one
176 4
		if($this->nbTabs>1){
177 4
		    $this->th->ss->assign('TABS', $this->_displayTabs($this->module . '|' . $this->displayView));
0 ignored issues
show
The method _displayTabs() does not exist on SearchForm. Did you maybe mean displayTabs()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
178
		}
179 4
		$this->th->ss->assign('searchTableColumnCount',
180 4
		    ((isset($this->searchdefs['templateMeta']['maxColumns']) ? $this->searchdefs['templateMeta']['maxColumns'] : 2) * 2 ) - 1);
181 4
		$this->th->ss->assign('fields', $this->fieldDefs);
182 4
		$this->th->ss->assign('customFields', $this->customFieldDefs);
183 4
		$this->th->ss->assign('formData', $this->formData);
184 4
        $time_format = $timedate->get_user_time_format();
185 4
        $this->th->ss->assign('TIME_FORMAT', $time_format);
186 4
        $this->th->ss->assign('USER_DATEFORMAT', $timedate->get_user_date_format());
187 4
        $this->th->ss->assign('CALENDAR_FDOW', $current_user->get_first_day_of_week());
188
189 4
        $date_format = $timedate->get_cal_date_format();
190 4
        $time_separator = ":";
191 4
        if(preg_match('/\d+([^\d])\d+([^\d]*)/s', $time_format, $match)) {
192 4
           $time_separator = $match[1];
193
        }
194
        // Create Smarty variables for the Calendar picker widget
195 4
        $t23 = strpos($time_format, '23') !== false ? '%H' : '%I';
196 4
        if(!isset($match[2]) || $match[2] == '') {
197 4
          $this->th->ss->assign('CALENDAR_FORMAT', $date_format . ' ' . $t23 . $time_separator . "%M");
198
        } else {
199
          $pm = $match[2] == "pm" ? "%P" : "%p";
200
          $this->th->ss->assign('CALENDAR_FORMAT', $date_format . ' ' . $t23 . $time_separator . "%M" . $pm);
201
        }
202 4
        $this->th->ss->assign('TIME_SEPARATOR', $time_separator);
203
204
        //Show and hide the good tab form
205 4
        foreach($this->tabs as $tabkey=>$viewtab){
206 4
            $viewName=str_replace(array($this->module . '|','_search'),'',$viewtab['key']);
207 4
            if(strpos($this->view,$viewName)!==false){
208 4
                $this->tabs[$tabkey]['displayDiv']='';
209
                //if this is advanced tab, use form with saved search sub form built in
210 4
                if($viewName=='advanced'){
211 1
                    $this->tpl = 'SearchFormGenericAdvanced.tpl';
212 1
                    if ($this->action =='ListView') {
213
                        $this->th->ss->assign('DISPLAY_SEARCH_HELP', true);
214
                    }
215 1
                    $this->th->ss->assign('DISPLAY_SAVED_SEARCH', $this->displaySavedSearch);
216 1
                    $this->th->ss->assign('SAVED_SEARCH', $this->displaySavedSearch());
0 ignored issues
show
The method displaySavedSearch() does not seem to exist on object<SearchForm>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
217
                    //this determines whether the saved search subform should be rendered open or not
218 1
                    if(isset($_REQUEST['showSSDIV']) && $_REQUEST['showSSDIV']=='yes'){
219
                        $this->th->ss->assign('SHOWSSDIV', 'yes');
220
                        $this->th->ss->assign('DISPLAYSS', '');
221
                    }else{
222 1
                        $this->th->ss->assign('SHOWSSDIV', 'no');
223 4
                        $this->th->ss->assign('DISPLAYSS', 'display:none');
224
                    }
225
                }
226
            }else{
227 4
                $this->tabs[$tabkey]['displayDiv']='display:none';
228
            }
229
230
        }
231
232 4
        $this->th->ss->assign('TAB_ARRAY', $this->tabs);
233
234 4
        $totalWidth = 0;
235 4
        if ( isset($this->searchdefs['templateMeta']['widths'])
236 4
                && isset($this->searchdefs['templateMeta']['maxColumns'])) {
237 1
            $totalWidth = ( $this->searchdefs['templateMeta']['widths']['label'] +
238 1
                                $this->searchdefs['templateMeta']['widths']['field'] ) *
239 1
                                $this->searchdefs['templateMeta']['maxColumns'];
240
            // redo the widths in case they are too big
241 1
            if ( $totalWidth > 100 ) {
242
                $resize = 100 / $totalWidth;
243
                $this->searchdefs['templateMeta']['widths']['label'] =
244
                    $this->searchdefs['templateMeta']['widths']['label'] * $resize;
245
                $this->searchdefs['templateMeta']['widths']['field'] =
246
                    $this->searchdefs['templateMeta']['widths']['field'] * $resize;
247
            }
248
        }
249 4
        $this->th->ss->assign('templateMeta', $this->searchdefs['templateMeta']);
250 4
        $this->th->ss->assign('HAS_ADVANCED_SEARCH', !empty($this->searchdefs['layout']['advanced_search']));
251 4
        $this->th->ss->assign('displayType', $this->displayType);
252
        // return the form of the shown tab only
253 4
        if($this->showSavedSearchesOptions){
254 4
            $this->th->ss->assign('SAVED_SEARCHES_OPTIONS', $this->displaySavedSearchSelect());
0 ignored issues
show
It seems like you code against a specific sub-type and not the parent class SearchForm as the method displaySavedSearchSelect() does only exist in the following sub-classes of SearchForm: SubPanelSearchForm. Maybe you want to instanceof check for one of these explicitly?

Let’s take a look at an example:

abstract class User
{
    /** @return string */
    abstract public function getPassword();
}

class MyUser extends User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different sub-classes of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the parent class:

    abstract class User
    {
        /** @return string */
        abstract public function getPassword();
    
        /** @return string */
        abstract public function getDisplayName();
    }
    
Loading history...
255
        }
256 4
        if ($this->module == 'Documents'){
257
            $this->th->ss->assign('DOCUMENTS_MODULE', true);
258
        }
259
260 4
        $return_txt = $this->th->displayTemplate($this->seed->module_dir, 'SearchForm_'.$this->parsedView, $this->locateFile($this->tpl));
0 ignored issues
show
The method locateFile() does not seem to exist on object<SearchForm>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
261
262 4
        if($header){
263 3
			$this->th->ss->assign('return_txt', $return_txt);
264 3
			$header_txt = $this->th->displayTemplate($this->seed->module_dir, 'SearchFormHeader', $this->locateFile('header.tpl'));
0 ignored issues
show
The method locateFile() does not seem to exist on object<SearchForm>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
265
            //pass in info to render the select dropdown below the form
266 3
            $footer_txt = $this->th->displayTemplate($this->seed->module_dir, 'SearchFormFooter', $this->locateFile('footer.tpl'));
0 ignored issues
show
The method locateFile() does not seem to exist on object<SearchForm>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
267 3
			$return_txt = $header_txt.$footer_txt;
268
		}
269 4
		return $return_txt;
270
 	}
271
272
 	/**
0 ignored issues
show
There is some trailing whitespace on this line which should be avoided as per coding-style.
Loading history...
273
 	 * Set options
274
 	 * @param array $options
275
 	 * @return SearchForm2
276
 	 */
277 6
    public function setOptions($options = null)
278
    {
279
        $defaults = array(
280 6
            'locator_class' => 'FileLocator',
281
            'locator_class_params' => array(
282
                array(
283 6
                    'custom/modules/' . $this->module . '/tpls/SearchForm',
284 6
                    'modules/' . $this->module . '/tpls/SearchForm',
285 6
                    'custom/include/SearchForm/tpls',
286 6
                    'include/SearchForm/tpls'
287
                )
288
            )
289
        );
290
291 6
        $this->options = empty($options) ? $defaults : $options;
292 6
        return $this;
293
    }
294
295
    /**
296
     * Get Options
297
     * @return array
298
     */
299
    public function getOptions()
300
    {
301
        return $this->options;
302
    }
303
304
305
 	/**
0 ignored issues
show
There is some trailing whitespace on this line which should be avoided as per coding-style.
Loading history...
306
      * Locate a file in the custom or stock folders.  Look in the custom folders first.
307
      *
308
      * @param string $file         The file we are looking for
309
      * @return bool|string         If the file is found return the path, False if not
310
      */
311 4
     protected function locateFile($file)
312
     {
313 4
        $paths = isset($this->options['locator_class_params'])?$this->options['locator_class_params'][0]:array();
314 4
        foreach ($paths as $path) {
315 4
             if (is_file($path . '/' . $file)) {
316 4
                 return $path . '/' . $file;
317
             }
318
         }
319
320
         return false;
321
     }
322
323 1
     function displaySavedSearch()
324
     {
325 1
        $savedSearch = new SavedSearch($this->listViewDefs[$this->module], $this->lv->data['pageData']['ordering']['orderBy'], $this->lv->data['pageData']['ordering']['sortOrder']);
326 1
        return $savedSearch->getForm($this->module, false);
327
     }
328
329
330 4
  function displaySavedSearchSelect(){
331 4
        $savedSearch = new SavedSearch($this->listViewDefs[$this->module], $this->lv->data['pageData']['ordering']['orderBy'], $this->lv->data['pageData']['ordering']['sortOrder']);
332 4
        return $savedSearch->getSelect($this->module);
333
    }
334
335
336
337
 	/**
0 ignored issues
show
There is some trailing whitespace on this line which should be avoided as per coding-style.
Loading history...
338
     * displays the tabs (top of the search form)
339
     *
340
     * @param string $currentKey key in $this->tabs to show as the current tab
341
     *
342
     * @return string html
343
     */
344 4
    function _displayTabs($currentKey)
345
    {
346 4
        if(isset($_REQUEST['saved_search_select']) && $_REQUEST['saved_search_select']!='_none') {
347
            $saved_search=loadBean('SavedSearch');
0 ignored issues
show
Deprecated Code introduced by
The function loadBean() has been deprecated with message: use SugarModule::loadBean() instead

This function has been deprecated. The supplier of the file has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed from the class and what other function to use instead.

Loading history...
348
            $saved_search->retrieveSavedSearch($_REQUEST['saved_search_select']);
349
        }
350
351 4
        $str = '<script>';
352 4
        if(!empty($_REQUEST['displayColumns']))
353
            $str .= 'SUGAR.savedViews.displayColumns = "' . $_REQUEST['displayColumns'] . '";';
354 4
        elseif(isset($saved_search->contents['displayColumns']) && !empty($saved_search->contents['displayColumns']))
355
            $str .= 'SUGAR.savedViews.displayColumns = "' . $saved_search->contents['displayColumns'] . '";';
356 4
        if(!empty($_REQUEST['hideTabs']))
357
            $str .= 'SUGAR.savedViews.hideTabs = "' . $_REQUEST['hideTabs'] . '";';
358 4
        elseif(isset($saved_search->contents['hideTabs']) && !empty($saved_search->contents['hideTabs']))
359
            $str .= 'SUGAR.savedViews.hideTabs = "' . $saved_search->contents['hideTabs'] . '";';
360 4
        if(!empty($_REQUEST['orderBy']))
361
            $str .= 'SUGAR.savedViews.selectedOrderBy = "' . $_REQUEST['orderBy'] . '";';
362 4
        elseif(isset($saved_search->contents['orderBy']) && !empty($saved_search->contents['orderBy']))
363
            $str .= 'SUGAR.savedViews.selectedOrderBy = "' . $saved_search->contents['orderBy'] . '";';
364 4
        if(!empty($_REQUEST['sortOrder']))
365
            $str .= 'SUGAR.savedViews.selectedSortOrder = "' . $_REQUEST['sortOrder'] . '";';
366 4
        elseif(isset($saved_search->contents['sortOrder']) && !empty($saved_search->contents['sortOrder']))
367
            $str .= 'SUGAR.savedViews.selectedSortOrder = "' . $saved_search->contents['sortOrder'] . '";';
368
369 4
        $str .= '</script>';
370
371 4
        return $str;
372
    }
373
374
 	/*
375
	 * Generate the data
376
	 */
377 6
	function _build_field_defs(){
378 6
		$this->formData = array();
379 6
		$this->fieldDefs = array();
380 6
		foreach($this->searchdefs['layout'][$this->displayView] as $data){
381 4
			if(is_array($data)){
382
				//Fields may be listed but disabled so that when they are enabled, they have the correct custom display data.
383 4
				if (isset($data['enabled']) && $data['enabled'] == false)
384
					continue;
385 4
				$data['name'] = $data['name'].'_'.$this->parsedView;
386 4
				$this->formData[] = array('field' => $data);
387 4
				$this->fieldDefs[$data['name']]= $data;
388
			} else {
389 4
				$this->formData[] = array('field' => array('name'=>$data.'_'.$this->parsedView));
390
			}
391
		}
392
393 6
		if($this->seed){
394 4
			$this->seed->fill_in_additional_detail_fields();
395
			// hack to make the employee status field for the Users/Employees module display correctly
396 4
			if($this->seed->object_name == 'Employee' || $this->seed->object_name == 'User'){
397 3
                $this->seed->field_defs['employee_status']['type'] = 'enum';
398 3
                $this->seed->field_defs['employee_status']['massupdate'] = true;
399 3
                $this->seed->field_defs['employee_status']['options'] = 'employee_status_dom';
400 3
                unset($this->seed->field_defs['employee_status']['function']);
401
            }
402
403 4
	        foreach($this->seed->toArray() as $name => $value) {
404 4
	            $fvName = $name.'_'.$this->parsedView;
405 4
                if(!empty($this->fieldDefs[$fvName]))
406 1
	            	$this->fieldDefs[$fvName] = array_merge($this->seed->field_defs[$name], $this->fieldDefs[$fvName]);
407
	            else{
408 4
	            	$this->fieldDefs[$fvName] = $this->seed->field_defs[$name];
409 4
	            	$this->fieldDefs[$fvName]['name'] = $this->fieldDefs[$fvName]['name'].'_'.$this->parsedView;
410
	            }
411
412 4
	            if(isset($this->fieldDefs[$fvName]['type']) && $this->fieldDefs[$fvName]['type'] == 'relate') {
413 4
	                if(isset($this->fieldDefs[$fvName]['id_name'])) {
414 4
	                   $this->fieldDefs[$fvName]['id_name'] .= '_'.$this->parsedView;
415
	                }
416
	            }
417
418 4
	            if(isset($this->fieldDefs[$fvName]['options']) && isset($GLOBALS['app_list_strings'][$this->fieldDefs[$fvName]['options']]))
419
                {
420
	                // fill in enums
421 4
                    $this->fieldDefs[$fvName]['options'] = $GLOBALS['app_list_strings'][$this->fieldDefs[$fvName]['options']];
422
                    //Hack to add blanks for parent types on search views
423
                    //53131 - add blank option for SearchField options with def 'options_add_blank' set to true
424 4
                    if ($this->fieldDefs[$fvName]['type'] == "parent_type" || $this->fieldDefs[$fvName]['type'] == "parent" || (isset($this->searchFields[$name]['options_add_blank']) && $this->searchFields[$name]['options_add_blank']) )
425
                    {
426 2
                        if (!array_key_exists('', $this->fieldDefs[$fvName]['options'])) {
427 2
                            $this->fieldDefs[$fvName]['options'] =
428 2
                                array('' => '') + $this->fieldDefs[$fvName]['options'];
429
                        }
430
                    }
431
	            }
432
433 4
	            if(isset($this->fieldDefs[$fvName]['function'])) {
434
435 4
	            	$this->fieldDefs[$fvName]['type']='multienum';
436
437 4
	       	 		if(is_array($this->fieldDefs[$fvName]['function'])) {
438 4
	       	 		   $this->fieldDefs[$fvName]['function']['preserveFunctionValue']=true;
439
	       	 		}
440
441 4
	       	 		$function = $this->fieldDefs[$fvName]['function'];
442
443 4
	       			if(is_array($function) && isset($function['name'])){
444 4
	       				$function_name = $this->fieldDefs[$fvName]['function']['name'];
445
	       			}else{
446
	       				$function_name = $this->fieldDefs[$fvName]['function'];
447
	       			}
448
449 4
					if(!empty($this->fieldDefs[$fvName]['function']['returns']) && $this->fieldDefs[$fvName]['function']['returns'] == 'html'){
450 4
						if(!empty($this->fieldDefs[$fvName]['function']['include'])){
451
								require_once($this->fieldDefs[$fvName]['function']['include']);
452
						}
453 4
						$value = call_user_func($function_name, $this->seed, $name, $value, $this->view);
454 4
						$this->fieldDefs[$fvName]['value'] = $value;
455
					}else{
456 1
						if(!isset($function['params']) || !is_array($function['params'])) {
457
							$this->fieldDefs[$fvName]['options'] = call_user_func($function_name, $this->seed, $name, $value, $this->view);
458
						} else {
459 1
							$this->fieldDefs[$fvName]['options'] = call_user_func_array($function_name, $function['params']);
460
						}
461
					}
462
	       	 	}
463 4
	       	 	if(isset($this->fieldDefs[$name]['type']) && $this->fieldDefs[$fvName]['type'] == 'function'
464 4
                       && isset($this->fieldDefs[$fvName]['function_name']))
465
                {
466
	       	 		$value = $this->callFunction($this->fieldDefs[$fvName]);
0 ignored issues
show
The method callFunction() does not seem to exist on object<SearchForm>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
467
	       	 		$this->fieldDefs[$fvName]['value'] = $value;
468
	       	 	}
469
470 4
	            $this->fieldDefs[$name]['value'] = $value;
471
472
473 4
	            if((!empty($_REQUEST[$fvName]) || (isset($_REQUEST[$fvName]) && $_REQUEST[$fvName] == '0'))
474 4
                && empty($this->fieldDefs[$fvName]['function']['preserveFunctionValue'])) {
475
	            	$value = $_REQUEST[$fvName];
476 4
	            	$this->fieldDefs[$fvName]['value'] = $value;
477
	            }
478
479
	        } //foreach
480
481
482
		}
483
484 6
	}
485
486
	    /**
487
     * Populate the searchFields from an array
488
     *
489
     * @param array $array array to search through
490
     * @param string $switchVar variable to use in switch statement
491
     * @param bool $addAllBeanFields true to process at all bean fields
492
     */
493 1
    function populateFromArray(&$array, $switchVar = null, $addAllBeanFields = true) {
494
495 1
       if((!empty($array['searchFormTab']) || !empty($switchVar)) && !empty($this->searchFields)) {
496 1
			$arrayKeys = array_keys($array);
497 1
            $searchFieldsKeys = array_keys($this->searchFields);
498 1
            if(empty($switchVar)) $switchVar = $array['searchFormTab'];
499
            //name of  the search tab
500 1
            $SearchName=str_replace('_search', '', $switchVar);
501 1
            if($switchVar=='saved_views'){
502
                foreach($this->searchFields as $name => $params) {
503
                    foreach($this->tabs as $tabName){
504
                        if(!empty($array[$name . '_' . $tabName['name']])) {
505
                             $this->searchFields[$name]['value'] = $array[$name . '_' . $tabName['name']];
506
                             if(empty($this->fieldDefs[$name . '_' . $tabName['name']]['value'])) $this->fieldDefs[$name . '_' . $tabName['name']]['value'] = $array[$name . '_' . $tabName['name']];
507
                        }
508
                    }
509
                }
510
                if($addAllBeanFields) {
511
                    foreach($this->seed->field_name_map as $key => $params) {
512
                        if(!in_array($key, $searchFieldsKeys)) {
513
                            foreach($this->tabs->name as $tabName){
514
                                if(in_array($key . '_' . $tabName['name'], $arrayKeys) ) {
515
									$this->searchFields[$key] = array('query_type' => 'default',
516
                                                                      'value'      => $array[$key . '_' . $tabName['name']]);
517
                                }
518
                            }
519
                        }
520
                    }
521
                }
522
            }else{
523
524 1
            	$fromMergeRecords = isset($array['merge_module']);
525
526 1
                foreach($this->searchFields as $name => $params) {
527 1
					$long_name = $name.'_'.$SearchName;
528
					/*nsingh 21648: Add additional check for bool values=0. empty() considers 0 to be empty Only repopulates if value is 0 or 1:( */
529 1
                    if (isset($array[$long_name]) && ( $array[$long_name] !== '' || (isset($this->fieldDefs[$long_name]['type']) && $this->fieldDefs[$long_name]['type'] == 'bool'&& ($array[$long_name]=='0' || $array[$long_name]=='1'))))
530
					{
531
                        $this->searchFields[$name]['value'] = $array[$long_name];
532
                        if(empty($this->fieldDefs[$long_name]['value'])) {
533
                        	$this->fieldDefs[$long_name]['value'] = $array[$long_name];
534
                        }
535
                    }
536 1
                    else if(!empty($array[$name]) && !$fromMergeRecords) // basic
537
                    {
538
                    	$this->searchFields[$name]['value'] = $array[$name];
539
                        if(empty($this->fieldDefs[$long_name]['value'])) {
540
                        	$this->fieldDefs[$long_name]['value'] = $array[$name];
541
                        }
542
                    }
543
544 1
                    if(!empty($params['enable_range_search']) && isset($this->searchFields[$name]['value']))
545
					{
546
						if(preg_match('/^range_(.*?)$/', $long_name, $match) && isset($array[$match[1].'_range_choice']))
547
						{
548
							$this->searchFields[$name]['operator'] = $array[$match[1].'_range_choice'];
549
						}
550
					}
551
552 1
					if(!empty($params['is_date_field']) && isset($this->searchFields[$name]['value']))
553
					{
554
						global $timedate;
555
                        // FG - bug 45287 - to db conversion is ok, but don't adjust timezone (not now), otherwise you'll jump to the day before (if at GMT-xx)
556
						$date_value = $timedate->to_db_date($this->searchFields[$name]['value'], false);
557 1
						$this->searchFields[$name]['value'] = $date_value == '' ? $this->searchFields[$name]['value'] : $date_value;
558
					}
559
                }
560
561 1
                if((empty($array['massupdate']) || $array['massupdate'] == 'false') && $addAllBeanFields) {
562 1
                    foreach($this->seed->field_name_map as $key => $params) {
563 1
                    	if($key != 'assigned_user_name' && $key != 'modified_by_name')
564
                    	{
565 1
                    		$long_name = $key.'_'.$SearchName;
566
567 1
	                        if(in_array($key.'_'.$SearchName, $arrayKeys) && !in_array($key, $searchFieldsKeys))
568
	                    	{
569
	                        	$this->searchFields[$key] = array('query_type' => 'default', 'value' => $array[$long_name]);
570
571
                                if (!empty($params['type']) && $params['type'] == 'parent'
572
                                    && !empty($params['type_name']) && !empty($this->searchFields[$key]['value']))
573
                                {
574
                                	    require_once('include/SugarFields/SugarFieldHandler.php');
575
										$sfh = new SugarFieldHandler();
576
                   						$sf = $sfh->getSugarField('Parent');
577
578
                                        $this->searchFields[$params['type_name']] = array('query_type' => 'default',
579
                                                                                          'value'      => $sf->getSearchInput($params['type_name'], $array));
580
                                }
581
582
                                if(empty($this->fieldDefs[$long_name]['value'])) {
583 1
                                    $this->fieldDefs[$long_name]['value'] =  $array[$long_name];
584
                                }
585
                            }
586
                        }
587
                    }
588
                }
589
            }
590
        }
591
592
593 1
       if ( is_array($this->searchFields) ) {
594 1
           foreach ( $this->searchFields as $fieldName => $field ) {
595 1
               if ( !empty($field['value']) && is_string($field['value']) ) {
596 1
                   $this->searchFields[$fieldName]['value'] = trim($field['value']);
597
               }
598
           }
599
       }
600
601 1
    }
602
603
    /**
604
     * Populate the searchFields from $_REQUEST
605
     *
606
     * @param string $switchVar variable to use in switch statement
607
     * @param bool $addAllBeanFields true to process at all bean fields
608
     */
609 1
    function populateFromRequest($switchVar = null, $addAllBeanFields = true) {
610 1
    	$this->populateFromArray($_REQUEST, $switchVar, $addAllBeanFields);
611 1
    }
612
613
614
 	/**
0 ignored issues
show
There is some trailing whitespace on this line which should be avoided as per coding-style.
Loading history...
615
     * Parse date expression and return WHERE clause
616
     * @param string $operator Date expression operator
617
     * @param string DB field name
618
      * @param string DB field type
619
     */
620
    protected function parseDateExpression($operator, $db_field, $field_type = '')
621
    {
622
        if ($field_type == "date") {
623
            $type = "date";
624
            $adjForTZ = false;
625
        } else {
626
            $type = "datetime";
627
            $adjForTZ = true;
628
        }
629
        $dates = TimeDate::getInstance()->parseDateRange($operator, null, $adjForTZ);
630
        if(empty($dates)) return '';
631
        $start = $this->seed->db->convert($this->seed->db->quoted($dates[0]->asDb()), $type);
632
        $end = $this->seed->db->convert($this->seed->db->quoted($dates[1]->asDb()), $type);
633
        return "($db_field >= $start AND $db_field <= $end)";
634
    }
635
636
     /**
637
      * generateSearchWhere
638
      *
639
      * This function serves as the central piece of SearchForm2.php
640
      * It is responsible for creating the WHERE clause for a given search operation
641
      *
642
      * @param bool $add_custom_fields boolean indicating whether or not custom fields should be added
643
      * @param string $module Module to search against
644
      *
645
      * @return string the SQL WHERE clause based on the arguments supplied in SearchForm2 instance
646
      */
647 1
     public function generateSearchWhere($add_custom_fields = false, $module='') {
648 1
         global $timedate;
649
650 1
         $db = $this->seed->db;
651 1
         $this->searchColumns = array () ;
652 1
         $values = $this->searchFields;
653
654 1
         $where_clauses = array();
655 1
         $like_char = '%';
656 1
         $table_name = $this->seed->object_name;
657 1
         $this->seed->fill_in_additional_detail_fields();
658
659
         //rrs check for team_id
660
661 1
         foreach($this->searchFields as $field=>$parms) {
662 1
             $customField = false;
663
             // Jenny - Bug 7462: We need a type check here to avoid database errors
664
             // when searching for numeric fields. This is a temporary fix until we have
665
             // a generic search form validation mechanism.
666 1
             $type = (!empty($this->seed->field_name_map[$field]['type']))?$this->seed->field_name_map[$field]['type']:'';
667
668
             //If range search is enabled for the field, we first check if this is the starting range
669 1
             if(!empty($parms['enable_range_search']) && empty($type))
670
             {
671 1
                 if(preg_match('/^start_range_(.*?)$/', $field, $match))
672
                 {
673 1
                     $real_field = $match[1];
674 1
                     $start_field = 'start_range_' . $real_field;
675 1
                     $end_field = 'end_range_' . $real_field;
676
677 1
                     if(isset($this->searchFields[$start_field]['value']) && isset($this->searchFields[$end_field]['value']))
678
                     {
679
                         $this->searchFields[$real_field]['value'] = $this->searchFields[$start_field]['value'] . '<>' . $this->searchFields[$end_field]['value'];
680
                         $this->searchFields[$real_field]['operator'] = 'between';
681
                         $parms['value'] = $this->searchFields[$real_field]['value'];
682
                         $parms['operator'] = 'between';
683
684
                         $field_type = isset($this->seed->field_name_map[$real_field]['type']) ? $this->seed->field_name_map[$real_field]['type'] : '';
685
                         if($field_type == 'datetimecombo' || $field_type == 'datetime')
686
                         {
687
                                $type = $field_type;
688
                         }
689
690
                         $field = $real_field;
691
                         unset($this->searchFields[$end_field]['value']);
692
                     }else{
693
                         //if both start and end ranges have not been defined, skip this filter.
694 1
                        continue;
695
                     }
696 1
                 } else if (preg_match('/^range_(.*?)$/', $field, $match) && isset($this->searchFields[$field]['value'])) {
697
                     $real_field = $match[1];
698
699
                     //Special case for datetime and datetimecombo fields.  By setting the type here we allow an actual between search
700
                     if(in_array($parms['operator'], array('=', 'between', "not_equal", 'less_than', 'greater_than', 'less_than_equals', 'greater_than_equals')))
701
                     {
702
                        $field_type = isset($this->seed->field_name_map[$real_field]['type']) ? $this->seed->field_name_map[$real_field]['type'] : '';
703
                        if(strtolower($field_type) == 'readonly' && isset($this->seed->field_name_map[$real_field]['dbType'])) {
704
                           $field_type = $this->seed->field_name_map[$real_field]['dbType'];
705
                        }
706
                        if($field_type == 'datetimecombo' || $field_type == 'datetime' || $field_type == 'int')
707
                        {
708
                           $type = $field_type;
709
                        }
710
                     }
711
712
                     $this->searchFields[$real_field]['value'] = $this->searchFields[$field]['value'];
713
                     $this->searchFields[$real_field]['operator'] = $this->searchFields[$field]['operator'];
714
                     $params['value'] = $this->searchFields[$field]['value'];
715
                     $params['operator'] = $this->searchFields[$field]['operator'];
716
                     unset($this->searchFields[$field]['value']);
717
                     $field = $real_field;
718
                 } else {
719
                     //Skip this range search field, it is the end field THIS IS NEEDED or the end range date will break the query
720 1
                     continue;
721
                 }
722
             }
723
724
             //Test to mark whether or not the field is a custom field
725 1
             if(!empty($this->seed->field_name_map[$field]['source'])
726 1
                 && ($this->seed->field_name_map[$field]['source'] == 'custom_fields' ||
727
                     //Non-db custom fields, such as custom relates
728 1
                     ($this->seed->field_name_map[$field]['source'] == 'non-db'
729 1
                     && (!empty($this->seed->field_name_map[$field]['custom_module']) ||
730 1
                          isset($this->seed->field_name_map[$field]['ext2']))))){
731
                 $customField = true;
732
             }
733
734 1
             if ($type == 'int' && isset($parms['value']) && !empty($parms['value'])) {
735
                 require_once ('include/SugarFields/SugarFieldHandler.php');
736
                 $intField = SugarFieldHandler::getSugarField('int');
737
                 $newVal = $intField->getSearchWhereValue($parms['value']);
738
                 $parms['value'] = $newVal;
739 1
             } elseif($type == 'html' && $customField) {
740
                 continue;
741
             }
742
743
744 1
             if(isset($parms['value']) && $parms['value'] != "") {
745
746
                 $operator = $db->isNumericType($type)?'=':'like';
747
                 if(!empty($parms['operator'])) {
748
                     $operator = strtolower($parms['operator']);
749
                 }
750
751
                 if(is_array($parms['value'])) {
752
                     $field_value = '';
753
754
                     // always construct the where clause for multiselects using the 'like' form to handle combinations of multiple $vals and multiple $parms
755
                      if(!empty($this->seed->field_name_map[$field]['isMultiSelect']) && $this->seed->field_name_map[$field]['isMultiSelect']) {
756
                         // construct the query for multenums
757
                         // use the 'like' query as both custom and OOB multienums are implemented with types that cannot be used with an 'in'
758
                         $operator = 'custom_enum';
759
			// Relationshipfields get their field name directly from the field name map,
760
			// this alias-name is automatically replaced by the join table and rname through sugarbean::create_new_list_query
761
			if (isset($this->seed->field_name_map[$field]) &&
762
				isset($this->seed->field_name_map[$field]['source']) &&
763
				$this->seed->field_name_map[$field]['source'] == 'non-db')
764
			{
765
				$db_field = $this->seed->field_name_map[$field]['name'];
766
			}
767
			else
768
			{
769
				$table_name = $this->seed->table_name ;
770
				if ($customField)
771
					$table_name .= "_cstm" ;
772
				$db_field = $table_name . "." . $field;
773
			}
774
775
                         foreach($parms['value'] as $val) {
776
                             if($val != ' ' and $val != '') {
777
                                    $qVal = $db->quote($val);
778
                                    if (!empty($field_value)) {
779
                                        $field_value .= ' or ';
780
                                    }
781
                                    $field_value .= "$db_field like '%^$qVal^%'";
782
                             } else {
783
                                 $field_value .= '('.$db_field . ' IS NULL or '.$db_field."='^^' or ".$db_field."='')";
784
                             }
785
                         }
786
787
                     } else {
788
                         $operator = $operator != 'subquery' ? 'in' : $operator;
789
                         foreach($parms['value'] as $val) {
790
                             if($val != ' ' and $val != '') {
791
                                 if (!empty($field_value)) {
792
                                     $field_value .= ',';
793
                                 }
794
                                 $field_value .= $db->quoteType($type, $val);
795
                             }
796
                                 // Bug 41209: adding a new operator "isnull" here
797
                                 // to handle the case when blank is selected from dropdown.
798
                                 // In that case, $val is empty.
799
                                 // When $val is empty, we need to use "IS NULL",
800
                                 // as "in (null)" won't work
801
                                 else if ($operator=='in') {
802
                                     $operator = 'isnull';
803
                                 }
804
                         }
805
                     }
806
807
                 } else {
808
                     $field_value = $parms['value'];
809
                 }
810
811
                 //set db_fields array.
812
                 if(!isset($parms['db_field'])) {
813
                     $parms['db_field'] = array($field);
814
                 }
815
816
                 //This if-else block handles the shortcut checkbox selections for "My Items" and "Closed Only"
817
                 if(!empty($parms['my_items'])) {
818
                     if( $parms['value'] == false ) {
819
                         continue;
820
                     } else {
821
                         //my items is checked.
822
                         global $current_user;
823
                         $field_value = $db->quote($current_user->id);
824
                         $operator = '=' ;
825
                     }
826
                 } else if(!empty($parms['closed_values']) && is_array($parms['closed_values'])) {
827
                     if( $parms['value'] == false ) {
828
                         continue;
829
                     } else {
830
                         $field_value = '';
831
                         foreach($parms['closed_values'] as $closed_value)
832
                         {
833
                             $field_value .= "," . $db->quoted($closed_value);
834
                         }
835
                         $field_value = substr($field_value, 1);
836
                     }
837
                 }
838
839
                 $where = '';
840
                 $itr = 0;
841
842
                 if($field_value != '' || $operator=='isnull') {
843
844
                     $this->searchColumns [ strtoupper($field) ] = $field ;
845
846
                     foreach ($parms['db_field'] as $db_field) {
847
                         if (strstr($db_field, '.') === false) {
848
                             //Try to get the table for relate fields from link defs
849
                             if ($type == 'relate' && !empty($this->seed->field_name_map[$field]['link'])
850
                                 && !empty($this->seed->field_name_map[$field]['rname'])) {
851
                                     $link = $this->seed->field_name_map[$field]['link'];
852
                                     if (($this->seed->load_relationship($link))){
853
                                         //Martin fix #27494
854
                                         $db_field = $this->seed->field_name_map[$field]['name'];
855
                                     } else {
856
                                         //Best Guess for table name
857
                                         $db_field = strtolower($link['module']) . '.' . $db_field;
858
                                     }
859
860
861
                             }
862
                             else if ($type == 'parent') {
863
                                 if (!empty($this->searchFields['parent_type'])) {
864
                                     $parentType = $this->searchFields['parent_type'];
865
                                     $rel_module = $parentType['value'];
866
                                     global $beanFiles, $beanList;
867
                                     if(!empty($beanFiles[$beanList[$rel_module]])) {
868
                                         require_once($beanFiles[$beanList[$rel_module]]);
869
                                         $rel_seed = new $beanList[$rel_module]();
870
                                         $db_field = 'parent_' . $rel_module . '_' . $rel_seed->table_name . '.name';
871
                                     }
872
                                 }
873
                             }
874
                             // Relate fields in custom modules and custom relate fields
875
                             else if ($type == 'relate' && $customField && !empty($this->seed->field_name_map[$field]['module'])) {
876
                                 $db_field = !empty($this->seed->field_name_map[$field]['name'])?$this->seed->field_name_map[$field]['name']:'name';
877
                             }
878
                            else if(!$customField){
879
                                if ( !empty($this->seed->field_name_map[$field]['db_concat_fields']) )
880
                                    $db_field = $db->concat($this->seed->table_name, $this->seed->field_name_map[$db_field]['db_concat_fields']);
881
                                // Relationship fields get the name directly from the field_name_map
882
                                else if (!(isset($this->seed->field_name_map[$db_field]) && isset($this->seed->field_name_map[$db_field]['source']) && $this->seed->field_name_map[$db_field]['source'] == 'non-db'))
883
                                    $db_field = $this->seed->table_name .  "." . $db_field;
884
                             }else{
885
                                 if ( !empty($this->seed->field_name_map[$field]['db_concat_fields']) )
886
                                    $db_field = $db->concat($this->seed->table_name .  "_cstm.", $this->seed->field_name_map[$db_field]['db_concat_fields']);
887
                                else
888
                                    $db_field = $this->seed->table_name .  "_cstm." . $db_field;
889
                             }
890
891
                         }
892
893
                         if($type == 'date') {
894
                            // The regular expression check is to circumvent special case YYYY-MM
895
                             $operator = '=';
896
                             if(preg_match('/^\d{4}.\d{1,2}$/', $field_value) != 0) { // preg_match returns number of matches
897
                                $db_field = $this->seed->db->convert($db_field, "date_format", array("%Y-%m"));
898
                            } else {
899
                                $field_value = $timedate->to_db_date($field_value, false);
900
                                $db_field = $this->seed->db->convert($db_field, "date_format", array("%Y-%m-%d"));
901
                            }
902
                         }
903
904
                         if($type == 'datetime' || $type == 'datetimecombo') {
905
                             try {
906
                                 if($operator == '=' || $operator == 'between') {
907
                                     // FG - bug45287 - If User asked for a range, takes edges from it.
908
                                     $placeholderPos = strpos($field_value, "<>");
909
                                     if ($placeholderPos !== FALSE && $placeholderPos > 0)
910
                                     {
911
                                         $datesLimit = explode("<>", $field_value);
912
                                         $dateStart = $timedate->getDayStartEndGMT($datesLimit[0]);
913
                                         $dateEnd = $timedate->getDayStartEndGMT($datesLimit[1]);
914
                                         $dates = $dateStart;
915
                                         $dates['end'] = $dateEnd['end'];
916
                                         $dates['enddate'] = $dateEnd['enddate'];
917
                                         $dates['endtime'] = $dateEnd['endtime'];
918
                                     }
919
                                     else
920
                                     {
921
                                         $dates = $timedate->getDayStartEndGMT($field_value);
922
                                     }
923
                                     // FG - bug45287 - Note "start" and "end" are the correct interval at GMT timezone
924
                                     $field_value = array($dates["start"], $dates["end"]);
925
                                     $operator = 'between';
926
                                 } else if($operator == 'not_equal') {
927
                                    $dates = $timedate->getDayStartEndGMT($field_value);
928
                                    $field_value = array($dates["start"], $dates["end"]);
929
                                    $operator = 'date_not_equal';
930
                                 } else if($operator == 'greater_than') {
931
                                    $dates = $timedate->getDayStartEndGMT($field_value);
932
                                    $field_value = $dates["end"];
933
                                 } else if($operator == 'less_than') {
934
                                    $dates = $timedate->getDayStartEndGMT($field_value);
935
                                    $field_value = $dates["start"];
936
                                 } else if($operator == 'greater_than_equals') {
937
                                    $dates = $timedate->getDayStartEndGMT($field_value);
938
                                    $field_value = $dates["start"];
939
                                 } else if($operator == 'less_than_equals') {
940
                                    $dates = $timedate->getDayStartEndGMT($field_value);
941
                                    $field_value = $dates["end"];
942
                                 }
943
                             } catch(Exception $timeException) {
944
                                 //In the event that a date value is given that cannot be correctly processed by getDayStartEndGMT method,
945
                                 //just skip searching on this field and continue.  This may occur if user switches locale date formats
946
                                 //in another browser screen, but re-runs a search with the previous format on another screen
947
                                 $GLOBALS['log']->error($timeException->getMessage());
948
                                 continue;
949
                             }
950
                         }
951
952
                         if($type == 'decimal' || $type == 'float' || $type == 'currency' || (!empty($parms['enable_range_search']) && empty($parms['is_date_field']))) {
953
                             require_once('modules/Currencies/Currency.php');
954
955
                             //we need to handle formatting either a single value or 2 values in case the 'between' search option is set
956
                             //start by splitting the string if the between operator exists
957
                             $fieldARR = explode('<>', $field_value);
958
                             //set the first pass through boolean
959
                             $values = array();
960
                             foreach($fieldARR as $fv){
961
                                 //reset the field value, it will be rebuild in the foreach loop below
962
                                 $tmpfield_value = unformat_number($fv);
963
964
                                 if ( $type == 'currency' && stripos($field,'_usdollar')!==FALSE ) {
965
                                     // It's a US Dollar field, we need to do some conversions from the user's local currency
966
                                     $currency_id = $GLOBALS['current_user']->getPreference('currency');
967
                                     if ( empty($currency_id) ) {
968
                                         $currency_id = -99;
969
                                     }
970
                                     if ( $currency_id != -99 ) {
971
                                         $currency = new Currency();
972
                                         $currency->retrieve($currency_id);
973
                                         $tmpfield_value = $currency->convertToDollar($tmpfield_value);
974
                                     }
975
                                 }
976
                                 $values[] = $tmpfield_value;
977
                             }
978
979
                             $field_value = join('<>',$values);
980
981
                             if(!empty($parms['enable_range_search']) && $parms['operator'] == '=' && $type != 'int')
982
                             {
983
                                 // Databases can't really search for floating point numbers, because they can't be accurately described in binary,
984
                                 // So we have to fuzz out the math a little bit
985
                                 $field_value = array(($field_value - 0.01) , ($field_value + 0.01));
986
                                 $operator = 'between';
987
                             }
988
                         }
989
990
991
                         if($db->supports("case_sensitive") && isset($parms['query_type']) && $parms['query_type'] == 'case_insensitive') {
992
                               $db_field = 'upper(' . $db_field . ")";
993
                               $field_value = strtoupper($field_value);
994
                         }
995
996
                         $itr++;
997
                         if(!empty($where)) {
998
                             $where .= " OR ";
999
                         }
1000
1001
                         //Here we make a last attempt to determine the field type if possible
1002
                         if(empty($type) && isset($parms['db_field']) && isset($parms['db_field'][0]) && isset($this->seed->field_defs[$parms['db_field'][0]]['type']))
1003
                         {
1004
                             $type = $this->seed->field_defs[$parms['db_field'][0]]['type'];
1005
                         }
1006
1007
                         switch(strtolower($operator)) {
1008
                             case 'subquery':
1009
                                 $in = 'IN';
1010
                                 if ( isset($parms['subquery_in_clause']) ) {
1011
                                     if ( !is_array($parms['subquery_in_clause']) ) {
1012
                                         $in = $parms['subquery_in_clause'];
1013
                                     }
1014
                                     elseif ( isset($parms['subquery_in_clause'][$field_value]) ) {
1015
                                         $in = $parms['subquery_in_clause'][$field_value];
1016
                                     }
1017
                                 }
1018
                                 $sq = $parms['subquery'];
1019
                                 if(is_array($sq)){
1020
                                     $and_or = ' AND ';
1021
                                     if (isset($sq['OR'])){
1022
                                         $and_or = ' OR ';
1023
                                     }
1024
                                     $first = true;
1025
                                     foreach($sq as $q){
1026
                                         if(empty($q) || strlen($q)<2) continue;
1027
                                         if(!$first){
1028
                                             $where .= $and_or;
1029
                                         }
1030
                                         $where .= " {$db_field} $in ({$q} ".$this->seed->db->quoted($field_value.'%').") ";
1031
                                         $first = false;
1032
                                     }
1033
                                 }elseif(!empty($parms['query_type']) && $parms['query_type'] == 'format'){
1034
                                     $stringFormatParams = array(0 => $field_value, 1 => $GLOBALS['current_user']->id);
1035
                                     $where .= "{$db_field} $in (".string_format($parms['subquery'], $stringFormatParams).")";
1036
                                 }else{
1037
                                     //Bug#37087: Re-write our sub-query to it is executed first and contents stored in a derived table to avoid mysql executing the query
1038
                                     //outside in. Additional details: http://bugs.mysql.com/bug.php?id=9021
1039
                                     $selectCol = ' * ';
1040
                                     //use the select column in the subquery if it exists
1041
                                     if(!empty($parms['subquery'])){
1042
                                         $selectCol = $this->getSelectCol($parms['subquery']);
0 ignored issues
show
The method getSelectCol() does not seem to exist on object<SearchForm>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
1043
                                     }
1044
                                    $where .= "{$db_field} $in (select $selectCol from ({$parms['subquery']} ".$this->seed->db->quoted($field_value.'%').") {$field}_derived)";
1045
                                 }
1046
1047
                                 break;
1048
1049
                             case 'like':
1050
                                 if($type == 'bool' && $field_value == 0)
1051
                                 {
1052
                                     // Bug 43452 - FG - Added parenthesis surrounding the OR (without them the WHERE clause would be broken)
1053
                                     $where .=  "( " . $db_field . " = '0' OR " . $db_field . " IS NULL )";
1054
                                 }
1055
                                 else
1056
                                 {
1057
                                     // check to see if this is coming from unified search or not
1058
                                     $UnifiedSearch = !empty($parms['force_unifiedsearch']);
1059
                                     if(isset($_REQUEST['action']) && $_REQUEST['action'] == 'UnifiedSearch'){
1060
                                         $UnifiedSearch = true;
1061
                                     }
1062
1063
                                     // If it is a unified search and if the search contains more then 1 word (contains space)
1064
                                     // and if it's the last element from db_field (so we do the concat only once, not for every db_field element)
1065
                                     // we concat the db_field array() (both original, and in reverse order) and search for the whole string in it
1066
                                     if ( $UnifiedSearch && strpos($field_value, ' ') !== false && strpos($db_field, $parms['db_field'][count($parms['db_field']) - 1]) !== false )
1067
                                     {
1068
                                         // Get the table name used for concat
1069
                                         $concat_table = explode('.', $db_field);
1070
                                         $concat_table = $concat_table[0];
1071
                                         // Get the fields for concatenating
1072
                                         $concat_fields = $parms['db_field'];
1073
1074
                                         // If db_fields (e.g. contacts.first_name) contain table name, need to remove it
1075
                                         for ($i = 0; $i < count($concat_fields); $i++)
0 ignored issues
show
Performance Best Practice introduced by
It seems like you are calling the size function count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration:

for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
1076
                                         {
1077
                                         	if (strpos($concat_fields[$i], $concat_table) !== false)
1078
                                         	{
1079
                                         		$concat_fields[$i] = substr($concat_fields[$i], strlen($concat_table) + 1);
1080
                                         	}
1081
                                         }
1082
1083
                                         // Concat the fields and search for the value
1084
                                         $where .= $this->seed->db->concat($concat_table, $concat_fields) . " LIKE " . $this->seed->db->quoted($field_value . $like_char);
1085
                                         $where .= ' OR ' . $this->seed->db->concat($concat_table, array_reverse($concat_fields)) . " LIKE " . $this->seed->db->quoted($field_value . $like_char);
1086
                                     }
1087
                                     else
1088
                                     {
1089
                                         //Check if this is a first_name, last_name search
1090
                                         if(isset($this->seed->field_name_map) && isset($this->seed->field_name_map[$db_field]))
1091
                                         {
1092
                                             $vardefEntry = $this->seed->field_name_map[$db_field];
1093
                                             if(!empty($vardefEntry['db_concat_fields']) && in_array('first_name', $vardefEntry['db_concat_fields']) && in_array('last_name', $vardefEntry['db_concat_fields']))
1094
                                             {
1095
                                                   if(!empty($GLOBALS['app_list_strings']['salutation_dom']) && is_array($GLOBALS['app_list_strings']['salutation_dom']))
1096
                                                   {
1097
                                                      foreach($GLOBALS['app_list_strings']['salutation_dom'] as $salutation)
1098
                                                      {
1099
                                                         if(!empty($salutation) && strpos($field_value, $salutation) === 0)
1100
                                                         {
1101
                                                            $field_value = trim(substr($field_value, strlen($salutation)));
1102
                                                            break;
1103
                                                         }
1104
                                                      }
1105
                                                   }
1106
                                             }
1107
                                         }
1108
1109
                                         //field is not last name or this is not from global unified search, so do normal where clause
1110
                                         $where .=  $db_field . " like ".$this->seed->db->quoted(sql_like_string($field_value, $like_char));
1111
                                     }
1112
                                 }
1113
                                 break;
1114
                             case 'not in':
1115
                                 $where .= $db_field . ' not in ('.$field_value.')';
1116
                                 break;
1117
                             case 'in':
1118
                                 $where .=  $db_field . ' in ('.$field_value.')';
1119
                                 break;
1120
                             case '=':
1121
                                 if($type == 'bool' && $field_value == 0) {
1122
                                     $where .=  "($db_field = 0 OR $db_field IS NULL)";
1123
                                 }
1124
                                 else {
1125
                                     $where .=  $db_field . " = ".$db->quoteType($type, $field_value);
1126
                                 }
1127
                                 break;
1128
                             // tyoung bug 15971 - need to add these special cases into the $where query
1129
                             case 'custom_enum':
1130
                                 $where .= $field_value;
1131
                                 break;
1132
                             case 'between':
1133
                                 if(!is_array($field_value)) {
1134
                                     $field_value = explode('<>', $field_value);
1135
                                 }
1136
                                 $field_value[0] = $db->quoteType($type, $field_value[0]);
1137
                                 $field_value[1] = $db->quoteType($type, $field_value[1]);
1138
                                 $where .= "($db_field >= {$field_value[0]} AND $db_field <= {$field_value[1]})";
1139
                                 break;
1140
                             case 'date_not_equal':
1141
                                 if(!is_array($field_value)) {
1142
                                     $field_value = explode('<>', $field_value);
1143
                                 }
1144
                                 $field_value[0] = $db->quoteType($type, $field_value[0]);
1145
                                 $field_value[1] = $db->quoteType($type, $field_value[1]);
1146
                                 $where .= "($db_field IS NULL OR $db_field < {$field_value[0]} OR $db_field > {$field_value[1]})";
1147
                                 break;
1148
                             case 'innerjoin':
1149
                                 $this->seed->listview_inner_join[] = $parms['innerjoin'] . " '" . $parms['value'] . "%')";
1150
                                 break;
1151
                             case 'not_equal':
1152
                                 $field_value = $db->quoteType($type, $field_value);
1153
                                 $where .= "($db_field IS NULL OR $db_field != $field_value)";
1154
                                 break;
1155
                             case 'greater_than':
1156
                                 $field_value = $db->quoteType($type, $field_value);
1157
                                 $where .= "$db_field > $field_value";
1158
                                 break;
1159
                             case 'greater_than_equals':
1160
                                 $field_value = $db->quoteType($type, $field_value);
1161
                                 $where .= "$db_field >= $field_value";
1162
                                 break;
1163
                             case 'less_than':
1164
                                 $field_value = $db->quoteType($type, $field_value);
1165
                                 $where .= "$db_field < $field_value";
1166
                                 break;
1167
                             case 'less_than_equals':
1168
                                 $field_value = $db->quoteType($type, $field_value);
1169
                                 $where .= "$db_field <= $field_value";
1170
                                 break;
1171
                             case 'next_7_days':
1172
                             case 'last_7_days':
1173
                             case 'last_month':
1174
                             case 'this_month':
1175
                             case 'next_month':
1176
                             case 'last_30_days':
1177
                             case 'next_30_days':
1178
                             case 'this_year':
1179
                             case 'last_year':
1180
                             case 'next_year':
1181
                                 if (!empty($field) && !empty($this->seed->field_name_map[$field]['type'])) {
1182
                                     $where .= $this->parseDateExpression(strtolower($operator), $db_field, $this->seed->field_name_map[$field]['type']);
0 ignored issues
show
The method parseDateExpression() does not seem to exist on object<SearchForm>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
1183
                                 } else {
1184
                                     $where .= $this->parseDateExpression(strtolower($operator), $db_field);
0 ignored issues
show
The method parseDateExpression() does not seem to exist on object<SearchForm>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
1185
                                 }
1186
                                 break;
1187
                             case 'isnull':
1188
                                 $where .=  "($db_field IS NULL OR $db_field = '')";
1189
                                 if ($field_value != '')
1190
                                     $where .=  ' OR ' . $db_field . " in (".$field_value.')';
1191
                                 break;
1192
                         }
1193
                     }
1194
                 }
1195
1196
                 if(!empty($where)) {
1197
                     if($itr > 1) {
1198
                         array_push($where_clauses, '( '.$where.' )');
1199
                     }
1200
                     else {
1201 1
                         array_push($where_clauses, $where);
1202
                     }
1203
                 }
1204
             }
1205
         }
1206
1207 1
         return $where_clauses;
1208
     }
1209
1210
1211
1212
    /**
1213
     * isEmptyDropdownField
1214
     *
1215
     * This function checks to see if a blank dropdown field was supplied.  This scenario will occur where
1216
     * a dropdown select is in single selection mode
1217
     *
1218
     * @param $value Mixed dropdown value
1219
     */
1220
    private function isEmptyDropdownField($name='', $value=array())
1221
    {
1222
    	$result = is_array($value) && isset($value[0]) && $value[0] == '';
1223
    	$GLOBALS['log']->debug("Found empty value for {$name} dropdown search key");
1224
    	return $result;
1225
    }
1226
1227
     /**
1228
      * Return the search defs for a particular module.
1229
      *
1230
      * @static
1231
      * @param $module
1232
      */
1233 5
     public static function retrieveSearchDefs($module)
1234
     {
1235 5
         $searchdefs = array();
1236 5
         $searchFields = array();
1237
1238 5
         if(file_exists('custom/modules/'.$module.'/metadata/metafiles.php'))
1239
         {
1240
             require('custom/modules/'.$module.'/metadata/metafiles.php');
1241
         }
1242 5
         elseif(file_exists('modules/'.$module.'/metadata/metafiles.php'))
1243
         {
1244
             require('modules/'.$module.'/metadata/metafiles.php');
1245
         }
1246
1247 5
         if (file_exists('custom/modules/'.$module.'/metadata/searchdefs.php'))
1248
         {
1249
             require('custom/modules/'.$module.'/metadata/searchdefs.php');
1250
         }
1251 5
         elseif (!empty($metafiles[$module]['searchdefs']))
0 ignored issues
show
The variable $metafiles seems to never exist, and therefore empty should always return true. Did you maybe rename this variable?

This check looks for calls to isset(...) or empty() on variables that are yet undefined. These calls will always produce the same result and can be removed.

This is most likely caused by the renaming of a variable or the removal of a function/method parameter.

Loading history...
1252
         {
1253
             require($metafiles[$module]['searchdefs']);
1254
         }
1255 5
         elseif (file_exists('modules/'.$module.'/metadata/searchdefs.php'))
1256
         {
1257 3
             require('modules/'.$module.'/metadata/searchdefs.php');
1258
         }
1259
1260
1261 5
         if(!empty($metafiles[$module]['searchfields']))
1262
         {
1263
             require($metafiles[$module]['searchfields']);
1264
         }
1265 5
         elseif(file_exists('modules/'.$module.'/metadata/SearchFields.php'))
1266
         {
1267 3
             require('modules/'.$module.'/metadata/SearchFields.php');
1268
         }
1269 5
         if(file_exists('custom/modules/'.$module.'/metadata/SearchFields.php'))
1270
         {
1271
             require('custom/modules/'.$module.'/metadata/SearchFields.php');
1272
         }
1273
1274 5
         return array('searchdefs' => $searchdefs, 'searchFields' => $searchFields );
1275
     }
1276
1277
    /**
1278
      * this function will take the subquery string and return the columns to be used in the select of the derived table
1279
      *
1280
      * @param string $subquery the subquery string to parse through
1281
      * @return string the retrieved column list
1282
      */
1283
    protected function getSelectCol($subquery)
1284
    {
1285
        $selectCol = '';
1286
1287
        if (empty($subquery)) {
1288
            return $selectCol;
1289
        }
1290
        $subquery = strtolower($subquery);
1291
        //grab the values between the select and from
1292
        $select = stripos($subquery, 'select');
1293
        $from = stripos($subquery, 'from');
1294
        if ($select !==false && $from!==false && $select+6 < $from) {
1295
            $selectCol = substr($subquery, $select+6, $from-$select-6);
1296
        }
1297
        //remove table names if they exist
1298
        $columns = explode(',', $selectCol);
1299
        $i = 0;
1300
        foreach ($columns as $column) {
1301
            $dot = strpos($column, '.');
1302
            if ($dot > 0) {
1303
                $columns[$i] = substr($column, $dot+1);
1304
            }
1305
            $i++;
1306
        }
1307
        $selectCol = implode(',', $columns);
1308
        return $selectCol;
1309
    }
1310
 }
1311