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.

modules/DynamicFields/DynamicField.php (17 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
if (! defined ( 'sugarEntry' ) || ! sugarEntry)
3
    die ( 'Not A Valid Entry Point' ) ;
4
5
/*********************************************************************************
6
 * SugarCRM Community Edition is a customer relationship management program developed by
7
 * SugarCRM, Inc. Copyright (C) 2004-2013 SugarCRM Inc.
8
9
 * SuiteCRM is an extension to SugarCRM Community Edition developed by Salesagility Ltd.
10
 * Copyright (C) 2011 - 2014 Salesagility Ltd.
11
 *
12
 * This program is free software; you can redistribute it and/or modify it under
13
 * the terms of the GNU Affero General Public License version 3 as published by the
14
 * Free Software Foundation with the addition of the following permission added
15
 * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK
16
 * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY
17
 * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
18
 *
19
 * This program is distributed in the hope that it will be useful, but WITHOUT
20
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
21
 * FOR A PARTICULAR PURPOSE.  See the GNU Affero General Public License for more
22
 * details.
23
 *
24
 * You should have received a copy of the GNU Affero General Public License along with
25
 * this program; if not, see http://www.gnu.org/licenses or write to the Free
26
 * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
27
 * 02110-1301 USA.
28
 *
29
 * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road,
30
 * SW2-130, Cupertino, CA 95014, USA. or at email address [email protected].
31
 *
32
 * The interactive user interfaces in modified source and object code versions
33
 * of this program must display Appropriate Legal Notices, as required under
34
 * Section 5 of the GNU Affero General Public License version 3.
35
 *
36
 * In accordance with Section 7(b) of the GNU Affero General Public License version 3,
37
 * these Appropriate Legal Notices must retain the display of the "Powered by
38
 * SugarCRM" logo and "Supercharged by SuiteCRM" logo. If the display of the logos is not
39
 * reasonably feasible for  technical reasons, the Appropriate Legal Notices must
40
 * display the words  "Powered by SugarCRM" and "Supercharged by SuiteCRM".
41
 ********************************************************************************/
42
43
44
class DynamicField {
45
46
    var $use_existing_labels = false; // this value is set to true by install_custom_fields() in ModuleInstaller.php; everything else expects it to be false
47
    var $base_path = "";
48
49 883
    public function __construct($module = '') {
50 883
        $this->module = (! empty ( $module )) ? $module :( (isset($_REQUEST['module']) && ! empty($_REQUEST['module'])) ? $_REQUEST ['module'] : '');
51 883
        $this->base_path = "custom/Extension/modules/{$this->module}/Ext/Vardefs";
52 883
    }
53
54
    /**
55
     * @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
56
     */
57
    public function DynamicField($module = ''){
58
        $deprecatedMessage = 'PHP4 Style Constructors are deprecated and will be remove in 7.8, please update your code';
59
        if(isset($GLOBALS['log'])) {
60
            $GLOBALS['log']->deprecated($deprecatedMessage);
61
        }
62
        else {
63
            trigger_error($deprecatedMessage, E_USER_DEPRECATED);
64
        }
65
        self::__construct($module);
66
    }
67
68
   function getModuleName()
69
    {
70
        return $this->module ;
71
    }
72
73
    /*
74
     * As DynamicField has a counterpart in MBModule, provide the MBModule function getPackagename() here also
75
     */
76
    function getPackageName()
77
    {
78
        return null ;
79
    }
80
81
    function deleteCache(){
82
    }
83
84
85
    /**
86
    * This will add the bean as a reference in this object as well as building the custom field cache if it has not been built
87
    * LOADS THE BEAN IF THE BEAN IS NOT BEING PASSED ALONG IN SETUP IT SHOULD BE SET PRIOR TO SETUP
88
    *
89
    * @param SUGARBEAN $bean
90
    */
91 875
    function setup($bean = null) {
92 875
        if ($bean) {
93 875
            $this->bean = $bean;
94
        }
95 875
        if (isset ( $this->bean->module_dir )) {
96 875
            $this->module = $this->bean->module_dir;
97
        }
98 875
        if(!isset($GLOBALS['dictionary'][$this->bean->object_name]['custom_fields'])){
99 864
            $this->buildCache ( $this->module );
100
        }
101 875
    }
102
103
    function setLabel( $language='en_us' , $key , $value )
104
    {
105
        $params [ "label_" . $key ] = $value;
106
        require_once 'modules/ModuleBuilder/parsers/parser.label.php' ;
107
        $parser = new ParserLabel ( $this->module ) ;
108
        $parser->handleSave( $params , $language);
109
    }
110
111
    /**
112
    * Builds the cache for custom fields based on the vardefs
113
    *
114
    * @param STRING $module
115
    * @param boolean saveCache Boolean value indicating whether or not to pass saveCache value to saveToVardef, defaults to true
116
    * @return unknown
117
    */
118 872
    function buildCache($module = false, $saveCache=true) {
119
        //We can't build the cache while installing as the required database tables may not exist.
120 872
        if (!empty($GLOBALS['installing']) && $GLOBALS['installing'] == true|| empty($GLOBALS['db']))
121
            return false;
122 872
        if($module == '../data')return false;
123
124 872
        static $results = array ( ) ;
125
126 872
        $where = '';
127 872
        if (! empty ( $module )) {
128 871
            $where .= " custom_module='$module' AND ";
129 871
            unset( $results[ $module ] ) ; // clear out any old results for the module as $results is declared static
130
        }
131
        else
132
        {
133 1
            $results = array ( ) ; // clear out results - if we remove a module we don't want to have its old vardefs hanging around
134
        }
135
136 872
        $GLOBALS['log']->debug('rebuilding cache for ' . $module);
137 872
        $query = "SELECT * FROM fields_meta_data WHERE $where deleted = 0";
138
139 872
        $result = $GLOBALS['db']->query ( $query );
140 872
        require_once ('modules/DynamicFields/FieldCases.php');
141
142
        // retrieve the field definition from the fields_meta_data table
143
        // using 'encode'=false to fetchByAssoc to prevent any pre-formatting of the base metadata
144
        // for immediate use in HTML. This metadata will be further massaged by get_field_def() and so should not be pre-formatted
145 872
        while ( $row = $GLOBALS['db']->fetchByAssoc ( $result, false ) ) {
146 22
            $field = get_widget ( $row ['type'] );
147
148 22
            foreach ( $row as $key => $value ) {
149 22
                $field->$key = $value;
150
            }
151 22
            $field->default = $field->default_value;
152 22
            $vardef = $field->get_field_def ();
153 22
            $vardef ['id'] = $row ['id'];
154 22
            $vardef ['custom_module'] = $row ['custom_module'];
155 22
            if (empty ( $vardef ['source'] ))
156
                $vardef ['source'] = 'custom_fields';
157 22
            if (empty ( $results [$row ['custom_module']] ))
158 22
                $results [$row ['custom_module']] = array ( );
159 22
            $results [$row ['custom_module']] [$row ['name']] = $vardef;
160
        }
161 872
        if (empty ( $module )) {
162 1
            foreach ( $results as $module => $result ) {
163 1
                $this->saveToVardef ( $module, $result, $saveCache);
164
            }
165
        } else {
166 871
            if (! empty ( $results [$module] )) {
167 22
                $this->saveToVardef ( $module, $results [$module], $saveCache);
168
            }else{
169 865
                $this->saveToVardef ( $module, false, $saveCache);
170
            }
171
        }
172
173 872
        return true;
174
175
    }
176
177
    /**
178
    * Returns the widget for a custom field from the fields_meta_data table.
179
    */
180
    function getFieldWidget($module, $fieldName) {
181
        if (empty($module) || empty($fieldName)){
182
            sugar_die("Unable to load widget for '$module' : '$fieldName'");
183
        }
184
        $query = "SELECT * FROM fields_meta_data WHERE custom_module='$module' AND name='$fieldName' AND deleted = 0";
185
        $result = $GLOBALS['db']->query ( $query );
186
        require_once ('modules/DynamicFields/FieldCases.php');
187
        if ( $row = $GLOBALS['db']->fetchByAssoc ( $result ) ) {
188
            $field = get_widget ( $row ['type'] );
189
            $field->populateFromRow($row);
190
            return $field;
191
        }
192
    }
193
194
195
    /**
196
    * Updates the cached vardefs with the custom field information stored in result
197
    *
198
    * @param string $module
199
    * @param array $result
200
    * @param boolean saveCache Boolean value indicating whether or not to call VardefManager::saveCache, defaults to true
201
    */
202 871
    function saveToVardef($module,$result,$saveCache=true) {
203
204
205 871
        global $beanList;
206 871
        if (! empty ( $beanList [$module] )) {
207 871
            $object = BeanFactory::getObjectName($module);
208
209 871
            if(empty($GLOBALS['dictionary'][$object]['fields'])){
210
                //if the vardef isn't loaded let's try loading it.
211 783
                VardefManager::refreshVardefs($module,$object, null, false);
212
                //if it's still not loaded we really don't have anything useful to cache
213 783
                if(empty($GLOBALS['dictionary'][$object]['fields']))return;
214
            }
215 868
            if (!isset($GLOBALS['dictionary'][$object]['custom_fields'])) {
216 864
                $GLOBALS['dictionary'][$object]['custom_fields'] = false;
217
            }
218 868
            if (! empty ( $GLOBALS ['dictionary'] [$object] )) {
219 868
                if (! empty ( $result )) {
220
                    // First loop to add
221
222 22
                foreach ( $result as $field ) {
223 22
                    foreach($field as $k=>$v){
224
                        //allows values for custom fields to be defined outside of the scope of studio
225 22
                        if(!isset($GLOBALS ['dictionary'] [$object] ['fields'] [$field ['name']][$k])){
226 22
                            $GLOBALS ['dictionary'] [$object] ['fields'] [$field ['name']][$k] = $v;
227
                        }
228
                    }
229
                }
230
231
                    // Second loop to remove
232 22
                    foreach ( $GLOBALS ['dictionary'] [$object] ['fields'] as $name => $fieldDef ) {
233
234 22
                        if (isset ( $fieldDef ['custom_module'] )) {
235 22
                            if (! isset ( $result [$name] )) {
236
                                unset ( $GLOBALS ['dictionary'] [$object] ['fields'] [$name] );
237
                            } else {
238 22
                                $GLOBALS ['dictionary'] [$object] ['custom_fields'] = true;
239
                            }
240
                        }
241
242
                    } //if
243
                }
244
            }
245
246 868
            $manager = new VardefManager();
247 868
            if($saveCache)
248
            {
249 862
                $manager->saveCache ($this->module, $object);
250
            }
251
252
            // Everything works off of vardefs, so let's have it save the users vardefs
253
            // to the employees module, because they both use the same table behind
254
            // the scenes
255 868
            if ($module == 'Users')
256
            {
257 157
                $manager->loadVardef('Employees', 'Employee', true);
258 157
                return;
259
            }
260
261
        }
262 868
    }
263
264
    /**
265
    * returns either false or an array containing the select and join parameter for a query using custom fields
266
    * @param $expandedList boolean	If true, return a list of all fields with source=custom_fields in the select instead of the standard _cstm.*
267
    *     This is required for any downstream construction of a SQL statement where we need to manipulate the select list,
268
    *     for example, listviews with custom relate fields where the value comes from join rather than from the custom table
269
    *
270
    * @return array select=>select columns, join=>prebuilt join statement
271
    */
272 170
  function getJOIN( $expandedList = false , $includeRelates = false, &$where = false){
273 170
        if(!$this->bean->hasCustomFields()){
274
            return array(
275 170
                'select' => '',
276
                'join' => ''
277
            );
278
        }
279
280
        if (empty($expandedList) )
281
        {
282
            $select = ",{$this->bean->table_name}_cstm.*" ;
283
        }
284
        else
285
        {
286
            $select = '';
287
            $isList = is_array($expandedList);
288
            foreach($this->bean->field_defs as $name=>$field)
289
            {
290
                if (!empty($field['source']) && $field['source'] == 'custom_fields' && (!$isList || !empty($expandedList[$name]))){
291
                    // assumption: that the column name in _cstm is the same as the field name. Currently true.
292
                    // however, two types of dynamic fields do not have columns in the custom table - html fields (they're readonly) and flex relates (parent_name doesn't exist)
293
                    if ( $field['type'] != 'html' && $name != 'parent_name')
294
                        $select .= ",{$this->bean->table_name}_cstm.{$name}" ;
295
                }
296
            }
297
        }
298
        $join = " LEFT JOIN " .$this->bean->table_name. "_cstm ON " .$this->bean->table_name. ".id = ". $this->bean->table_name. "_cstm.id_c ";
299
300
        if ($includeRelates) {
301
            $jtAlias = "relJoin";
302
            $jtCount = 1;
303
            foreach($this->bean->field_defs as $name=>$field)
304
            {
305
                if ($field['type'] == 'relate' && isset($field['custom_module'])) {
306
                    $relateJoinInfo = $this->getRelateJoin($field, $jtAlias.$jtCount);
307
                    $select .= $relateJoinInfo['select'];
308
                    $join .= $relateJoinInfo['from'];
309
                    //bug 27654 martin
310
                    if ($where)
311
                    {
312
                        $pattern = '/'.$field['name'].'\slike/i';
313
                        $replacement = $relateJoinInfo['name_field'].' like';
314
                        $where = preg_replace($pattern,$replacement,$where);
315
                    }
316
                    $jtCount++;
317
                }
318
            }
319
        }
320
321
        return array('select'=>$select, 'join'=>$join);
322
323
    }
324
325
   function getRelateJoin($field_def, $joinTableAlias, $withIdName = true) {
326
        if (empty($field_def['type']) || $field_def['type'] != "relate") {
327
            return false;
328
        }
329
        global $beanFiles, $beanList, $module;
330
        $rel_module = $field_def['module'];
331
        if(empty($beanFiles[$beanList[$rel_module]])) {
332
            return false;
333
        }
334
335
        require_once($beanFiles[$beanList[$rel_module]]);
336
        $rel_mod = new $beanList[$rel_module]();
337
        $rel_table = $rel_mod->table_name;
338
        if (isset($rel_mod->field_defs['name']))
339
        {
340
            $name_field_def = $rel_mod->field_defs['name'];
341
            if(isset($name_field_def['db_concat_fields']))
342
            {
343
                $name_field = db_concat($joinTableAlias, $name_field_def['db_concat_fields']);
0 ignored issues
show
Deprecated Code introduced by
The function db_concat() has been deprecated with message: use DBManager::concat() 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...
344
            }
345
            //If the name field is non-db, we need to find another field to display
346
            else if(!empty($rel_mod->field_defs['name']['source']) && $rel_mod->field_defs['name']['source'] == "non-db" && !empty($field_def['rname']))
347
            {
348
                $name_field = "$joinTableAlias." . $field_def['rname'];
349
            }
350
            else
351
            {
352
                $name_field = "$joinTableAlias.name";
353
            }
354
        }
355
        $tableName = isset($field_def['custom_module']) ? "{$this->bean->table_name}_cstm" : $this->bean->table_name ;
356
        $relID = $field_def['id_name'];
357
        $ret_array['rel_table'] = $rel_table;
358
        $ret_array['name_field'] = $name_field;
359
        $ret_array['select'] = ($withIdName ? ", {$tableName}.{$relID}" : "") . ", {$name_field} {$field_def['name']} ";
360
        $ret_array['from'] = " LEFT JOIN $rel_table $joinTableAlias ON $tableName.$relID = $joinTableAlias.id"
361
                            . " AND $joinTableAlias.deleted=0 ";
362
        return $ret_array;
363
   }
364
365
   /**
366
    * Fills in all the custom fields of type relate relationships for an object
367
    *
368
    */
369 80
   function fill_relationships(){
370 80
        global $beanList, $beanFiles;
371 80
        if(!empty($this->bean->relDepth)) {
372
            if($this->bean->relDepth > 1)return;
373
        }else{
374 80
            $this->bean->relDepth = 0;
375
        }
376 80
        foreach($this->bean->field_defs as $field){
377 80
            if(empty($field['source']) || $field['source'] != 'custom_fields')continue;
378
            if($field['type'] == 'relate'){
379
                $related_module =$field['ext2'];
380
                $name = $field['name'];
381
                if (empty($this->bean->$name)) { //Don't load the relationship twice
382
                    $id_name = $field['id_name'];
383
                    if(isset($beanList[ $related_module])){
384
                        $class = $beanList[$related_module];
385
386
                        if(file_exists($beanFiles[$class]) && isset($this->bean->$name)){
387
                            require_once($beanFiles[$class]);
388
                            $mod = new $class();
389
                            $mod->relDepth = $this->bean->relDepth + 1;
390
                            $mod->retrieve($this->bean->$id_name);
391
                            $this->bean->$name = $mod->name;
392
                        }
393
                    }
394
                }
395
            }
396
        }
397 80
    }
398
399
    /**
400
     * Process the save action for sugar bean custom fields
401
     *
402
     * @param boolean $isUpdate
403
     */
404 66
     function save($isUpdate){
405
406 66
        if($this->bean->hasCustomFields() && isset($this->bean->id)){
407
408
            if($isUpdate){
409
                $query = "UPDATE ". $this->bean->table_name. "_cstm SET ";
410
            }
411
            $queryInsert = "INSERT INTO ". $this->bean->table_name. "_cstm (id_c";
412
            $values = "('".$this->bean->id."'";
413
            $first = true;
414
            foreach($this->bean->field_defs as $name=>$field){
415
416
                if(empty($field['source']) || $field['source'] != 'custom_fields')continue;
417
                if($field['type'] == 'html' || $field['type'] == 'parent')continue;
418
                if(isset($this->bean->$name)){
419
                    $quote = "'";
420
421
                    if(in_array($field['type'], array('int', 'float', 'double', 'uint', 'ulong', 'long', 'short', 'tinyint', 'currency', 'decimal'))) {
422
                        $quote = '';
423
                        if(!isset($this->bean->$name) || !is_numeric($this->bean->$name) ){
424
                            if($field['required']){
425
                                $this->bean->$name = 0;
426
                            }else{
427
                                $this->bean->$name = 'NULL';
428
                            }
429
                        }
430
                    }
431
                    if ( $field['type'] == 'bool' ) {
432
                        if ( $this->bean->$name === FALSE )
433
                            $this->bean->$name = '0';
434
                        elseif ( $this->bean->$name === TRUE )
435
                            $this->bean->$name = '1';
436
                    }
437
438
                    $val = $this->bean->$name;
439
					if(($field['type'] == 'date' || $field['type'] == 'datetimecombo') && (empty($this->bean->$name )|| $this->bean->$name == '1900-01-01')){
440
                    	$quote = '';
441
                        $val = 'NULL';
442
                        $this->bean->$name = ''; // do not set it to string 'NULL'
443
                    }
444
                    if($isUpdate){
445
                        if($first){
446
                            $query .= " $name=$quote".$GLOBALS['db']->quote($val)."$quote";
447
448
                        }else{
449
                            $query .= " ,$name=$quote".$GLOBALS['db']->quote($val)."$quote";
450
                        }
451
                    }
452
                    $first = false;
453
                    $queryInsert .= " ,$name";
454
                    $values .= " ,$quote". $GLOBALS['db']->quote($val). "$quote";
455
                }
456
            }
457
            if($isUpdate){
458
                $query.= " WHERE id_c='" . $this->bean->id ."'";
459
460
            }
461
462
            $queryInsert .= " ) VALUES $values )";
463
464
            if(!$first){
465
                if(!$isUpdate){
466
                    $GLOBALS['db']->query($queryInsert);
467
                }else{
468
                    $checkquery = "SELECT id_c FROM {$this->bean->table_name}_cstm WHERE id_c = '{$this->bean->id}'";
469
                    if ( $GLOBALS['db']->getOne($checkquery) ) {
470
                        $result = $GLOBALS['db']->query($query);
471
                    } else {
472
                        $GLOBALS['db']->query($queryInsert);
473
                    }
474
                }
475
            }
476
        }
477
478 66
    }
479
    /**
480
     * Deletes the field from fields_meta_data and drops the database column then it rebuilds the cache
481
     * Use the widgets get_db_modify_alter_table() method to get the table sql - some widgets do not need any custom table modifications
482
     * @param STRING $name - field name
0 ignored issues
show
There is no parameter named $name. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
483
     */
484
    function deleteField($widget){
485
        require_once('modules/DynamicFields/templates/Fields/TemplateField.php');
486
        global $beanList;
487
        if (!($widget instanceof TemplateField)) {
488
            $field_name = $widget;
489
            $widget = new TemplateField();
490
            $widget->name = $field_name;
491
        }
492
        $object_name = $beanList[$this->module];
493
494
        //Some modules like cases have a bean name that doesn't match the object name
495
        if (empty($GLOBALS['dictionary'][$object_name])) {
496
            $newName = BeanFactory::getObjectName($this->module);
497
            $object_name = $newName != false ? $newName : $object_name;
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison !== instead.

When comparing two booleans, it is generally considered safer to use the strict comparison operator.

Loading history...
498
        }
499
500
        $GLOBALS['db']->query("DELETE FROM fields_meta_data WHERE id='" . $this->module . $widget->name . "'");
501
        $sql = $widget->get_db_delete_alter_table( $this->bean->table_name . "_cstm" ) ;
502
        if (! empty( $sql ) )
503
            $GLOBALS['db']->query( $sql );
504
505
        $this->removeVardefExtension($widget);
506
        VardefManager::clearVardef();
507
        VardefManager::refreshVardefs($this->module, $object_name);
508
509
    }
510
511
    /*
512
     * Method required by the TemplateRelatedTextField->save() method
513
     * Taken from MBModule's implementation
514
     */
515
    function fieldExists($name = '', $type = ''){
516
        // must get the vardefs from the GLOBAL array as $bean->field_defs does not contain the values from the cache at this point
517
        // TODO: fix this - saveToVardefs() updates GLOBAL['dictionary'] correctly, obtaining its information directly from the fields_meta_data table via buildCache()...
518
        $name = $this->getDBName($name);
519
        $vardefs = $GLOBALS['dictionary'][$this->bean->object_name]['fields'];
520
        if(!empty($vardefs)){
521
            if(empty($type) && empty($name))
522
                return false;
523
            else if(empty($type))
524
                return !empty($vardefs[$name]);
525
            else if(empty($name)){
526
                foreach($vardefs as $def){
527
                    if(!empty($def['type']) && $def['type'] == $type)
528
                        return true;
529
                }
530
                return false;
531
            }else
532
                return (!empty($vardefs[$name]) && ($vardefs[$name]['type'] == $type));
533
        }else{
534
            return false;
535
        }
536
    }
537
538
539
    /**
540
     * Adds a custom field using a field object
541
     *
542
     * @param Field Object $field
543
     * @return boolean
544
     */
545
    function addFieldObject(&$field){
546
        $GLOBALS['log']->debug('adding field');
547
        $object_name = $this->module;
548
        $db_name = $field->name;
549
550
        $fmd = new FieldsMetaData();
551
        $id =  $fmd->retrieve($object_name.$db_name,true, false);
552
        $is_update = false;
553
        $label = strtoupper( $field->label );
554
        if(!empty($id)){
555
            $is_update = true;
556
        }else{
557
            $db_name = $this->getDBName($field->name);
558
            $field->name = $db_name;
559
        }
560
        $this->createCustomTable();
561
        $fmd->id = $object_name.$db_name;
562
        $fmd->custom_module= $object_name;
563
        $fmd->name = $db_name;
564
        $fmd->vname = $label;
565
        $fmd->type = $field->type;
566
        $fmd->help = $field->help;
567
        if (!empty($field->len))
568
            $fmd->len = $field->len; // tyoung bug 15407 - was being set to $field->size so changes weren't being saved
569
        $fmd->required = ($field->required ? 1 : 0);
570
        $fmd->default_value = $field->default;
571
        $fmd->ext1 = $field->ext1;
572
        $fmd->ext2 = $field->ext2;
573
        $fmd->ext3 = $field->ext3;
574
        $fmd->ext4 = (isset($field->ext4) ? $field->ext4 : '');
575
        $fmd->comments = $field->comment;
576
        $fmd->massupdate = $field->massupdate;
577
        $fmd->importable = ( isset ( $field->importable ) ) ? $field->importable : null ;
578
        $fmd->duplicate_merge = $field->duplicate_merge;
579
        $fmd->audited =$field->audited;
580
        $fmd->inline_edit = $field->inline_edit;
581
        $fmd->reportable = ($field->reportable ? 1 : 0);
582
        if(!$is_update){
583
            $fmd->new_with_id=true;
584
        }
585
        if($field){
586
            if(!$is_update){
587
                //Do two SQL calls here in this case
588
            	//The first is to create the column in the custom table without the default value
589
            	//The second is to modify the column created in the custom table to set the default value
590
            	//We do this so that the existing entries in the custom table don't have the default value set
591
            	$field->default = '';
592
            	$field->default_value = '';
593
                // resetting default and default_value does not work for multienum and causes trouble for mssql
594
                // so using a temporary variable here to indicate that we don't want default for this query
595
                $field->no_default = 1;
596
                $query = $field->get_db_add_alter_table($this->bean->table_name . '_cstm');
597
                // unsetting temporary member variable
598
                unset($field->no_default);
599
                if(!empty($query)){
600
                	$GLOBALS['db']->query($query, true, "Cannot create column");
601
	                $field->default = $fmd->default_value;
602
	                $field->default_value = $fmd->default_value;
603
	                $query = $field->get_db_modify_alter_table($this->bean->table_name . '_cstm');
604
	                if(!empty($query)){
605
	                	$GLOBALS['db']->query($query, true, "Cannot set default");
606
	            	}
607
                }
608
            }else{
609
                $query = $field->get_db_modify_alter_table($this->bean->table_name . '_cstm');
610
                if(!empty($query)){
611
                	$GLOBALS['db']->query($query, true, "Cannot modify field");
612
            	}
613
            }
614
            $fmd->save();
615
            $this->buildCache($this->module);
616
            $this->saveExtendedAttributes($field, array_keys($fmd->field_defs));
617
        }
618
619
        return true;
620
    }
621
622
    function saveExtendedAttributes($field, $column_fields)
623
    {
624
            require_once ('modules/ModuleBuilder/parsers/StandardField.php') ;
625
            require_once ('modules/DynamicFields/FieldCases.php') ;
626
            global $beanList;
627
628
            $to_save = array();
629
            $base_field = get_widget ( $field->type) ;
630
        foreach ($field->vardef_map as $property => $fmd_col){
631
            //Skip over attribes that are either the default or part of the normal attributes stored in the DB
632
            if (!isset($field->$property) || in_array($fmd_col, $column_fields) || in_array($property, $column_fields)
633
                || $this->isDefaultValue($property, $field->$property, $base_field)
634
                || $property == "action" || $property == "label_value" || $property == "label"
635
                || (substr($property, 0,3) == 'ext' && strlen($property) == 4))
636
            {
637
                continue;
638
            }
639
            $to_save[$property] =
640
                is_string($field->$property) ? htmlspecialchars_decode($field->$property, ENT_QUOTES) : $field->$property;
0 ignored issues
show
The call to htmlspecialchars_decode() has too many arguments starting with ENT_QUOTES.

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...
641
        }
642
        $bean_name = $beanList[$this->module];
643
644
        $this->writeVardefExtension($bean_name, $field, $to_save);
645
    }
646
647
    protected function isDefaultValue($property, $value, $baseField)
648
    {
649
        switch ($property) {
650
            case "importable":
651
                return ( $value === 'true' || $value === '1' || $value === true || $value === 1 ); break;
0 ignored issues
show
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
652
            case "required":
653
            case "audited":
654
            case "inline_edit":
655
            case "massupdate":
656
                return ( $value === 'false' || $value === '0' || $value === false || $value === 0); break;
0 ignored issues
show
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
657
            case "default_value":
658
            case "default":
659
            case "help":
660
            case "comments":
661
                return ($value == "");
662
            case "duplicate_merge":
663
                return ( $value === 'false' || $value === '0' || $value === false || $value === 0 || $value === "disabled"); break;
0 ignored issues
show
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
664
        }
665
666
        if (isset($baseField->$property))
667
        {
668
            return $baseField->$property == $value;
669
        }
670
671
        return false;
672
    }
673
674
    protected function writeVardefExtension($bean_name, $field, $def_override)
675
    {
676
        //Hack for the broken cases module
677
        $vBean = $bean_name == "aCase" ? "Case" : $bean_name;
678
        $file_loc = "$this->base_path/sugarfield_{$field->name}.php";
679
680
        $out =  "<?php\n // created: " . date('Y-m-d H:i:s') . "\n";
681
        foreach ($def_override as $property => $val)
682
        {
683
            $out .= override_value_to_string_recursive(array($vBean, "fields", $field->name, $property), "dictionary", $val) . "\n";
684
        }
685
686
        $out .= "\n ?>";
687
688
        if (!file_exists($this->base_path))
689
            mkdir_recursive($this->base_path);
690
691
        if( $fh = @sugar_fopen( $file_loc, 'w' ) )
692
        {
693
            fputs( $fh, $out);
694
            fclose( $fh );
695
            return true ;
696
        }
697
        else
698
        {
699
            return false ;
700
        }
701
    }
702
703
    protected function removeVardefExtension($field)
704
    {
705
        $file_loc = "$this->base_path/sugarfield_{$field->name}.php";
706
707
        if (is_file($file_loc))
708
        {
709
            unlink($file_loc);
710
        }
711
    }
712
713
714
    /**
715
     * DEPRECIATED: Use addFieldObject instead.
716
     * Adds a Custom Field using parameters
717
     *
718
     * @param unknown_type $name
719
     * @param unknown_type $label
720
     * @param unknown_type $type
721
     * @param unknown_type $max_size
722
     * @param unknown_type $required_option
723
     * @param unknown_type $default_value
724
     * @param unknown_type $ext1
725
     * @param unknown_type $ext2
726
     * @param unknown_type $ext3
727
     * @param unknown_type $audited
728
     * @param unknown_type $inline_edit
729
     * @param unknown_type $mass_update
730
     * @param unknown_type $ext4
731
     * @param unknown_type $help
732
     * @param unknown_type $duplicate_merge
733
     * @param unknown_type $comment
734
     * @return boolean
735
     */
736
    function addField($name,$label='', $type='Text',$max_size='255',$required_option='optional', $default_value='', $ext1='', $ext2='', $ext3='',$audited=0, $inline_edit = 1, $mass_update = 0 , $ext4='', $help='',$duplicate_merge=0, $comment=''){
737
        require_once('modules/DynamicFields/templates/Fields/TemplateField.php');
738
        $field = new TemplateField();
739
        $field->label = $label;
0 ignored issues
show
Documentation Bug introduced by
It seems like $label can also be of type object<unknown_type>. However, the property $label is declared as type string. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
740
        if(empty($field->label)){
741
            $field->label = $name;
742
        }
743
        $field->name = $name;
744
        $field->type = $type;
0 ignored issues
show
Documentation Bug introduced by
It seems like $type can also be of type object<unknown_type>. However, the property $type is declared as type string. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
745
        $field->len = $max_size;
0 ignored issues
show
Documentation Bug introduced by
It seems like $max_size can also be of type object<unknown_type>. However, the property $len is declared as type string. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
746
        $field->required = (!empty($required_option) && $required_option != 'optional');
747
        $field->default = $default_value;
748
        $field->ext1 = $ext1;
0 ignored issues
show
Documentation Bug introduced by
It seems like $ext1 can also be of type object<unknown_type>. However, the property $ext1 is declared as type string. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
749
        $field->ext2 = $ext2;
0 ignored issues
show
Documentation Bug introduced by
It seems like $ext2 can also be of type object<unknown_type>. However, the property $ext2 is declared as type string. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
750
        $field->ext3 = $ext3;
0 ignored issues
show
Documentation Bug introduced by
It seems like $ext3 can also be of type object<unknown_type>. However, the property $ext3 is declared as type string. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
751
        $field->ext4 = $ext4;
0 ignored issues
show
Documentation Bug introduced by
It seems like $ext4 can also be of type object<unknown_type>. However, the property $ext4 is declared as type string. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
752
        $field->help = $help;
0 ignored issues
show
Documentation Bug introduced by
It seems like $help can also be of type object<unknown_type>. However, the property $help is declared as type string. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
753
        $field->comments = $comment;
754
        $field->massupdate = $mass_update;
755
        $field->duplicate_merge = $duplicate_merge;
756
        $field->audited = $audited;
757
        $field->inline_edit = $inline_edit;
758
        $field->reportable = 1;
0 ignored issues
show
Documentation Bug introduced by
The property $reportable was declared of type boolean, but 1 is of type integer. Maybe add a type cast?

This check looks for assignments to scalar types that may be of the wrong type.

To ensure the code behaves as expected, it may be a good idea to add an explicit type cast.

$answer = 42;

$correct = false;

$correct = (bool) $answer;
Loading history...
759
        return $this->addFieldObject($field);
760
    }
761
762
    /**
763
     * Creates the custom table with an id of id_c
764
     *
765
     */
766
    function createCustomTable($execute = true){
767
        $out = "";
768
        if (!$GLOBALS['db']->tableExists($this->bean->table_name."_cstm")) {
769
            $GLOBALS['log']->debug('creating custom table for '. $this->bean->table_name);
770
            $iddef = array(
771
                "id_c" => array(
772
                    "name" => "id_c",
773
                    "type" => "id",
774
                    "required" => 1,
775
                )
776
            );
777
            $ididx = array(
778
       			'id'=>array(
779
       				'name' =>$this->bean->table_name."_cstm_pk",
780
       				'type' =>'primary',
781
       				'fields'=>array('id_c')
782
                ),
783
           );
784
785
            $query = $GLOBALS['db']->createTableSQLParams($this->bean->table_name."_cstm", $iddef, $ididx);
786
            if(!$GLOBALS['db']->supports("inline_keys")) {
787
                $indicesArr = $GLOBALS['db']->getConstraintSql($ididx, $this->bean->table_name."_cstm");
788
            } else {
789
                $indicesArr = array();
790
            }
791
            if($execute) {
792
                $GLOBALS['db']->query($query);
793
                if(!empty($indicesArr)) {
794
                    foreach($indicesArr as $idxq) {
795
                        $GLOBALS['db']->query($idxq);
796
                    }
797
                }
798
            }
799
            $out = $query . "\n";
800
            if(!empty($indicesArr)) {
801
                $out .= join("\n", $indicesArr)."\n";
802
            }
803
804
            $out .= $this->add_existing_custom_fields($execute);
805
        }
806
807
        return $out;
808
    }
809
810
    /**
811
     * Updates the db schema and adds any custom fields we have used if the custom table was dropped
812
     *
813
     */
814
    function add_existing_custom_fields($execute = true){
815
    	$out = "";
816
        if($this->bean->hasCustomFields()){
817
	        foreach($this->bean->field_defs as $name=>$data){
818
	        	if(empty($data['source']) || $data['source'] != 'custom_fields')
819
                    continue;
820
	            $out .= $this->add_existing_custom_field($data, $execute);
821
	        }
822
    	}
823
        return $out;
824
    }
825
826
    function add_existing_custom_field($data, $execute = true)
827
    {
828
829
        $field = get_widget ( $data ['type'] );
830
        $field->populateFromRow($data);
831
        $query = "/*MISSING IN DATABASE - {$data['name']} -  ROW*/\n"
832
                . $field->get_db_add_alter_table($this->bean->table_name . '_cstm');
833
        $out = $query . "\n";
834
        if ($execute)
835
            $GLOBALS['db']->query($query);
836
837
        return $out;
838
    }
839
840
    public function repairCustomFields($execute = true)
841
    {
842
        $out = $this->createCustomTable($execute);
843
        //If the table didn't exist, createCustomTable will have returned all the SQL to create and populate it
844
        if (!empty($out))
845
            return "/*Checking Custom Fields for module : {$this->module} */\n$out";
846
        //Otherwise make sure all the custom fields defined in the vardefs exist in the custom table.
847
        //We aren't checking for data types, just that the column exists.
848
        $db = $GLOBALS['db'];
849
        $tablename = $this->bean->table_name."_cstm";
850
        $compareFieldDefs = $db->get_columns($tablename);
851
        foreach($this->bean->field_defs as $name=>$data){
852
            if(empty($data['source']) || $data['source'] != 'custom_fields')
853
                continue;
854
            /**
855
             * @bug 43471
856
             * @issue 43471
857
             * @itr 23441
858
             *
859
             * force the name to be lower as it needs to be lower since that is how it's put into the key
860
             * in the get_columns() call above.
861
             */
862
            if(!empty($compareFieldDefs[strtolower($name)])) {
863
                continue;
864
            }
865
            $out .= $this->add_existing_custom_field($data, $execute);
866
        }
867
        if (!empty($out))
868
            $out = "/*Checking Custom Fields for module : {$this->module} */\n$out";
869
870
        return $out;
871
    }
872
873
    /**
874
     * Adds a label to the module's mod_strings for the current language
875
     * Note that the system label name
876
     *
877
     * @param string $displayLabel The label value to be displayed
878
     * @return string The core of the system label name - returns currency_id5 for example, when the full label would then be LBL_CURRENCY_ID5
879
     * TODO: Only the core is returned for historical reasons - switch to return the real system label
880
     */
881
    function addLabel ( $displayLabel )
882
    {
883
        $mod_strings = return_module_language($GLOBALS[ 'current_language' ], $this->module);
884
        $limit = 10;
885
        $count = 0;
886
        $field_key = $this->getDBName($displayLabel, false);
887
        $systemLabel = $field_key;
888
        if(!$this->use_existing_labels){ // use_existing_labels defaults to false in this module; as of today, only set to true by ModuleInstaller.php
889
            while( isset( $mod_strings [ $systemLabel ] ) && $count <= $limit )
890
            {
891
                $systemLabel = $field_key. "_$count";
892
                $count++;
893
            }
894
        }
895
        $selMod = (!empty($_REQUEST['view_module'])) ? $_REQUEST['view_module'] : $this->module;
896
        require_once 'modules/ModuleBuilder/parsers/parser.label.php' ;
897
        $parser = new ParserLabel ( $selMod , isset ( $_REQUEST [ 'view_package' ] ) ? $_REQUEST [ 'view_package' ] : null ) ;
898
        $parser->handleSave ( array('label_'. $systemLabel => $displayLabel ) , $GLOBALS [ 'current_language' ] ) ;
899
900
        return $systemLabel;
901
    }
902
903
    /**
904
     * Returns a Database Safe Name
905
     *
906
     * @param STRING $name
907
     * @param BOOLEAN $_C do we append _c to the name
908
     * @return STRING
909
     */
910
    function getDBName($name, $_C= true){
911
        static $cached_results = array();
912
        if(!empty($cached_results[$name]))
913
        {
914
            return $cached_results[$name];
915
        }
916
        $exclusions = array('parent_type', 'parent_id', 'currency_id', 'parent_name');
917
        // Remove any non-db friendly characters
918
        $return_value = preg_replace("/[^\w]+/","_",$name);
919
        if($_C == true && !in_array($return_value, $exclusions) && substr($return_value, -2) != '_c'){
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

When comparing two booleans, it is generally considered safer to use the strict comparison operator.

Loading history...
920
            $return_value .= '_c';
921
        }
922
        $cached_results[$name] = $return_value;
923
        return $return_value;
924
    }
925
926
    function setWhereClauses(&$where_clauses){
927
        if (isset($this->avail_fields)) {
928
            foreach($this->avail_fields as $name=>$value){
929
                if(!empty($_REQUEST[$name])){
930
                    $where_clauses[] = $this->bean->table_name . "_cstm.$name LIKE '". $GLOBALS['db']->quote($_REQUEST[$name]). "%'";
931
                }
932
            }
933
        }
934
935
    }
936
937
    /////////////////////////BACKWARDS COMPATABILITY MODE FOR PRE 5.0 MODULES\\\\\\\\\\\\\\\\\\\\\\\\\\\
938
    ////////////////////////////END BACKWARDS COMPATABILITY MODE FOR PRE 5.0 MODULES\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
939
940
    /**
941
     *
942
     * DEPRECATED
943
     loads fields into the bean
944
     This used to be called during the retrieve process now it is done through a join
945
     Restored from pre-r30895 to maintain support for custom code that may have called retrieve() directly
946
     */
947
948 1
    function retrieve()
949
    {
950 1
        if(!isset($this->bean)){
951
            $GLOBALS['log']->fatal("DynamicField retrieve, bean not instantiated: ".var_export(debug_print_backtrace(), true));
952
            return false;
953
        }
954
955 1
        if(!$this->bean->hasCustomFields()){
956 1
            return false;
957
        }
958
959
        $query = "SELECT * FROM ".$this->bean->table_name."_cstm WHERE id_c='".$this->bean->id."'";
960
        $result = $GLOBALS['db']->query($query);
961
        $row = $GLOBALS['db']->fetchByAssoc($result);
962
963
        if($row)
964
        {
965
            foreach($row as $name=>$value)
966
            {
967
                // originally in pre-r30895 we checked if this field was in avail_fields i.e., in fields_meta_data and not deleted
968
                // with the removal of avail_fields post-r30895 we have simplified this - we now retrieve every custom field even if previously deleted
969
                // this is considered harmless as the value although set in the bean will not otherwise be used (nothing else works off the list of fields in the bean)
970
                $this->bean->$name = $value;
971
            }
972
        }
973
974
    }
975
976
   function populateXTPL($xtpl, $view) {
977
978
        if($this->bean->hasCustomFields()){
979
            $results = $this->getAllFieldsView($view, 'xtpl');
980
            foreach($results as $name=>$value){
981
                if(is_array($value['xtpl']))
982
                {
983
                    foreach($value['xtpl'] as $xName=>$xValue)
984
                    {
985
                        $xtpl->assign(strtoupper($xName), $xValue);
986
                    }
987
                } else {
988
                    $xtpl->assign(strtoupper($name), $value['xtpl']);
989
                }
990
            }
991
        }
992
993
    }
994
995
    function populateAllXTPL($xtpl, $view){
996
        $this->populateXTPL($xtpl, $view);
997
998
    }
999
1000
    function getAllFieldsView($view, $type){
1001
         require_once ('modules/DynamicFields/FieldCases.php');
1002
         $results = array();
1003
         foreach($this->bean->field_defs as $name=>$data){
1004
            if(empty($data['source']) || $data['source'] != 'custom_fields')
1005
            {
1006
            	continue;
1007
            }
1008
            $field = get_widget ( $data ['type'] );
1009
            $field->populateFromRow($data);
1010
            $field->view = $view;
1011
            $field->bean = $this->bean;
1012
            switch(strtolower($type))
1013
            {
1014
                case 'xtpl':
1015
                    $results[$name] = array('xtpl'=>$field->get_xtpl());
1016
                    break;
1017
                case 'html':
1018
                    $results[$name] = array('html'=> $field->get_html(), 'label'=> $field->get_html_label(), 'fieldType'=>$field->data_type, 'isCustom' =>true);
1019
                    break;
1020
            }
1021
1022
        }
1023
        return $results;
1024
    }
1025
1026
    ////////////////////////////END BACKWARDS COMPATABILITY MODE FOR PRE 5.0 MODULES\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
1027
}
1028
1029
?>
1030