Passed
Push — master ( 65bdac...4e88da )
by Alxarafe
32:38
created

Base/ExtraFields.php (2 issues)

1
<?php
2
/* Copyright (C) 2002-2003  Rodolphe Quiedeville    <[email protected]>
3
 * Copyright (C) 2002-2003  Jean-Louis Bergamo      <[email protected]>
4
 * Copyright (C) 2004       Sebastien Di Cintio     <[email protected]>
5
 * Copyright (C) 2004       Benoit Mortier          <[email protected]>
6
 * Copyright (C) 2009-2012  Laurent Destailleur     <[email protected]>
7
 * Copyright (C) 2009-2012  Regis Houssin           <[email protected]>
8
 * Copyright (C) 2013       Florian Henry           <[email protected]>
9
 * Copyright (C) 2015       Charles-Fr BENKE        <[email protected]>
10
 * Copyright (C) 2016       Raphaël Doursenaud      <[email protected]>
11
 * Copyright (C) 2017       Nicolas ZABOURI         <[email protected]>
12
 * Copyright (C) 2018       Frédéric France         <[email protected]>
13
 *
14
 * This program is free software; you can redistribute it and/or modify
15
 * it under the terms of the GNU General Public License as published by
16
 * the Free Software Foundation; either version 3 of the License, or
17
 * (at your option) any later version.
18
 *
19
 * This program is distributed in the hope that it will be useful,
20
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22
 * GNU General Public License for more details.
23
 *
24
 * You should have received a copy of the GNU General Public License
25
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
26
 */
27
28
/**
29
 * 	\file 		htdocs/core/class/extrafields.class.php
30
 * 	\ingroup    core
31
 * 	\brief      File of class to manage extra fields
32
 */
33
namespace Alixar\Base;
34
35
use Alxarafe\Helpers\Config;
36
use Alixar\Helpers\DolUtils;
37
use Alixar\Helpers\Globals;
38
39
/**
40
 * 	Class to manage standard extra fields
41
 */
42
class ExtraFields
43
{
44
45
    /**
46
     * @var DoliDB Database handler.
47
     */
48
    // public $db;
49
    // type of element (for what object is the extrafield)
50
    // @deprecated
51
    var $attribute_elementtype;
52
    // Array with type of the extra field
53
    // @deprecated
54
    var $attribute_type;
55
    // Array with label of extra field
56
    // @deprecated
57
    var $attribute_label;
58
    // Array with size of extra field
59
    // @deprecated
60
    var $attribute_size;
61
    // array with list of possible values for some types of extra fields
62
    // @deprecated
63
    var $attribute_choice;
64
    // Array to store compute formula for computed fields
65
    // @deprecated
66
    var $attribute_computed;
67
    // Array to store default value
68
    // @deprecated
69
    var $attribute_default;
70
    // Array to store if attribute is unique or not
71
    // @deprecated
72
    var $attribute_unique;
73
    // Array to store if attribute is required or not
74
    // @deprecated
75
    var $attribute_required;
76
    // Array to store parameters of attribute (used in select type)
77
    // @deprecated
78
    var $attribute_param;
79
    // Array to store position of attribute
80
    // @deprecated
81
    var $attribute_pos;
82
    // Array to store if attribute is editable regardless of the document status
83
    // @deprecated
84
    var $attribute_alwayseditable;
85
    // Array to store permission to check
86
    // @deprecated
87
    var $attribute_perms;
88
    // Array to store language file to translate label of values
89
    // @deprecated
90
    var $attribute_langfile;
91
    // Array to store if field is visible by default on list
92
    // @deprecated
93
    var $attribute_list;
94
    // New array to store extrafields definition
95
    var $attributes;
96
97
    /**
98
     * @var string Error code (or message)
99
     */
100
    public $error = '';
101
    var $errno;
102
    public static $type2label = array(
103
        'varchar' => 'String',
104
        'text' => 'TextLong',
105
        'html' => 'HtmlText',
106
        'int' => 'Int',
107
        'double' => 'Float',
108
        'date' => 'Date',
109
        'datetime' => 'DateAndTime',
110
        'boolean' => 'Boolean',
111
        'price' => 'ExtrafieldPrice',
112
        'phone' => 'ExtrafieldPhone',
113
        'mail' => 'ExtrafieldMail',
114
        'url' => 'ExtrafieldUrl',
115
        'password' => 'ExtrafieldPassword',
116
        'select' => 'ExtrafieldSelect',
117
        'sellist' => 'ExtrafieldSelectList',
118
        'radio' => 'ExtrafieldRadio',
119
        'checkbox' => 'ExtrafieldCheckBox',
120
        'chkbxlst' => 'ExtrafieldCheckBoxFromList',
121
        'link' => 'ExtrafieldLink',
122
        'separate' => 'ExtrafieldSeparator',
123
    );
124
125
    /**
126
     * 	Constructor
127
     *
128
     *  @param		DoliDB		$db      Database handler
129
     */
130
    function __construct()
131
    {
132
        // Config::$dbEngine = $db;
133
        $this->error = array();
0 ignored issues
show
Documentation Bug introduced by
It seems like array() of type array is incompatible with the declared type string of property $error.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
134
        $this->attributes = array();
135
136
        // For old usage
137
        $this->attribute_elementtype = array();
0 ignored issues
show
Documentation Bug introduced by
It seems like array() of type array is incompatible with the declared type Alixar\Base\DoliDB of property $attribute_elementtype.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
138
        $this->attribute_type = array();
139
        $this->attribute_label = array();
140
        $this->attribute_size = array();
141
        $this->attribute_computed = array();
142
        $this->attribute_default = array();
143
        $this->attribute_unique = array();
144
        $this->attribute_required = array();
145
        $this->attribute_perms = array();
146
        $this->attribute_langfile = array();
147
        $this->attribute_list = array();
148
    }
149
150
    /**
151
     *  Add a new extra field parameter
152
     *
153
     *  @param	string			$attrname           Code of attribute
154
     *  @param  string			$label              label of attribute
155
     *  @param  int				$type               Type of attribute ('boolean','int','varchar','text','html','date','datehour','price','phone','mail','password','url','select','checkbox','separate',...)
156
     *  @param  int				$pos                Position of attribute
157
     *  @param  string			$size               Size/length of attribute
158
     *  @param  string			$elementtype        Element type. Same value than object->table_element (Example 'member', 'product', 'thirdparty', ...)
159
     *  @param	int				$unique				Is field unique or not
160
     *  @param	int				$required			Is field required or not
161
     *  @param	string			$default_value		Defaulted value (In database. use the default_value feature for default value on screen. Example: '', '0', 'null', 'avalue')
162
     *  @param  array|string	$param				Params for field (ex for select list : array('options' => array(value'=>'label of option')) )
163
     *  @param  int				$alwayseditable		Is attribute always editable regardless of the document status
164
     *  @param	string			$perms				Permission to check
165
     *  @param	string			$list				Visibilty ('0'=never visible, '1'=visible on list+forms, '2'=list only, '3'=form only or 'eval string')
166
     *  @param	string			$help				Text with help tooltip
167
     *  @param  string  		$computed           Computed value
168
     *  @param  string  		$entity    		 	Entity of extrafields (for multicompany modules)
169
     *  @param  string  		$langfile  		 	Language file
170
     *  @param  string  		$enabled  		 	Condition to have the field enabled or not
171
     *  @return int      							<=0 if KO, >0 if OK
172
     */
173
    function addExtraField($attrname, $label, $type, $pos, $size, $elementtype, $unique = 0, $required = 0, $default_value = '', $param = '', $alwayseditable = 0, $perms = '', $list = '-1', $help = '', $computed = '', $entity = '', $langfile = '', $enabled = '1')
174
    {
175
        if (empty($attrname))
176
            return -1;
177
        if (empty($label))
178
            return -1;
179
180
        if ($elementtype == 'thirdparty')
181
            $elementtype = 'societe';
182
        if ($elementtype == 'contact')
183
            $elementtype = 'socpeople';
184
185
        // Create field into database except for separator type which is not stored in database
186
        if ($type != 'separate') {
187
            $result = $this->create($attrname, $type, $size, $elementtype, $unique, $required, $default_value, $param, $perms, $list, $computed, $help);
188
        }
189
        $err1 = $this->errno;
190
        if ($result > 0 || $err1 == 'DB_ERROR_COLUMN_ALREADY_EXISTS' || $type == 'separate') {
191
            // Add declaration of field into table
192
            $result2 = $this->create_label($attrname, $label, $type, $pos, $size, $elementtype, $unique, $required, $param, $alwayseditable, $perms, $list, $help, $default_value, $computed, $entity, $langfile, $enabled);
193
            $err2 = $this->errno;
194
            if ($result2 > 0 || ($err1 == 'DB_ERROR_COLUMN_ALREADY_EXISTS' && $err2 == 'DB_ERROR_RECORD_ALREADY_EXISTS')) {
195
                $this->error = '';
196
                $this->errno = 0;
197
                return 1;
198
            } else
199
                return -2;
200
        }
201
        else {
202
            return -1;
203
        }
204
    }
205
206
    /**
207
     * 	Add a new optional attribute.
208
     *  This is a private method. For public method, use addExtraField.
209
     *
210
     * 	@param	string	$attrname			code of attribute
211
     *  @param	int		$type				Type of attribute ('boolean', 'int', 'varchar', 'text', 'html', 'date', 'datehour','price','phone','mail','password','url','select','checkbox', ...)
212
     *  @param	string	$length				Size/length of attribute ('5', '24,8', ...)
213
     *  @param  string	$elementtype        Element type ('member', 'product', 'thirdparty', 'contact', ...)
214
     *  @param	int		$unique				Is field unique or not
215
     *  @param	int		$required			Is field required or not
216
     *  @param  string  $default_value		Default value for field (in database)
217
     *  @param  array	$param				Params for field  (ex for select list : array('options'=>array('value'=>'label of option'))
218
     *  @param	string	$perms				Permission
219
     * 	@param	string	$list				Into list view by default
220
     *  @param  string  $computed           Computed value
221
     *  @return int      	           		<=0 if KO, >0 if OK
222
     */
223
    private function create($attrname, $type = 'varchar', $length = 255, $elementtype = 'member', $unique = 0, $required = 0, $default_value = '', $param = '', $perms = '', $list = '0', $computed = '')
224
    {
225
        if ($elementtype == 'thirdparty')
226
            $elementtype = 'societe';
227
        if ($elementtype == 'contact')
228
            $elementtype = 'socpeople';
229
230
        $table = $elementtype . '_extrafields';
231
        if ($elementtype == 'categorie')
232
            $table = 'categories_extrafields';
233
234
        if (!empty($attrname) && preg_match("/^\w[a-zA-Z0-9_]*$/", $attrname) && !is_numeric($attrname)) {
235
            if ($type == 'boolean') {
236
                $typedb = 'int';
237
                $lengthdb = '1';
238
            } elseif ($type == 'price') {
239
                $typedb = 'double';
240
                $lengthdb = '24,8';
241
            } elseif ($type == 'phone') {
242
                $typedb = 'varchar';
243
                $lengthdb = '20';
244
            } elseif ($type == 'mail') {
245
                $typedb = 'varchar';
246
                $lengthdb = '128';
247
            } elseif ($type == 'url') {
248
                $typedb = 'varchar';
249
                $lengthdb = '255';
250
            } elseif (($type == 'select') || ($type == 'sellist') || ($type == 'radio') || ($type == 'checkbox') || ($type == 'chkbxlst')) {
251
                $typedb = 'varchar';
252
                $lengthdb = '255';
253
            } elseif ($type == 'link') {
254
                $typedb = 'int';
255
                $lengthdb = '11';
256
            } elseif ($type == 'html') {
257
                $typedb = 'text';
258
                $lengthdb = $length;
259
            } elseif ($type == 'password') {
260
                $typedb = 'varchar';
261
                $lengthdb = '128';
262
            } else {
263
                $typedb = $type;
264
                $lengthdb = $length;
265
                if ($type == 'varchar' && empty($lengthdb))
266
                    $lengthdb = '255';
267
            }
268
            $field_desc = array(
269
                'type' => $typedb,
270
                'value' => $lengthdb,
271
                'null' => ($required ? 'NOT NULL' : 'NULL'),
272
                'default' => $default_value
273
            );
274
275
            $result = Config::$dbEngine->DDLAddField(MAIN_DB_PREFIX . $table, $attrname, $field_desc);
276
            if ($result > 0) {
277
                if ($unique) {
278
                    $sql = "ALTER TABLE " . MAIN_DB_PREFIX . $table . " ADD UNIQUE INDEX uk_" . $table . "_" . $attrname . " (" . $attrname . ")";
279
                    $resql = Config::$dbEngine->query($sql, 1, 'dml');
280
                }
281
                return 1;
282
            } else {
283
                $this->error = Config::$dbEngine->lasterror();
284
                $this->errno = Config::$dbEngine->lasterrno();
285
                return -1;
286
            }
287
        } else {
288
            return 0;
289
        }
290
    }
291
292
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
293
    /**
294
     * 	Add description of a new optional attribute
295
     *
296
     * 	@param	string			$attrname		code of attribute
297
     * 	@param	string			$label			label of attribute
298
     *  @param	int				$type			Type of attribute ('int', 'varchar', 'text', 'html', 'date', 'datehour', 'float')
299
     *  @param	int				$pos			Position of attribute
300
     *  @param	string			$size			Size/length of attribute ('5', '24,8', ...)
301
     *  @param  string			$elementtype	Element type ('member', 'product', 'thirdparty', ...)
302
     *  @param	int				$unique			Is field unique or not
303
     *  @param	int				$required		Is field required or not
304
     *  @param  array|string	$param			Params for field  (ex for select list : array('options' => array(value'=>'label of option')) )
305
     *  @param  int				$alwayseditable	Is attribute always editable regardless of the document status
306
     *  @param	string			$perms			Permission to check
307
     *  @param	string			$list			Visibily
308
     *  @param	string			$help			Help on tooltip
309
     *  @param  string          $default        Default value (in database. use the default_value feature for default value on screen).
310
     *  @param  string          $computed       Computed value
311
     *  @param  string          $entity     	Entity of extrafields
312
     *  @param	string			$langfile		Language file
313
     *  @param  string  		$enabled  		Condition to have the field enabled or not
314
     *  @return	int								<=0 if KO, >0 if OK
315
     */
316
    private function create_label($attrname, $label = '', $type = '', $pos = 0, $size = 0, $elementtype = 'member', $unique = 0, $required = 0, $param = '', $alwayseditable = 0, $perms = '', $list = '-1', $help = '', $default = '', $computed = '', $entity = '', $langfile = '', $enabled = '1')
317
    {
318
        // phpcs:enable
319
        // global $conf, $user;
320
321
        if ($elementtype == 'thirdparty')
322
            $elementtype = 'societe';
323
        if ($elementtype == 'contact')
324
            $elementtype = 'socpeople';
325
326
        // Clean parameters
327
        if (empty($pos))
328
            $pos = 0;
329
        if (empty($list))
330
            $list = '0';
331
        if (empty($required))
332
            $required = 0;
333
        if (empty($unique))
334
            $unique = 0;
335
        if (empty($alwayseditable))
336
            $alwayseditable = 0;
337
338
        if (!empty($attrname) && preg_match("/^\w[a-zA-Z0-9-_]*$/", $attrname) && !is_numeric($attrname)) {
339
            if (is_array($param) && count($param) > 0) {
340
                $params = serialize($param);
341
            } elseif (strlen($param) > 0) {
342
                $params = trim($param);
343
            } else {
344
                $params = '';
345
            }
346
347
            $sql = "INSERT INTO " . MAIN_DB_PREFIX . "extrafields(";
348
            $sql .= " name,";
349
            $sql .= " label,";
350
            $sql .= " type,";
351
            $sql .= " pos,";
352
            $sql .= " size,";
353
            $sql .= " entity,";
354
            $sql .= " elementtype,";
355
            $sql .= " fieldunique,";
356
            $sql .= " fieldrequired,";
357
            $sql .= " param,";
358
            $sql .= " alwayseditable,";
359
            $sql .= " perms,";
360
            $sql .= " langs,";
361
            $sql .= " list,";
362
            $sql .= " fielddefault,";
363
            $sql .= " fieldcomputed,";
364
            $sql .= " fk_user_author,";
365
            $sql .= " fk_user_modif,";
366
            $sql .= " datec,";
367
            $sql .= " enabled,";
368
            $sql .= " help";
369
            $sql .= " )";
370
            $sql .= " VALUES('" . $attrname . "',";
371
            $sql .= " '" . Config::$dbEngine->escape($label) . "',";
372
            $sql .= " '" . Config::$dbEngine->escape($type) . "',";
373
            $sql .= " " . $pos . ",";
374
            $sql .= " '" . Config::$dbEngine->escape($size) . "',";
375
            $sql .= " " . ($entity === '' ? Globals::$conf->entity : $entity) . ",";
376
            $sql .= " '" . Config::$dbEngine->escape($elementtype) . "',";
377
            $sql .= " " . $unique . ",";
378
            $sql .= " " . $required . ",";
379
            $sql .= " '" . Config::$dbEngine->escape($params) . "',";
380
            $sql .= " " . $alwayseditable . ",";
381
            $sql .= " " . ($perms ? "'" . Config::$dbEngine->escape($perms) . "'" : "null") . ",";
382
            $sql .= " " . ($langfile ? "'" . Config::$dbEngine->escape($langfile) . "'" : "null") . ",";
383
            $sql .= " '" . Config::$dbEngine->escape($list) . "',";
384
            $sql .= " " . ($default ? "'" . Config::$dbEngine->escape($default) . "'" : "null") . ",";
385
            $sql .= " " . ($computed ? "'" . Config::$dbEngine->escape($computed) . "'" : "null") . ",";
386
            $sql .= " " . (is_object(Globals::$user) ? Globals::$user->id : 0) . ",";
387
            $sql .= " " . (is_object(Globals::$user) ? Globals::$user->id : 0) . ",";
388
            $sql .= "'" . Config::$dbEngine->idate(dol_now()) . "',";
389
            $sql .= " " . ($enabled ? "'" . Config::$dbEngine->escape($enabled) . "'" : "1") . ",";
390
            $sql .= " " . ($help ? "'" . Config::$dbEngine->escape($help) . "'" : "null");
391
            $sql .= ')';
392
393
            DolUtils::dol_syslog(get_class($this) . "::create_label", LOG_DEBUG);
394
            if (Config::$dbEngine->query($sql)) {
395
                return 1;
396
            } else {
397
                $this->error = Config::$dbEngine->lasterror();
398
                $this->errno = Config::$dbEngine->lasterrno();
399
                return -1;
400
            }
401
        }
402
    }
403
404
    /**
405
     * 	Delete an optional attribute
406
     *
407
     * 	@param	string	$attrname		Code of attribute to delete
408
     *  @param  string	$elementtype    Element type ('member', 'product', 'thirdparty', 'contact', ...)
409
     *  @return int              		< 0 if KO, 0 if nothing is done, 1 if OK
410
     */
411
    function delete($attrname, $elementtype = 'member')
412
    {
413
        if ($elementtype == 'thirdparty')
414
            $elementtype = 'societe';
415
        if ($elementtype == 'contact')
416
            $elementtype = 'socpeople';
417
418
        $table = $elementtype . '_extrafields';
419
        if ($elementtype == 'categorie')
420
            $table = 'categories_extrafields';
421
422
        $error = 0;
423
424
        if (!empty($attrname) && preg_match("/^\w[a-zA-Z0-9-_]*$/", $attrname)) {
425
            $result = $this->delete_label($attrname, $elementtype);
426
            if ($result < 0) {
427
                $this->error = Config::$dbEngine->lasterror();
428
                $error++;
429
            }
430
431
            if (!$error) {
432
                $sql = "SELECT COUNT(rowid) as nb";
433
                $sql .= " FROM " . MAIN_DB_PREFIX . "extrafields";
434
                $sql .= " WHERE elementtype = '" . $elementtype . "'";
435
                $sql .= " AND name = '" . $attrname . "'";
436
                //$sql.= " AND entity IN (0,".Globals::$conf->entity.")";      Do not test on entity here. We want to see if there is still on field remaning in other entities before deleting field in table
437
                $resql = Config::$dbEngine->query($sql);
438
                if ($resql) {
439
                    $obj = Config::$dbEngine->fetch_object($resql);
440
                    if ($obj->nb <= 0) {
441
                        $result = Config::$dbEngine->DDLDropField(MAIN_DB_PREFIX . $table, $attrname); // This also drop the unique key
442
                        if ($result < 0) {
443
                            $this->error = Config::$dbEngine->lasterror();
444
                            $error++;
445
                        }
446
                    }
447
                }
448
            }
449
450
            return $result;
451
        } else {
452
            return 0;
453
        }
454
    }
455
456
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
457
    /**
458
     * 	Delete description of an optional attribute
459
     *
460
     * 	@param	string	$attrname			Code of attribute to delete
461
     *  @param  string	$elementtype        Element type ('member', 'product', 'thirdparty', ...)
462
     *  @return int              			< 0 if KO, 0 if nothing is done, 1 if OK
463
     */
464
    private function delete_label($attrname, $elementtype = 'member')
465
    {
466
        // phpcs:enable
467
        // global $conf;
468
469
        if ($elementtype == 'thirdparty')
470
            $elementtype = 'societe';
471
        if ($elementtype == 'contact')
472
            $elementtype = 'socpeople';
473
474
        if (isset($attrname) && $attrname != '' && preg_match("/^\w[a-zA-Z0-9-_]*$/", $attrname)) {
475
            $sql = "DELETE FROM " . MAIN_DB_PREFIX . "extrafields";
476
            $sql .= " WHERE name = '" . $attrname . "'";
477
            $sql .= " AND entity IN  (0," . Globals::$conf->entity . ')';
478
            $sql .= " AND elementtype = '" . $elementtype . "'";
479
480
            DolUtils::dol_syslog(get_class($this) . "::delete_label", LOG_DEBUG);
481
            $resql = Config::$dbEngine->query($sql);
482
            if ($resql) {
483
                return 1;
484
            } else {
485
                print dol_print_error(Config::$dbEngine);
486
                return -1;
487
            }
488
        } else {
489
            return 0;
490
        }
491
    }
492
493
    /**
494
     * 	Modify type of a personalized attribute
495
     *
496
     *  @param	string	$attrname			Name of attribute
497
     *  @param	string	$label				Label of attribute
498
     *  @param	string	$type				Type of attribute ('boolean', 'int', 'varchar', 'text', 'html', 'date', 'datehour','price','phone','mail','password','url','select','checkbox', ...)
499
     *  @param	int		$length				Length of attribute
500
     *  @param  string	$elementtype        Element type ('member', 'product', 'thirdparty', 'contact', ...)
501
     *  @param	int		$unique				Is field unique or not
502
     *  @param	int		$required			Is field required or not
503
     *  @param	int		$pos				Position of attribute
504
     *  @param  array	$param				Params for field (ex for select list : array('options' => array(value'=>'label of option')) )
505
     *  @param  int		$alwayseditable		Is attribute always editable regardless of the document status
506
     *  @param	string	$perms				Permission to check
507
     *  @param	string	$list				Visibility
508
     *  @param	string	$help				Help on tooltip
509
     *  @param  string  $default            Default value (in database. use the default_value feature for default value on screen).
510
     *  @param  string  $computed           Computed value
511
     *  @param  string  $entity	            Entity of extrafields
512
     *  @param	string	$langfile			Language file
513
     *  @param  string  $enabled  			Condition to have the field enabled or not
514
     *  @param  int     $totalizable        Is extrafield totalizable on list
515
     * 	@return	int							>0 if OK, <=0 if KO
516
     */
517
    function update($attrname, $label, $type, $length, $elementtype, $unique = 0, $required = 0, $pos = 0, $param = '', $alwayseditable = 0, $perms = '', $list = '', $help = '', $default = '', $computed = '', $entity = '', $langfile = '', $enabled = '1', $totalizable = 0)
518
    {
519
        if ($elementtype == 'thirdparty')
520
            $elementtype = 'societe';
521
        if ($elementtype == 'contact')
522
            $elementtype = 'socpeople';
523
524
        $table = $elementtype . '_extrafields';
525
        if ($elementtype == 'categorie')
526
            $table = 'categories_extrafields';
527
528
        if (isset($attrname) && $attrname != '' && preg_match("/^\w[a-zA-Z0-9-_]*$/", $attrname)) {
529
            if ($type == 'boolean') {
530
                $typedb = 'int';
531
                $lengthdb = '1';
532
            } elseif ($type == 'price') {
533
                $typedb = 'double';
534
                $lengthdb = '24,8';
535
            } elseif ($type == 'phone') {
536
                $typedb = 'varchar';
537
                $lengthdb = '20';
538
            } elseif ($type == 'mail') {
539
                $typedb = 'varchar';
540
                $lengthdb = '128';
541
            } elseif ($type == 'url') {
542
                $typedb = 'varchar';
543
                $lengthdb = '255';
544
            } elseif (($type == 'select') || ($type == 'sellist') || ($type == 'radio') || ($type == 'checkbox') || ($type == 'chkbxlst')) {
545
                $typedb = 'varchar';
546
                $lengthdb = '255';
547
            } elseif ($type == 'html') {
548
                $typedb = 'text';
549
            } elseif ($type == 'link') {
550
                $typedb = 'int';
551
                $lengthdb = '11';
552
            } elseif ($type == 'password') {
553
                $typedb = 'varchar';
554
                $lengthdb = '50';
555
            } else {
556
                $typedb = $type;
557
                $lengthdb = $length;
558
            }
559
            $field_desc = array('type' => $typedb, 'value' => $lengthdb, 'null' => ($required ? 'NOT NULL' : 'NULL'), 'default' => $default);
560
561
            if ($type != 'separate') { // No table update when separate type
562
                $result = Config::$dbEngine->DDLUpdateField(MAIN_DB_PREFIX . $table, $attrname, $field_desc);
563
            }
564
            if ($result > 0 || $type == 'separate') {
565
                if ($label) {
566
                    $result = $this->update_label($attrname, $label, $type, $length, $elementtype, $unique, $required, $pos, $param, $alwayseditable, $perms, $list, $help, $default, $computed, $entity, $langfile, $enabled, $totalizable);
567
                }
568
                if ($result > 0) {
569
                    $sql = '';
570
                    if ($unique) {
571
                        $sql = "ALTER TABLE " . MAIN_DB_PREFIX . $table . " ADD UNIQUE INDEX uk_" . $table . "_" . $attrname . " (" . $attrname . ")";
572
                    } else {
573
                        $sql = "ALTER TABLE " . MAIN_DB_PREFIX . $table . " DROP INDEX uk_" . $table . "_" . $attrname;
574
                    }
575
                    DolUtils::dol_syslog(get_class($this) . '::update', LOG_DEBUG);
576
                    $resql = Config::$dbEngine->query($sql, 1, 'dml');
577
                    return 1;
578
                } else {
579
                    $this->error = Config::$dbEngine->lasterror();
580
                    return -1;
581
                }
582
            } else {
583
                $this->error = Config::$dbEngine->lasterror();
584
                return -1;
585
            }
586
        } else {
587
            return 0;
588
        }
589
    }
590
591
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
592
    /**
593
     *  Modify description of personalized attribute
594
     *
595
     *  @param	string	$attrname			Name of attribute
596
     *  @param	string	$label				Label of attribute
597
     *  @param  string	$type               Type of attribute
598
     *  @param  int		$size		        Length of attribute
599
     *  @param  string	$elementtype		Element type ('member', 'product', 'thirdparty', ...)
600
     *  @param	int		$unique				Is field unique or not
601
     *  @param	int		$required			Is field required or not
602
     *  @param	int		$pos				Position of attribute
603
     *  @param  array	$param				Params for field  (ex for select list : array('options' => array(value'=>'label of option')) )
604
     *  @param  int		$alwayseditable		Is attribute always editable regardless of the document status
605
     *  @param	string	$perms				Permission to check
606
     *  @param	string	$list				Visiblity
607
     *  @param	string	$help				Help on tooltip.
608
     *  @param  string  $default            Default value (in database. use the default_value feature for default value on screen).
609
     *  @param  string  $computed           Computed value
610
     *  @param  string  $entity     		Entity of extrafields
611
     *  @param	string	$langfile			Language file
612
     *  @param  string  $enabled  			Condition to have the field enabled or not
613
     *  @param  int     $totalizable        Is extrafield totalizable on list
614
     *  @return	int							<=0 if KO, >0 if OK
615
     */
616
    private function update_label($attrname, $label, $type, $size, $elementtype, $unique = 0, $required = 0, $pos = 0, $param = '', $alwayseditable = 0, $perms = '', $list = '0', $help = '', $default = '', $computed = '', $entity = '', $langfile = '', $enabled = '1', $totalizable = 0)
617
    {
618
        // phpcs:enable
619
        // global $conf, $user;
620
        DolUtils::dol_syslog(get_class($this) . "::update_label " . $attrname . ", " . $label . ", " . $type . ", " . $size . ", " . $elementtype . ", " . $unique . ", " . $required . ", " . $pos . ", " . $alwayseditable . ", " . $perms . ", " . $list . ", " . $default . ", " . $computed . ", " . $entity . ", " . $langfile . ", " . $enabled . ", " . $totalizable);
621
622
        // Clean parameters
623
        if ($elementtype == 'thirdparty')
624
            $elementtype = 'societe';
625
        if ($elementtype == 'contact')
626
            $elementtype = 'socpeople';
627
628
        if (empty($pos))
629
            $pos = 0;
630
        if (empty($list))
631
            $list = '0';
632
        if (empty($totalizable)) {
633
            $totalizable = 0;
634
        }
635
        if (empty($required))
636
            $required = 0;
637
        if (empty($unique))
638
            $unique = 0;
639
        if (empty($alwayseditable))
640
            $alwayseditable = 0;
641
642
        if (isset($attrname) && $attrname != '' && preg_match("/^\w[a-zA-Z0-9-_]*$/", $attrname)) {
643
            Config::$dbEngine->begin();
644
645
            if (is_array($param) && count($param) > 0) {
646
                $params = serialize($param);
647
            } elseif (strlen($param) > 0) {
648
                $params = trim($param);
649
            } else {
650
                $params = '';
651
            }
652
653
            if ($entity === '' || $entity != '0') {
654
                // We dont want on all entities, we delete all and current
655
                $sql_del = "DELETE FROM " . MAIN_DB_PREFIX . "extrafields";
656
                $sql_del .= " WHERE name = '" . $attrname . "'";
657
                $sql_del .= " AND entity IN (0, " . ($entity === '' ? Globals::$conf->entity : $entity) . ")";
658
                $sql_del .= " AND elementtype = '" . $elementtype . "'";
659
            } else {
660
                // We want on all entities ($entities = '0'), we delete on all only (we keep setup specific to each entity)
661
                $sql_del = "DELETE FROM " . MAIN_DB_PREFIX . "extrafields";
662
                $sql_del .= " WHERE name = '" . $attrname . "'";
663
                $sql_del .= " AND entity = 0";
664
                $sql_del .= " AND elementtype = '" . $elementtype . "'";
665
            }
666
            $resql1 = Config::$dbEngine->query($sql_del);
667
668
            $sql = "INSERT INTO " . MAIN_DB_PREFIX . "extrafields(";
669
            $sql .= " name,";  // This is code
670
            $sql .= " entity,";
671
            $sql .= " label,";
672
            $sql .= " type,";
673
            $sql .= " size,";
674
            $sql .= " elementtype,";
675
            $sql .= " fieldunique,";
676
            $sql .= " fieldrequired,";
677
            $sql .= " perms,";
678
            $sql .= " langs,";
679
            $sql .= " pos,";
680
            $sql .= " alwayseditable,";
681
            $sql .= " param,";
682
            $sql .= " list,";
683
            $sql .= " totalizable,";
684
            $sql .= " fielddefault,";
685
            $sql .= " fieldcomputed,";
686
            $sql .= " fk_user_author,";
687
            $sql .= " fk_user_modif,";
688
            $sql .= " datec,";
689
            $sql .= " enabled,";
690
            $sql .= " help";
691
            $sql .= ") VALUES (";
692
            $sql .= "'" . $attrname . "',";
693
            $sql .= " " . ($entity === '' ? Globals::$conf->entity : $entity) . ",";
694
            $sql .= " '" . Config::$dbEngine->escape($label) . "',";
695
            $sql .= " '" . Config::$dbEngine->escape($type) . "',";
696
            $sql .= " '" . Config::$dbEngine->escape($size) . "',";
697
            $sql .= " '" . Config::$dbEngine->escape($elementtype) . "',";
698
            $sql .= " " . $unique . ",";
699
            $sql .= " " . $required . ",";
700
            $sql .= " " . ($perms ? "'" . Config::$dbEngine->escape($perms) . "'" : "null") . ",";
701
            $sql .= " " . ($langfile ? "'" . Config::$dbEngine->escape($langfile) . "'" : "null") . ",";
702
            $sql .= " " . $pos . ",";
703
            $sql .= " '" . Config::$dbEngine->escape($alwayseditable) . "',";
704
            $sql .= " '" . Config::$dbEngine->escape($params) . "',";
705
            $sql .= " '" . Config::$dbEngine->escape($list) . "', ";
706
            $sql .= " " . $totalizable . ",";
707
            $sql .= " " . (($default != '') ? "'" . Config::$dbEngine->escape($default) . "'" : "null") . ",";
708
            $sql .= " " . ($computed ? "'" . Config::$dbEngine->escape($computed) . "'" : "null") . ",";
709
            $sql .= " " . Globals::$user->id . ",";
710
            $sql .= " " . Globals::$user->id . ",";
711
            $sql .= "'" . Config::$dbEngine->idate(dol_now()) . "',";
712
            $sql .= "'" . Config::$dbEngine->escape($enabled) . "',";
713
            $sql .= " " . ($help ? "'" . Config::$dbEngine->escape($help) . "'" : "null");
714
            $sql .= ")";
715
716
            $resql2 = Config::$dbEngine->query($sql);
717
718
            if ($resql1 && $resql2) {
719
                Config::$dbEngine->commit();
720
                return 1;
721
            } else {
722
                Config::$dbEngine->rollback();
723
                print dol_print_error(Config::$dbEngine);
724
                return -1;
725
            }
726
        } else {
727
            return 0;
728
        }
729
    }
730
731
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
732
    /**
733
     * 	Load array this->attributes, or old this->attribute_xxx like attribute_label, attribute_type, ...
734
     *
735
     * 	@param	string		$elementtype		Type of element ('adherent', 'commande', 'thirdparty', 'facture', 'propal', 'product', ...).
736
     * 	@param	boolean		$forceload			Force load of extra fields whatever is option MAIN_EXTRAFIELDS_DISABLED. Deprecated. Should not be required.
737
     * 	@return	array							Array of attributes keys+label for all extra fields.
738
     */
739
    function fetch_name_optionals_label($elementtype, $forceload = false)
740
    {
741
        // phpcs:enable
742
        // global $conf;
743
744
        if (empty($elementtype))
745
            return array();
746
747
        if ($elementtype == 'thirdparty')
748
            $elementtype = 'societe';
749
        if ($elementtype == 'contact')
750
            $elementtype = 'socpeople';
751
        if ($elementtype == 'order_supplier')
752
            $elementtype = 'commande_fournisseur';
753
754
        $array_name_label = array();
755
756
        // To avoid conflicts with external modules. TODO Remove this.
757
        if (!$forceload && !empty(Globals::$conf->global->MAIN_EXTRAFIELDS_DISABLED))
758
            return $array_name_label;
759
760
        // Set array of label of entity
761
        // TODO Remove completely loading of label. This should be done by presentation.
762
        $labelmulticompany = array();
763
        if (!empty(Globals::$conf->multicompany->enabled)) {
764
            $sql_entity_name = 'SELECT rowid, label FROM ' . MAIN_DB_PREFIX . 'entity WHERE rowid in (0,' . Globals::$conf->entity . ')';
765
            $resql_entity_name = Config::$dbEngine->query($sql_entity_name);
766
            if ($resql_entity_name) {
767
                while ($obj = Config::$dbEngine->fetch_object($resql_entity_name)) {
768
                    $labelmulticompany[$obj->rowid] = $obj->label;
769
                }
770
            }
771
        }
772
773
        // We should not have several time this log. If we have, there is some optimization to do by calling a simple $object->fetch_optionals() that include cache management.
774
        DolUtils::dol_syslog("fetch_name_optionals_label elementtype=" . $elementtype);
775
776
        $sql = "SELECT rowid,name,label,type,size,elementtype,fieldunique,fieldrequired,param,pos,alwayseditable,perms,langs,list,totalizable,fielddefault,fieldcomputed,entity,enabled,help";
777
        $sql .= " FROM " . MAIN_DB_PREFIX . "extrafields";
778
        $sql .= " WHERE entity IN (0," . Globals::$conf->entity . ")";
779
        if ($elementtype)
780
            $sql .= " AND elementtype = '" . $elementtype . "'"; // Filed with object->table_element
781
        $sql .= " ORDER BY pos";
782
783
        $resql = Config::$dbEngine->select($sql);
784
        if ($resql) {
785
            foreach ($resql as $arrayTab) {
786
787
                // Convert array to object
788
                $tab = json_decode(json_encode($arrayTab));
789
790
                // We can add this attribute to object. TODO Remove this and return $this->attributes[$elementtype]['label']
791
                if ($tab->type != 'separate') {
792
                    $array_name_label[$tab->name] = $tab->label;
793
                }
794
795
                // Old usage
796
                $this->attribute_type[$tab->name] = $tab->type;
797
                $this->attribute_label[$tab->name] = $tab->label;
798
                $this->attribute_size[$tab->name] = $tab->size;
799
                $this->attribute_elementtype[$tab->name] = $tab->elementtype;
800
                $this->attribute_default[$tab->name] = $tab->fielddefault;
801
                $this->attribute_computed[$tab->name] = $tab->fieldcomputed;
802
                $this->attribute_unique[$tab->name] = $tab->fieldunique;
803
                $this->attribute_required[$tab->name] = $tab->fieldrequired;
804
                $this->attribute_param[$tab->name] = ($tab->param ? unserialize($tab->param) : '');
805
                $this->attribute_pos[$tab->name] = $tab->pos;
806
                $this->attribute_alwayseditable[$tab->name] = $tab->alwayseditable;
807
                $this->attribute_perms[$tab->name] = (strlen($tab->perms) == 0 ? 1 : $tab->perms);
808
                $this->attribute_langfile[$tab->name] = $tab->langs;
809
                $this->attribute_list[$tab->name] = $tab->list;
810
                $this->attribute_totalizable[$tab->name] = $tab->totalizable;
811
                $this->attribute_entityid[$tab->name] = $tab->entity;
812
                $this->attribute_entitylabel[$tab->name] = (empty($labelmulticompany[$tab->entity]) ? 'Entity' . $tab->entity : $labelmulticompany[$tab->entity]);
813
814
                // New usage
815
                $this->attributes[$tab->elementtype]['type'][$tab->name] = $tab->type;
816
                $this->attributes[$tab->elementtype]['label'][$tab->name] = $tab->label;
817
                $this->attributes[$tab->elementtype]['size'][$tab->name] = $tab->size;
818
                $this->attributes[$tab->elementtype]['elementtype'][$tab->name] = $tab->elementtype;
819
                $this->attributes[$tab->elementtype]['default'][$tab->name] = $tab->fielddefault;
820
                $this->attributes[$tab->elementtype]['computed'][$tab->name] = $tab->fieldcomputed;
821
                $this->attributes[$tab->elementtype]['unique'][$tab->name] = $tab->fieldunique;
822
                $this->attributes[$tab->elementtype]['required'][$tab->name] = $tab->fieldrequired;
823
                $this->attributes[$tab->elementtype]['param'][$tab->name] = ($tab->param ? unserialize($tab->param) : '');
824
                $this->attributes[$tab->elementtype]['pos'][$tab->name] = $tab->pos;
825
                $this->attributes[$tab->elementtype]['alwayseditable'][$tab->name] = $tab->alwayseditable;
826
                $this->attributes[$tab->elementtype]['perms'][$tab->name] = (strlen($tab->perms) == 0 ? 1 : $tab->perms);
827
                $this->attributes[$tab->elementtype]['langfile'][$tab->name] = $tab->langs;
828
                $this->attributes[$tab->elementtype]['list'][$tab->name] = $tab->list;
829
                $this->attributes[$tab->elementtype]['totalizable'][$tab->name] = $tab->totalizable;
830
                $this->attributes[$tab->elementtype]['entityid'][$tab->name] = $tab->entity;
831
                $this->attributes[$tab->elementtype]['entitylabel'][$tab->name] = (empty($labelmulticompany[$tab->entity]) ? 'Entity' . $tab->entity : $labelmulticompany[$tab->entity]);
832
                $this->attributes[$tab->elementtype]['enabled'][$tab->name] = $tab->enabled;
833
                $this->attributes[$tab->elementtype]['help'][$tab->name] = $tab->help;
834
            }
835
836
            $this->attributes[$tab->elementtype]['loaded'] = 1;
837
            if ($elementtype) {
838
                $this->attributes[$elementtype]['loaded'] = 1; // If nothing found, we also save tag 'loaded'
839
            }
840
        }
841
842
        return $array_name_label;
843
    }
844
845
    /**
846
     * Return HTML string to put an input field into a page
847
     * Code very similar with showInputField of common object
848
     *
849
     * @param  string  $key            			Key of attribute
850
     * @param  string  $value          			Preselected value to show (for date type it must be in timestamp format, for amount or price it must be a php numeric value)
851
     * @param  string  $moreparam      			To add more parametes on html input tag
852
     * @param  string  $keysuffix      			Prefix string to add after name and id of field (can be used to avoid duplicate names)
853
     * @param  string  $keyprefix      			Suffix string to add before name and id of field (can be used to avoid duplicate names)
854
     * @param  string  $morecss        			More css (to defined size of field. Old behaviour: may also be a numeric)
855
     * @param  int     $objectid       			Current object id
856
     * @param  string  $extrafieldsobjectkey	If defined (for example $object->table_element), use the new method to get extrafields data
857
     * @return string
858
     */
859
    function showInputField($key, $value, $moreparam = '', $keysuffix = '', $keyprefix = '', $morecss = '', $objectid = 0, $extrafieldsobjectkey = '')
860
    {
861
        // global $conf, $langs, $form;
862
863
        if (!is_object($form)) {
864
            require_once DOL_DOCUMENT_ROOT . '/core/class/html.form.class.php';
865
            $form = new Form(Config::$dbEngine);
866
        }
867
868
        $out = '';
869
870
        $keyprefix = $keyprefix . 'options_';  // Because we work on extrafields
871
872
        if (!empty($extrafieldsobjectkey)) {
873
            $label = $this->attributes[$extrafieldsobjectkey]['label'][$key];
874
            $type = $this->attributes[$extrafieldsobjectkey]['type'][$key];
875
            $size = $this->attributes[$extrafieldsobjectkey]['size'][$key];
876
            $default = $this->attributes[$extrafieldsobjectkey]['default'][$key];
877
            $computed = $this->attributes[$extrafieldsobjectkey]['computed'][$key];
878
            $unique = $this->attributes[$extrafieldsobjectkey]['unique'][$key];
879
            $required = $this->attributes[$extrafieldsobjectkey]['required'][$key];
880
            $param = $this->attributes[$extrafieldsobjectkey]['param'][$key];
881
            $perms = dol_eval($this->attributes[$extrafieldsobjectkey]['perms'][$key], 1);
882
            $langfile = $this->attributes[$extrafieldsobjectkey]['langfile'][$key];
883
            $list = dol_eval($this->attributes[$extrafieldsobjectkey]['list'][$key], 1);
884
            $totalizable = $this->attributes[$extrafieldsobjectkey]['totalizable'][$key];
885
            $help = $this->attributes[$extrafieldsobjectkey]['help'][$key];
886
            $hidden = (empty($list) ? 1 : 0);  // If empty, we are sure it is hidden, otherwise we show. If it depends on mode (view/create/edit form or list, this must be filtered by caller)
887
        } else { // Old usage
888
            $label = $this->attribute_label[$key];
889
            $type = $this->attribute_type[$key];
890
            $size = $this->attribute_size[$key];
891
            $elementtype = $this->attribute_elementtype[$key]; // Seems not used
892
            $default = $this->attribute_default[$key];
893
            $computed = $this->attribute_computed[$key];
894
            $unique = $this->attribute_unique[$key];
895
            $required = $this->attribute_required[$key];
896
            $param = $this->attribute_param[$key];
897
            $langfile = $this->attribute_langfile[$key];
898
            $list = $this->attribute_list[$key];
899
            $totalizable = $this->attribute_totalizable[$key];
900
            $hidden = (empty($list) ? 1 : 0);  // If empty, we are sure it is hidden, otherwise we show. If it depends on mode (view/create/edit form or list, this must be filtered by caller)
901
        }
902
903
        if ($computed) {
904
            if (!preg_match('/^search_/', $keyprefix))
905
                return '<span class="opacitymedium">' . Globals::$langs->trans("AutomaticallyCalculated") . '</span>';
906
            else
907
                return '';
908
        }
909
910
        if (empty($morecss)) {
911
            if ($type == 'date') {
912
                $morecss = 'minwidth100imp';
913
            } elseif ($type == 'datetime') {
914
                $morecss = 'minwidth200imp';
915
            } elseif (in_array($type, array('int', 'integer', 'double', 'price'))) {
916
                $morecss = 'maxwidth75';
917
            } elseif ($type == 'password') {
918
                $morecss = 'maxwidth100';
919
            } elseif ($type == 'url') {
920
                $morecss = 'minwidth400';
921
            } elseif ($type == 'boolean') {
922
                $morecss = '';
923
            } else {
924
                if (round($size) < 12) {
925
                    $morecss = 'minwidth100';
926
                } else if (round($size) <= 48) {
927
                    $morecss = 'minwidth200';
928
                } else {
929
                    $morecss = 'minwidth400';
930
                }
931
            }
932
        }
933
934
        if (in_array($type, array('date', 'datetime'))) {
935
            $tmp = explode(',', $size);
936
            $newsize = $tmp[0];
937
938
            $showtime = in_array($type, array('datetime')) ? 1 : 0;
939
940
            // Do not show current date when field not required (see selectDate() method)
941
            if (!$required && $value == '')
942
                $value = '-1';
943
944
            // TODO Must also support $moreparam
945
            $out = $form->selectDate($value, $keyprefix . $key . $keysuffix, $showtime, $showtime, $required, '', 1, (($keyprefix != 'search_' && $keyprefix != 'search_options_') ? 1 : 0), 0, 1);
946
        }
947
        elseif (in_array($type, array('int', 'integer'))) {
948
            $tmp = explode(',', $size);
949
            $newsize = $tmp[0];
950
            $out = '<input type="text" class="flat ' . $morecss . ' maxwidthonsmartphone" name="' . $keyprefix . $key . $keysuffix . '" id="' . $keyprefix . $key . $keysuffix . '" maxlength="' . $newsize . '" value="' . dol_escape_htmltag($value) . '"' . ($moreparam ? $moreparam : '') . '>';
951
        } elseif (preg_match('/varchar/', $type)) {
952
            $out = '<input type="text" class="flat ' . $morecss . ' maxwidthonsmartphone" name="' . $keyprefix . $key . $keysuffix . '" id="' . $keyprefix . $key . $keysuffix . '" maxlength="' . $size . '" value="' . dol_escape_htmltag($value) . '"' . ($moreparam ? $moreparam : '') . '>';
953
        } elseif (in_array($type, array('mail', 'phone', 'url'))) {
954
            $out = '<input type="text" class="flat ' . $morecss . ' maxwidthonsmartphone" name="' . $keyprefix . $key . $keysuffix . '" id="' . $keyprefix . $key . $keysuffix . '" value="' . dol_escape_htmltag($value) . '" ' . ($moreparam ? $moreparam : '') . '>';
955
        } elseif ($type == 'text') {
956
            if (!preg_match('/search_/', $keyprefix)) {  // If keyprefix is search_ or search_options_, we must just use a simple text field
957
                require_once DOL_DOCUMENT_ROOT . '/core/class/doleditor.class.php';
958
                $doleditor = new DolEditor($keyprefix . $key . $keysuffix, $value, '', 200, 'dolibarr_notes', 'In', false, false, false, ROWS_5, '90%');
959
                $out = $doleditor->Create(1);
960
            } else {
961
                $out = '<input type="text" class="flat ' . $morecss . ' maxwidthonsmartphone" name="' . $keyprefix . $key . $keysuffix . '" id="' . $keyprefix . $key . $keysuffix . '" value="' . dol_escape_htmltag($value) . '" ' . ($moreparam ? $moreparam : '') . '>';
962
            }
963
        } elseif ($type == 'html') {
964
            if (!preg_match('/search_/', $keyprefix)) {  // If keyprefix is search_ or search_options_, we must just use a simple text field
965
                require_once DOL_DOCUMENT_ROOT . '/core/class/doleditor.class.php';
966
                $doleditor = new DolEditor($keyprefix . $key . $keysuffix, $value, '', 200, 'dolibarr_notes', 'In', false, false, !empty(Globals::$conf->fckeditor->enabled) && Globals::$conf->global->FCKEDITOR_ENABLE_SOCIETE, ROWS_5, '90%');
967
                $out = $doleditor->Create(1);
968
            } else {
969
                $out = '<input type="text" class="flat ' . $morecss . ' maxwidthonsmartphone" name="' . $keyprefix . $key . $keysuffix . '" id="' . $keyprefix . $key . $keysuffix . '" value="' . dol_escape_htmltag($value) . '" ' . ($moreparam ? $moreparam : '') . '>';
970
            }
971
        } elseif ($type == 'boolean') {
972
            $checked = '';
973
            if (!empty($value)) {
974
                $checked = ' checked value="1" ';
975
            } else {
976
                $checked = ' value="1" ';
977
            }
978
            $out = '<input type="checkbox" class="flat ' . $morecss . ' maxwidthonsmartphone" name="' . $keyprefix . $key . $keysuffix . '" id="' . $keyprefix . $key . $keysuffix . '" ' . $checked . ' ' . ($moreparam ? $moreparam : '') . '>';
979
        } elseif ($type == 'price') {
980
            if (!empty($value)) {  // $value in memory is a php numeric, we format it into user number format.
981
                $value = price($value);
982
            }
983
            $out = '<input type="text" class="flat ' . $morecss . ' maxwidthonsmartphone" name="' . $keyprefix . $key . $keysuffix . '" id="' . $keyprefix . $key . $keysuffix . '" value="' . $value . '" ' . ($moreparam ? $moreparam : '') . '> ' . Globals::$langs->getCurrencySymbol(Globals::$conf->currency);
984
        } elseif ($type == 'double') {
985
            if (!empty($value)) {  // $value in memory is a php numeric, we format it into user number format.
986
                $value = price($value);
987
            }
988
            $out = '<input type="text" class="flat ' . $morecss . ' maxwidthonsmartphone" name="' . $keyprefix . $key . $keysuffix . '" id="' . $keyprefix . $key . $keysuffix . '" value="' . $value . '" ' . ($moreparam ? $moreparam : '') . '> ';
989
        } elseif ($type == 'select') {
990
            $out = '';
991
            if (!empty(Globals::$conf->use_javascript_ajax) && !empty(Globals::$conf->global->MAIN_EXTRAFIELDS_USE_SELECT2)) {
992
                include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
993
                $out .= ajax_combobox($keyprefix . $key . $keysuffix, array(), 0);
994
            }
995
996
            $out .= '<select class="flat ' . $morecss . ' maxwidthonsmartphone" name="' . $keyprefix . $key . $keysuffix . '" id="' . $keyprefix . $key . $keysuffix . '" ' . ($moreparam ? $moreparam : '') . '>';
997
            $out .= '<option value="0">&nbsp;</option>';
998
            foreach ($param['options'] as $key => $val) {
999
                if ((string) $key == '')
1000
                    continue;
1001
                list($val, $parent) = explode('|', $val);
1002
                $out .= '<option value="' . $key . '"';
1003
                $out .= (((string) $value == (string) $key) ? ' selected' : '');
1004
                $out .= (!empty($parent) ? ' parent="' . $parent . '"' : '');
1005
                $out .= '>';
1006
                if ($langfile && $val)
1007
                    $out .= Globals::$langs->trans($val);
1008
                else
1009
                    $out .= $val;
1010
                $out .= '</option>';
1011
            }
1012
            $out .= '</select>';
1013
        }
1014
        elseif ($type == 'sellist') {
1015
            $out = '';
1016
            if (!empty(Globals::$conf->use_javascript_ajax) && !empty(Globals::$conf->global->MAIN_EXTRAFIELDS_USE_SELECT2)) {
1017
                include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
1018
                $out .= ajax_combobox($keyprefix . $key . $keysuffix, array(), 0);
1019
            }
1020
1021
            $out .= '<select class="flat ' . $morecss . ' maxwidthonsmartphone" name="' . $keyprefix . $key . $keysuffix . '" id="' . $keyprefix . $key . $keysuffix . '" ' . ($moreparam ? $moreparam : '') . '>';
1022
            if (is_array($param['options'])) {
1023
                $param_list = array_keys($param['options']);
1024
                $InfoFieldList = explode(":", $param_list[0]);
1025
                $parentName = '';
1026
                $parentField = '';
1027
                // 0 : tableName
1028
                // 1 : label field name
1029
                // 2 : key fields name (if differ of rowid)
1030
                // 3 : key field parent (for dependent lists)
1031
                // 4 : where clause filter on column or table extrafield, syntax field='value' or extra.field=value
1032
                $keyList = (empty($InfoFieldList[2]) ? 'rowid' : $InfoFieldList[2] . ' as rowid');
1033
1034
1035
                if (count($InfoFieldList) > 4 && !empty($InfoFieldList[4])) {
1036
                    if (strpos($InfoFieldList[4], 'extra.') !== false) {
1037
                        $keyList = 'main.' . $InfoFieldList[2] . ' as rowid';
1038
                    } else {
1039
                        $keyList = $InfoFieldList[2] . ' as rowid';
1040
                    }
1041
                }
1042
                if (count($InfoFieldList) > 3 && !empty($InfoFieldList[3])) {
1043
                    list($parentName, $parentField) = explode('|', $InfoFieldList[3]);
1044
                    $keyList .= ', ' . $parentField;
1045
                }
1046
1047
                $fields_label = explode('|', $InfoFieldList[1]);
1048
                if (is_array($fields_label)) {
1049
                    $keyList .= ', ';
1050
                    $keyList .= implode(', ', $fields_label);
1051
                }
1052
1053
                $sqlwhere = '';
1054
                $sql = 'SELECT ' . $keyList;
1055
                $sql .= ' FROM ' . MAIN_DB_PREFIX . $InfoFieldList[0];
1056
                if (!empty($InfoFieldList[4])) {
1057
                    // can use curent entity filter
1058
                    if (strpos($InfoFieldList[4], '$ENTITY$') !== false) {
1059
                        $InfoFieldList[4] = str_replace('$ENTITY$', Globals::$conf->entity, $InfoFieldList[4]);
1060
                    }
1061
                    // can use SELECT request
1062
                    if (strpos($InfoFieldList[4], '$SEL$') !== false) {
1063
                        $InfoFieldList[4] = str_replace('$SEL$', 'SELECT', $InfoFieldList[4]);
1064
                    }
1065
1066
                    // current object id can be use into filter
1067
                    if (strpos($InfoFieldList[4], '$ID$') !== false && !empty($objectid)) {
1068
                        $InfoFieldList[4] = str_replace('$ID$', $objectid, $InfoFieldList[4]);
1069
                    } else {
1070
                        $InfoFieldList[4] = str_replace('$ID$', '0', $InfoFieldList[4]);
1071
                    }
1072
                    //We have to join on extrafield table
1073
                    if (strpos($InfoFieldList[4], 'extra') !== false) {
1074
                        $sql .= ' as main, ' . MAIN_DB_PREFIX . $InfoFieldList[0] . '_extrafields as extra';
1075
                        $sqlwhere .= ' WHERE extra.fk_object=main.' . $InfoFieldList[2] . ' AND ' . $InfoFieldList[4];
1076
                    } else {
1077
                        $sqlwhere .= ' WHERE ' . $InfoFieldList[4];
1078
                    }
1079
                } else {
1080
                    $sqlwhere .= ' WHERE 1=1';
1081
                }
1082
                // Some tables may have field, some other not. For the moment we disable it.
1083
                if (in_array($InfoFieldList[0], array('tablewithentity'))) {
1084
                    $sqlwhere .= ' AND entity = ' . Globals::$conf->entity;
1085
                }
1086
                $sql .= $sqlwhere;
1087
                //print $sql;
1088
1089
                $sql .= ' ORDER BY ' . implode(', ', $fields_label);
1090
1091
                DolUtils::dol_syslog(get_class($this) . '::showInputField type=sellist', LOG_DEBUG);
1092
                $resql = Config::$dbEngine->query($sql);
1093
                if ($resql) {
1094
                    $out .= '<option value="0">&nbsp;</option>';
1095
                    $num = Config::$dbEngine->num_rows($resql);
1096
                    $i = 0;
1097
                    while ($i < $num) {
1098
                        $labeltoshow = '';
1099
                        $obj = Config::$dbEngine->fetch_object($resql);
1100
1101
                        // Several field into label (eq table:code|libelle:rowid)
1102
                        $notrans = false;
1103
                        $fields_label = explode('|', $InfoFieldList[1]);
1104
                        if (is_array($fields_label)) {
1105
                            $notrans = true;
1106
                            foreach ($fields_label as $field_toshow) {
1107
                                $labeltoshow .= $obj->$field_toshow . ' ';
1108
                            }
1109
                        } else {
1110
                            $labeltoshow = $obj->{$InfoFieldList[1]};
1111
                        }
1112
                        $labeltoshow = dol_trunc($labeltoshow, 45);
1113
1114
                        if ($value == $obj->rowid) {
1115
                            foreach ($fields_label as $field_toshow) {
1116
                                $translabel = Globals::$langs->trans($obj->$field_toshow);
1117
                                if ($translabel != $obj->$field_toshow) {
1118
                                    $labeltoshow = dol_trunc($translabel, 18) . ' ';
1119
                                } else {
1120
                                    $labeltoshow = dol_trunc($obj->$field_toshow, 18) . ' ';
1121
                                }
1122
                            }
1123
                            $out .= '<option value="' . $obj->rowid . '" selected>' . $labeltoshow . '</option>';
1124
                        } else {
1125
                            if (!$notrans) {
1126
                                $translabel = Globals::$langs->trans($obj->{$InfoFieldList[1]});
1127
                                if ($translabel != $obj->{$InfoFieldList[1]}) {
1128
                                    $labeltoshow = dol_trunc($translabel, 18);
1129
                                } else {
1130
                                    $labeltoshow = dol_trunc($obj->{$InfoFieldList[1]}, 18);
1131
                                }
1132
                            }
1133
                            if (empty($labeltoshow))
1134
                                $labeltoshow = '(not defined)';
1135
                            if ($value == $obj->rowid) {
1136
                                $out .= '<option value="' . $obj->rowid . '" selected>' . $labeltoshow . '</option>';
1137
                            }
1138
1139
                            if (!empty($InfoFieldList[3]) && $parentField) {
1140
                                $parent = $parentName . ':' . $obj->{$parentField};
1141
                            }
1142
1143
                            $out .= '<option value="' . $obj->rowid . '"';
1144
                            $out .= ($value == $obj->rowid ? ' selected' : '');
1145
                            $out .= (!empty($parent) ? ' parent="' . $parent . '"' : '');
1146
                            $out .= '>' . $labeltoshow . '</option>';
1147
                        }
1148
1149
                        $i++;
1150
                    }
1151
                    Config::$dbEngine->free($resql);
1152
                } else {
1153
                    print 'Error in request ' . $sql . ' ' . Config::$dbEngine->lasterror() . '. Check setup of extra parameters.<br>';
1154
                }
1155
            }
1156
            $out .= '</select>';
1157
        } elseif ($type == 'checkbox') {
1158
            $value_arr = explode(',', $value);
1159
            $out = $form->multiselectarray($keyprefix . $key . $keysuffix, (empty($param['options']) ? null : $param['options']), $value_arr, '', 0, '', 0, '100%');
1160
        } elseif ($type == 'radio') {
1161
            $out = '';
1162
            foreach ($param['options'] as $keyopt => $val) {
1163
                $out .= '<input class="flat ' . $morecss . '" type="radio" name="' . $keyprefix . $key . $keysuffix . '" id="' . $keyprefix . $key . $keysuffix . '" ' . ($moreparam ? $moreparam : '');
1164
                $out .= ' value="' . $keyopt . '"';
1165
                $out .= ' id="' . $keyprefix . $key . $keysuffix . '_' . $keyopt . '"';
1166
                $out .= ($value == $keyopt ? 'checked' : '');
1167
                $out .= '/><label for="' . $keyprefix . $key . $keysuffix . '_' . $keyopt . '">' . $val . '</label><br>';
1168
            }
1169
        } elseif ($type == 'chkbxlst') {
1170
            if (is_array($value)) {
1171
                $value_arr = $value;
1172
            } else {
1173
                $value_arr = explode(',', $value);
1174
            }
1175
1176
            if (is_array($param['options'])) {
1177
                $param_list = array_keys($param['options']);
1178
                $InfoFieldList = explode(":", $param_list[0]);
1179
                $parentName = '';
1180
                $parentField = '';
1181
                // 0 : tableName
1182
                // 1 : label field name
1183
                // 2 : key fields name (if differ of rowid)
1184
                // 3 : key field parent (for dependent lists)
1185
                // 4 : where clause filter on column or table extrafield, syntax field='value' or extra.field=value
1186
                $keyList = (empty($InfoFieldList[2]) ? 'rowid' : $InfoFieldList[2] . ' as rowid');
1187
1188
                if (count($InfoFieldList) > 3 && !empty($InfoFieldList[3])) {
1189
                    list ( $parentName, $parentField ) = explode('|', $InfoFieldList[3]);
1190
                    $keyList .= ', ' . $parentField;
1191
                }
1192
                if (count($InfoFieldList) > 4 && !empty($InfoFieldList[4])) {
1193
                    if (strpos($InfoFieldList[4], 'extra.') !== false) {
1194
                        $keyList = 'main.' . $InfoFieldList[2] . ' as rowid';
1195
                    } else {
1196
                        $keyList = $InfoFieldList[2] . ' as rowid';
1197
                    }
1198
                }
1199
1200
                $fields_label = explode('|', $InfoFieldList[1]);
1201
                if (is_array($fields_label)) {
1202
                    $keyList .= ', ';
1203
                    $keyList .= implode(', ', $fields_label);
1204
                }
1205
1206
                $sqlwhere = '';
1207
                $sql = 'SELECT ' . $keyList;
1208
                $sql .= ' FROM ' . MAIN_DB_PREFIX . $InfoFieldList[0];
1209
                if (!empty($InfoFieldList[4])) {
1210
1211
                    // can use SELECT request
1212
                    if (strpos($InfoFieldList[4], '$SEL$') !== false) {
1213
                        $InfoFieldList[4] = str_replace('$SEL$', 'SELECT', $InfoFieldList[4]);
1214
                    }
1215
1216
                    // current object id can be use into filter
1217
                    if (strpos($InfoFieldList[4], '$ID$') !== false && !empty($objectid)) {
1218
                        $InfoFieldList[4] = str_replace('$ID$', $objectid, $InfoFieldList[4]);
1219
                    } else if (preg_match("#^.*list.php$#", $_SERVER["DOCUMENT_URI"])) {
1220
                        // Pattern for word=$ID$
1221
                        $word = '\b[a-zA-Z0-9-\.-_]+\b=\$ID\$';
1222
1223
                        // Removing space arount =, ( and )
1224
                        $InfoFieldList[4] = preg_replace('# *(=|\(|\)) *#', '$1', $InfoFieldList[4]);
1225
1226
                        $nbPreg = 1;
1227
                        // While we have parenthesis
1228
                        while ($nbPreg != 0) {
1229
                            // Init des compteurs
1230
                            $nbPregRepl = $nbPregSel = 0;
1231
                            // On retire toutes les parenthèses sans = avant
1232
                            $InfoFieldList[4] = preg_replace('#([^=])(\([^)^(]*(' . $word . ')[^)^(]*\))#', '$1 $3 ', $InfoFieldList[4], -1, $nbPregRepl);
1233
                            // On retire les espaces autour des = et parenthèses
1234
                            $InfoFieldList[4] = preg_replace('# *(=|\(|\)) *#', '$1', $InfoFieldList[4]);
1235
                            // On retire toutes les parenthèses avec = avant
1236
                            $InfoFieldList[4] = preg_replace('#\b[a-zA-Z0-9-\.-_]+\b=\([^)^(]*(' . $word . ')[^)^(]*\)#', '$1 ', $InfoFieldList[4], -1, $nbPregSel);
1237
                            // On retire les espaces autour des = et parenthèses
1238
                            $InfoFieldList[4] = preg_replace('# *(=|\(|\)) *#', '$1', $InfoFieldList[4]);
1239
1240
                            // Calcul du compteur général pour la boucle
1241
                            $nbPreg = $nbPregRepl + $nbPregSel;
1242
                        }
1243
1244
                        // Si l'on a un AND ou un OR, avant ou après
1245
                        preg_match('#(AND|OR|) *(' . $word . ') *(AND|OR|)#', $InfoFieldList[4], $matchCondition);
1246
                        while (!empty($matchCondition[0])) {
1247
                            // If the two sides differ but are not empty
1248
                            if (!empty($matchCondition[1]) && !empty($matchCondition[3]) && $matchCondition[1] != $matchCondition[3]) {
1249
                                // Nobody sain would do that without parentheses
1250
                                $InfoFieldList[4] = str_replace('$ID$', '0', $InfoFieldList[4]);
1251
                            } else {
1252
                                if (!empty($matchCondition[1])) {
1253
                                    $boolCond = (( $matchCondition[1] == "AND" ) ? ' AND 1 ' : ' OR 0 ');
1254
                                    $InfoFieldList[4] = str_replace($matchCondition[0], $boolCond . $matchCondition[3], $InfoFieldList[4]);
1255
                                } else if (!empty($matchCondition[3])) {
1256
                                    $boolCond = (( $matchCondition[3] == "AND" ) ? ' 1 AND ' : ' 0 OR');
1257
                                    $InfoFieldList[4] = str_replace($matchCondition[0], $boolCond, $InfoFieldList[4]);
1258
                                } else {
1259
                                    $InfoFieldList[4] = 1;
1260
                                }
1261
                            }
1262
1263
                            // Si l'on a un AND ou un OR, avant ou après
1264
                            preg_match('#(AND|OR|) *(' . $word . ') *(AND|OR|)#', $InfoFieldList[4], $matchCondition);
1265
                        }
1266
                    } else {
1267
                        $InfoFieldList[4] = str_replace('$ID$', '0', $InfoFieldList[4]);
1268
                    }
1269
1270
                    // We have to join on extrafield table
1271
                    if (strpos($InfoFieldList[4], 'extra') !== false) {
1272
                        $sql .= ' as main, ' . MAIN_DB_PREFIX . $InfoFieldList[0] . '_extrafields as extra';
1273
                        $sqlwhere .= ' WHERE extra.fk_object=main.' . $InfoFieldList[2] . ' AND ' . $InfoFieldList[4];
1274
                    } else {
1275
                        $sqlwhere .= ' WHERE ' . $InfoFieldList[4];
1276
                    }
1277
                } else {
1278
                    $sqlwhere .= ' WHERE 1=1';
1279
                }
1280
                // Some tables may have field, some other not. For the moment we disable it.
1281
                if (in_array($InfoFieldList[0], array('tablewithentity'))) {
1282
                    $sqlwhere .= ' AND entity = ' . Globals::$conf->entity;
1283
                }
1284
                // $sql.=preg_replace('/^ AND /','',$sqlwhere);
1285
                // print $sql;
1286
1287
                $sql .= $sqlwhere;
1288
                DolUtils::dol_syslog(get_class($this) . '::showInputField type=chkbxlst', LOG_DEBUG);
1289
                $resql = Config::$dbEngine->query($sql);
1290
                if ($resql) {
1291
                    $num = Config::$dbEngine->num_rows($resql);
1292
                    $i = 0;
1293
1294
                    $data = array();
1295
1296
                    while ($i < $num) {
1297
                        $labeltoshow = '';
1298
                        $obj = Config::$dbEngine->fetch_object($resql);
1299
1300
                        $notrans = false;
1301
                        // Several field into label (eq table:code|libelle:rowid)
1302
                        $fields_label = explode('|', $InfoFieldList[1]);
1303
                        if (is_array($fields_label)) {
1304
                            $notrans = true;
1305
                            foreach ($fields_label as $field_toshow) {
1306
                                $labeltoshow .= $obj->$field_toshow . ' ';
1307
                            }
1308
                        } else {
1309
                            $labeltoshow = $obj->{$InfoFieldList[1]};
1310
                        }
1311
                        $labeltoshow = dol_trunc($labeltoshow, 45);
1312
1313
                        if (is_array($value_arr) && in_array($obj->rowid, $value_arr)) {
1314
                            foreach ($fields_label as $field_toshow) {
1315
                                $translabel = Globals::$langs->trans($obj->$field_toshow);
1316
                                if ($translabel != $obj->$field_toshow) {
1317
                                    $labeltoshow = dol_trunc($translabel, 18) . ' ';
1318
                                } else {
1319
                                    $labeltoshow = dol_trunc($obj->$field_toshow, 18) . ' ';
1320
                                }
1321
                            }
1322
1323
                            $data[$obj->rowid] = $labeltoshow;
1324
                        } else {
1325
                            if (!$notrans) {
1326
                                $translabel = Globals::$langs->trans($obj->{$InfoFieldList[1]});
1327
                                if ($translabel != $obj->{$InfoFieldList[1]}) {
1328
                                    $labeltoshow = dol_trunc($translabel, 18);
1329
                                } else {
1330
                                    $labeltoshow = dol_trunc($obj->{$InfoFieldList[1]}, 18);
1331
                                }
1332
                            }
1333
                            if (empty($labeltoshow))
1334
                                $labeltoshow = '(not defined)';
1335
1336
                            if (is_array($value_arr) && in_array($obj->rowid, $value_arr)) {
1337
                                $data[$obj->rowid] = $labeltoshow;
1338
                            }
1339
1340
                            if (!empty($InfoFieldList[3]) && $parentField) {
1341
                                $parent = $parentName . ':' . $obj->{$parentField};
1342
                            }
1343
1344
                            $data[$obj->rowid] = $labeltoshow;
1345
                        }
1346
1347
                        $i ++;
1348
                    }
1349
                    Config::$dbEngine->free($resql);
1350
1351
                    $out = $form->multiselectarray($keyprefix . $key . $keysuffix, $data, $value_arr, '', 0, '', 0, '100%');
1352
                } else {
1353
                    print 'Error in request ' . $sql . ' ' . Config::$dbEngine->lasterror() . '. Check setup of extra parameters.<br>';
1354
                }
1355
            }
1356
        } elseif ($type == 'link') {
1357
            $param_list = array_keys($param['options']);    // $param_list='ObjectName:classPath'
1358
            $showempty = (($required && $default != '') ? 0 : 1);
1359
            $out = $form->selectForForms($param_list[0], $keyprefix . $key . $keysuffix, $value, $showempty);
1360
        } elseif ($type == 'password') {
1361
            // If prefix is 'search_', field is used as a filter, we use a common text field.
1362
            $out = '<input style="display:none" type="text" name="fakeusernameremembered">'; // Hidden field to reduce impact of evil Google Chrome autopopulate bug.
1363
            $out .= '<input autocomplete="new-password" type="' . ($keyprefix == 'search_' ? 'text' : 'password') . '" class="flat ' . $morecss . '" name="' . $keyprefix . $key . $keysuffix . '" id="' . $keyprefix . $key . $keysuffix . '" value="' . $value . '" ' . ($moreparam ? $moreparam : '') . '>';
1364
        }
1365
        if (!empty($hidden)) {
1366
            $out = '<input type="hidden" value="' . $value . '" name="' . $keyprefix . $key . $keysuffix . '" id="' . $keyprefix . $key . $keysuffix . '"/>';
1367
        }
1368
        /* Add comments
1369
          if ($type == 'date') $out.=' (YYYY-MM-DD)';
1370
          elseif ($type == 'datetime') $out.=' (YYYY-MM-DD HH:MM:SS)';
1371
         */
1372
        return $out;
1373
    }
1374
1375
    /**
1376
     * Return HTML string to put an output field into a page
1377
     *
1378
     * @param   string	$key            		Key of attribute
1379
     * @param   string	$value          		Value to show
1380
     * @param	string	$moreparam				To add more parameters on html input tag (only checkbox use html input for output rendering)
1381
     * @param	string	$extrafieldsobjectkey	If defined (for example $object->table_element), use the new method to get extrafields data
1382
     * @return	string							Formated value
1383
     */
1384
    function showOutputField($key, $value, $moreparam = '', $extrafieldsobjectkey = '')
1385
    {
1386
        // global $conf, $langs;
1387
1388
        if (!empty($extrafieldsobjectkey)) {
1389
            $label = $this->attributes[$extrafieldsobjectkey]['label'][$key];
1390
            $type = $this->attributes[$extrafieldsobjectkey]['type'][$key];
1391
            $size = $this->attributes[$extrafieldsobjectkey]['size'][$key];
1392
            $default = $this->attributes[$extrafieldsobjectkey]['default'][$key];
1393
            $computed = $this->attributes[$extrafieldsobjectkey]['computed'][$key];
1394
            $unique = $this->attributes[$extrafieldsobjectkey]['unique'][$key];
1395
            $required = $this->attributes[$extrafieldsobjectkey]['required'][$key];
1396
            $param = $this->attributes[$extrafieldsobjectkey]['param'][$key];
1397
            $perms = dol_eval($this->attributes[$extrafieldsobjectkey]['perms'][$key], 1);
1398
            $langfile = $this->attributes[$extrafieldsobjectkey]['langfile'][$key];
1399
            $list = dol_eval($this->attributes[$extrafieldsobjectkey]['list'][$key], 1);
1400
            $help = $this->attributes[$extrafieldsobjectkey]['help'][$key];
1401
            $hidden = (empty($list) ? 1 : 0);  // If $list empty, we are sure it is hidden, otherwise we show. If it depends on mode (view/create/edit form or list, this must be filtered by caller)
1402
        } else { // Old usage
1403
            $label = $this->attribute_label[$key];
1404
            $type = $this->attribute_type[$key];
1405
            $size = $this->attribute_size[$key];
1406
            $default = $this->attribute_default[$key];
1407
            $computed = $this->attribute_computed[$key];
1408
            $unique = $this->attribute_unique[$key];
1409
            $required = $this->attribute_required[$key];
1410
            $param = $this->attribute_param[$key];
1411
            $perms = dol_eval($this->attribute_perms[$key], 1);
1412
            $langfile = $this->attribute_langfile[$key];
1413
            $list = dol_eval($this->attribute_list[$key], 1);
1414
            $help = ''; // Not supported with old syntax
1415
            $hidden = (empty($list) ? 1 : 0);  // If $list empty, we are sure it is hidden, otherwise we show. If it depends on mode (view/create/edit form or list, this must be filtered by caller)
1416
        }
1417
1418
        if ($hidden)
1419
            return '';  // This is a protection. If field is hidden, we should just not call this method.
1420
1421
1422
1423
1424
            
1425
// If field is a computed field, value must become result of compute
1426
        if ($computed) {
1427
            // Make the eval of compute string
1428
            //var_dump($computed);
1429
            $value = dol_eval($computed, 1, 0);
1430
        }
1431
1432
        $showsize = 0;
1433
        if ($type == 'date') {
1434
            $showsize = 10;
1435
            $value = dol_print_date($value, 'day');
1436
        } elseif ($type == 'datetime') {
1437
            $showsize = 19;
1438
            $value = dol_print_date($value, 'dayhour');
1439
        } elseif ($type == 'int') {
1440
            $showsize = 10;
1441
        } elseif ($type == 'double') {
1442
            if (!empty($value)) {
1443
                $value = price($value);
1444
            }
1445
        } elseif ($type == 'boolean') {
1446
            $checked = '';
1447
            if (!empty($value)) {
1448
                $checked = ' checked ';
1449
            }
1450
            $value = '<input type="checkbox" ' . $checked . ' ' . ($moreparam ? $moreparam : '') . ' readonly disabled>';
1451
        } elseif ($type == 'mail') {
1452
            $value = dol_print_email($value, 0, 0, 0, 64, 1, 1);
1453
        } elseif ($type == 'url') {
1454
            $value = dol_print_url($value, '_blank', 32, 1);
1455
        } elseif ($type == 'phone') {
1456
            $value = dol_print_phone($value, '', 0, 0, '', '&nbsp;', 1);
1457
        } elseif ($type == 'price') {
1458
            $value = price($value, 0, Globals::$langs, 0, 0, -1, Globals::$conf->currency);
1459
        } elseif ($type == 'select') {
1460
            if ($langfile && $param['options'][$value])
1461
                $value = Globals::$langs->trans($param['options'][$value]);
1462
            else
1463
                $value = $param['options'][$value];
1464
        }
1465
        elseif ($type == 'sellist') {
1466
            $param_list = array_keys($param['options']);
1467
            $InfoFieldList = explode(":", $param_list[0]);
1468
1469
            $selectkey = "rowid";
1470
            $keyList = 'rowid';
1471
1472
            if (count($InfoFieldList) >= 3) {
1473
                $selectkey = $InfoFieldList[2];
1474
                $keyList = $InfoFieldList[2] . ' as rowid';
1475
            }
1476
1477
            $fields_label = explode('|', $InfoFieldList[1]);
1478
            if (is_array($fields_label)) {
1479
                $keyList .= ', ';
1480
                $keyList .= implode(', ', $fields_label);
1481
            }
1482
1483
            $sql = 'SELECT ' . $keyList;
1484
            $sql .= ' FROM ' . MAIN_DB_PREFIX . $InfoFieldList[0];
1485
            if (strpos($InfoFieldList[4], 'extra') !== false) {
1486
                $sql .= ' as main';
1487
            }
1488
            if ($selectkey == 'rowid' && empty($value)) {
1489
                $sql .= " WHERE " . $selectkey . "=0";
1490
            } elseif ($selectkey == 'rowid') {
1491
                $sql .= " WHERE " . $selectkey . "=" . Config::$dbEngine->escape($value);
1492
            } else {
1493
                $sql .= " WHERE " . $selectkey . "='" . Config::$dbEngine->escape($value) . "'";
1494
            }
1495
1496
            //$sql.= ' AND entity = '.Globals::$conf->entity;
1497
1498
            DolUtils::dol_syslog(get_class($this) . ':showOutputField:$type=sellist', LOG_DEBUG);
1499
            $resql = Config::$dbEngine->query($sql);
1500
            if ($resql) {
1501
                $value = ''; // value was used, so now we reste it to use it to build final output
1502
1503
                $obj = Config::$dbEngine->fetch_object($resql);
1504
1505
                // Several field into label (eq table:code|libelle:rowid)
1506
                $fields_label = explode('|', $InfoFieldList[1]);
1507
1508
                if (is_array($fields_label) && count($fields_label) > 1) {
1509
                    foreach ($fields_label as $field_toshow) {
1510
                        $translabel = '';
1511
                        if (!empty($obj->$field_toshow)) {
1512
                            $translabel = Globals::$langs->trans($obj->$field_toshow);
1513
                        }
1514
                        if ($translabel != $field_toshow) {
1515
                            $value .= dol_trunc($translabel, 18) . ' ';
1516
                        } else {
1517
                            $value .= $obj->$field_toshow . ' ';
1518
                        }
1519
                    }
1520
                } else {
1521
                    $translabel = '';
1522
                    if (!empty($obj->{$InfoFieldList[1]})) {
1523
                        $translabel = Globals::$langs->trans($obj->{$InfoFieldList[1]});
1524
                    }
1525
                    if ($translabel != $obj->{$InfoFieldList[1]}) {
1526
                        $value = dol_trunc($translabel, 18);
1527
                    } else {
1528
                        $value = $obj->{$InfoFieldList[1]};
1529
                    }
1530
                }
1531
            } else
1532
                DolUtils::dol_syslog(get_class($this) . '::showOutputField error ' . Config::$dbEngine->lasterror(), LOG_WARNING);
1533
        }
1534
        elseif ($type == 'radio') {
1535
            $value = $param['options'][$value];
1536
        } elseif ($type == 'checkbox') {
1537
            $value_arr = explode(',', $value);
1538
            $value = '';
1539
            $toprint = array();
1540
            if (is_array($value_arr)) {
1541
                foreach ($value_arr as $keyval => $valueval) {
1542
                    $toprint[] = '<li class="select2-search-choice-dolibarr noborderoncategories" style="background: #aaa">' . $param['options'][$valueval] . '</li>';
1543
                }
1544
            }
1545
            $value = '<div class="select2-container-multi-dolibarr" style="width: 90%;"><ul class="select2-choices-dolibarr">' . implode(' ', $toprint) . '</ul></div>';
1546
        } elseif ($type == 'chkbxlst') {
1547
            $value_arr = explode(',', $value);
1548
1549
            $param_list = array_keys($param['options']);
1550
            $InfoFieldList = explode(":", $param_list[0]);
1551
1552
            $selectkey = "rowid";
1553
            $keyList = 'rowid';
1554
1555
            if (count($InfoFieldList) >= 3) {
1556
                $selectkey = $InfoFieldList[2];
1557
                $keyList = $InfoFieldList[2] . ' as rowid';
1558
            }
1559
1560
            $fields_label = explode('|', $InfoFieldList[1]);
1561
            if (is_array($fields_label)) {
1562
                $keyList .= ', ';
1563
                $keyList .= implode(', ', $fields_label);
1564
            }
1565
1566
            $sql = 'SELECT ' . $keyList;
1567
            $sql .= ' FROM ' . MAIN_DB_PREFIX . $InfoFieldList[0];
1568
            if (strpos($InfoFieldList[4], 'extra') !== false) {
1569
                $sql .= ' as main';
1570
            }
1571
            // $sql.= " WHERE ".$selectkey."='".Config::$dbEngine->escape($value)."'";
1572
            // $sql.= ' AND entity = '.Globals::$conf->entity;
1573
1574
            DolUtils::dol_syslog(get_class($this) . ':showOutputField:$type=chkbxlst', LOG_DEBUG);
1575
            $resql = Config::$dbEngine->query($sql);
1576
            if ($resql) {
1577
                $value = ''; // value was used, so now we reste it to use it to build final output
1578
                $toprint = array();
1579
                while ($obj = Config::$dbEngine->fetch_object($resql)) {
1580
1581
                    // Several field into label (eq table:code|libelle:rowid)
1582
                    $fields_label = explode('|', $InfoFieldList[1]);
1583
                    if (is_array($value_arr) && in_array($obj->rowid, $value_arr)) {
1584
                        if (is_array($fields_label) && count($fields_label) > 1) {
1585
                            foreach ($fields_label as $field_toshow) {
1586
                                $translabel = '';
1587
                                if (!empty($obj->$field_toshow)) {
1588
                                    $translabel = Globals::$langs->trans($obj->$field_toshow);
1589
                                }
1590
                                if ($translabel != $field_toshow) {
1591
                                    $toprint[] = '<li class="select2-search-choice-dolibarr noborderoncategories" style="background: #aaa">' . dol_trunc($translabel, 18) . '</li>';
1592
                                } else {
1593
                                    $toprint[] = '<li class="select2-search-choice-dolibarr noborderoncategories" style="background: #aaa">' . $obj->$field_toshow . '</li>';
1594
                                }
1595
                            }
1596
                        } else {
1597
                            $translabel = '';
1598
                            if (!empty($obj->{$InfoFieldList[1]})) {
1599
                                $translabel = Globals::$langs->trans($obj->{$InfoFieldList[1]});
1600
                            }
1601
                            if ($translabel != $obj->{$InfoFieldList[1]}) {
1602
                                $toprint[] = '<li class="select2-search-choice-dolibarr noborderoncategories" style="background: #aaa">' . dol_trunc($translabel, 18) . '</li>';
1603
                            } else {
1604
                                $toprint[] = '<li class="select2-search-choice-dolibarr noborderoncategories" style="background: #aaa">' . $obj->{$InfoFieldList[1]} . '</li>';
1605
                            }
1606
                        }
1607
                    }
1608
                }
1609
                $value = '<div class="select2-container-multi-dolibarr" style="width: 90%;"><ul class="select2-choices-dolibarr">' . implode(' ', $toprint) . '</ul></div>';
1610
            } else {
1611
                DolUtils::dol_syslog(get_class($this) . '::showOutputField error ' . Config::$dbEngine->lasterror(), LOG_WARNING);
1612
            }
1613
        } elseif ($type == 'link') {
1614
            $out = '';
1615
1616
            // Only if something to display (perf)
1617
            if ($value) {  // If we have -1 here, pb is into sert, not into ouptu
1618
                $param_list = array_keys($param['options']);    // $param_list='ObjectName:classPath'
1619
1620
                $InfoFieldList = explode(":", $param_list[0]);
1621
                $classname = $InfoFieldList[0];
1622
                $classpath = $InfoFieldList[1];
1623
                if (!empty($classpath)) {
1624
                    dol_include_once($InfoFieldList[1]);
1625
                    if ($classname && class_exists($classname)) {
1626
                        $object = new $classname(Config::$dbEngine);
1627
                        $object->fetch($value);
1628
                        $value = $object->getNomUrl(3);
1629
                    }
1630
                } else {
1631
                    DolUtils::dol_syslog('Error bad setup of extrafield', LOG_WARNING);
1632
                    return 'Error bad setup of extrafield';
1633
                }
1634
            }
1635
        } elseif ($type == 'text') {
1636
            $value = dol_htmlentitiesbr($value);
1637
        } elseif ($type == 'html') {
1638
            $value = dol_htmlentitiesbr($value);
1639
        } elseif ($type == 'password') {
1640
            $value = dol_trunc(preg_replace('/./i', '*', $value), 8, 'right', 'UTF-8', 1);
1641
        } else {
1642
            $showsize = round($size);
1643
            if ($showsize > 48)
1644
                $showsize = 48;
1645
        }
1646
1647
        //print $type.'-'.$size;
1648
        $out = $value;
1649
1650
        return $out;
1651
    }
1652
1653
    /**
1654
     * Return tag to describe alignement to use for this extrafield
1655
     *
1656
     * @param   string	$key            		Key of attribute
1657
     * @param	string	$extrafieldsobjectkey	If defined, use the new method to get extrafields data
1658
     * @return	string							Formated value
1659
     */
1660
    function getAlignFlag($key, $extrafieldsobjectkey = '')
1661
    {
1662
        // global $conf, $langs;
1663
1664
        if (!empty($extrafieldsobjectkey))
1665
            $type = $this->attributes[$extrafieldsobjectkey]['type'][$key];
1666
        else
1667
            $type = $this->attribute_type[$key];
1668
1669
        $align = '';
1670
1671
        if ($type == 'date') {
1672
            $align = "center";
1673
        } elseif ($type == 'datetime') {
1674
            $align = "center";
1675
        } elseif ($type == 'int') {
1676
            $align = "right";
1677
        } elseif ($type == 'double') {
1678
            $align = "right";
1679
        } elseif ($type == 'boolean') {
1680
            $align = "center";
1681
        } elseif ($type == 'radio') {
1682
            $align = "center";
1683
        } elseif ($type == 'checkbox') {
1684
            $align = "center";
1685
        } elseif ($type == 'price') {
1686
            $align = "right";
1687
        }
1688
1689
        return $align;
1690
    }
1691
1692
    /**
1693
     * Return HTML string to print separator extrafield
1694
     *
1695
     * @param   string	$key            Key of attribute
1696
     * @param	string	$object			Object
1697
     * @return 	string					HTML code with line for separator
1698
     */
1699
    function showSeparator($key, $object)
1700
    {
1701
        // global $langs;
1702
1703
        $out = '<tr class="trextrafieldseparator trextrafieldseparator' . $key . '"><td colspan="2"><strong>';
1704
        $out .= Globals::$langs->trans($this->attributes[$object->table_element]['label'][$key]);
1705
        $out .= '</strong></td></tr>';
1706
        return $out;
1707
    }
1708
1709
    /**
1710
     * Fill array_options property of object by extrafields value (using for data sent by forms)
1711
     *
1712
     * @param   array	$extralabels    $array of extrafields (@deprecated)
1713
     * @param   object	$object         Object
1714
     * @param	string	$onlykey		Only following key is filled. When we make update of only one extrafield ($action = 'update_extras'), calling page must must set this to avoid to have other extrafields being reset.
1715
     * @return	int						1 if array_options set, 0 if no value, -1 if error (field required missing for example)
1716
     */
1717
    function setOptionalsFromPost($extralabels, &$object, $onlykey = '')
1718
    {
1719
        // global $_POST, $langs;
1720
        $nofillrequired = ''; // For error when required field left blank
1721
        $error_field_required = array();
1722
1723
        if (is_array($this->attributes[$object->table_element]['label']))
1724
            $extralabels = $this->attributes[$object->table_element]['label'];
1725
1726
        if (is_array($extralabels)) {
1727
            // Get extra fields
1728
            foreach ($extralabels as $key => $value) {
1729
                if (!empty($onlykey) && $key != $onlykey)
1730
                    continue;
1731
1732
                $key_type = $this->attributes[$object->table_element]['type'][$key];
1733
                if ($key_type == 'separate')
1734
                    continue;
1735
1736
                $enabled = 1;
1737
                if (isset($this->attributes[$object->table_element]['list'][$key])) {
1738
                    $enabled = dol_eval($this->attributes[$object->table_element]['list'][$key], 1);
1739
                }
1740
                $perms = 1;
1741
                if (isset($this->attributes[$object->table_element]['perms'][$key])) {
1742
                    $perms = dol_eval($this->attributes[$object->table_element]['perms'][$key], 1);
1743
                }
1744
                if (empty($enabled))
1745
                    continue;
1746
                if (empty($perms))
1747
                    continue;
1748
1749
                if ($this->attributes[$object->table_element]['required'][$key]) { // Value is required
1750
                    // Check if empty without using GETPOST, value can be alpha, int, array, etc...
1751
                    if ((!is_array($_POST["options_" . $key]) && empty($_POST["options_" . $key]) && $_POST["options_" . $key] != '0') || (is_array($_POST["options_" . $key]) && empty($_POST["options_" . $key]))) {
1752
                        //print 'ccc'.$value.'-'.$this->attributes[$object->table_element]['required'][$key];
1753
                        $nofillrequired++;
1754
                        $error_field_required[] = Globals::$langs->transnoentitiesnoconv($value);
1755
                    }
1756
                }
1757
1758
                if (in_array($key_type, array('date'))) {
1759
                    // Clean parameters
1760
                    // TODO GMT date in memory must be GMT so we should add gm=true in parameters
1761
                    $value_key = dol_mktime(0, 0, 0, $_POST["options_" . $key . "month"], $_POST["options_" . $key . "day"], $_POST["options_" . $key . "year"]);
1762
                } elseif (in_array($key_type, array('datetime'))) {
1763
                    // Clean parameters
1764
                    // TODO GMT date in memory must be GMT so we should add gm=true in parameters
1765
                    $value_key = dol_mktime($_POST["options_" . $key . "hour"], $_POST["options_" . $key . "min"], 0, $_POST["options_" . $key . "month"], $_POST["options_" . $key . "day"], $_POST["options_" . $key . "year"]);
1766
                } else if (in_array($key_type, array('checkbox', 'chkbxlst'))) {
1767
                    $value_arr = GETPOST("options_" . $key, 'array'); // check if an array
1768
                    if (!empty($value_arr)) {
1769
                        $value_key = implode($value_arr, ',');
1770
                    } else {
1771
                        $value_key = '';
1772
                    }
1773
                } else if (in_array($key_type, array('price', 'double'))) {
1774
                    $value_arr = GETPOST("options_" . $key, 'alpha');
1775
                    $value_key = price2num($value_arr);
1776
                } else {
1777
                    $value_key = GETPOST("options_" . $key);
1778
                }
1779
1780
                $object->array_options["options_" . $key] = $value_key;
1781
            }
1782
1783
            if ($nofillrequired) {
1784
                Globals::$langs->load('errors');
1785
                setEventMessages(Globals::$langs->trans('ErrorFieldsRequired') . ' : ' . implode(', ', $error_field_required), null, 'errors');
1786
                return -1;
1787
            } else {
1788
                return 1;
1789
            }
1790
        } else {
1791
            return 0;
1792
        }
1793
    }
1794
1795
    /**
1796
     * return array_options array of data of extrafields value of object sent by a search form
1797
     *
1798
     * @param  array|string		$extrafieldsobjectkey  	array of extrafields (old usage) or value of object->table_element (new usage)
1799
     * @param  string			$keyprefix      		Prefix string to add into name and id of field (can be used to avoid duplicate names)
1800
     * @param  string			$keysuffix      		Suffix string to add into name and id of field (can be used to avoid duplicate names)
1801
     * @return array|int								array_options set or 0 if no value
1802
     */
1803
    function getOptionalsFromPost($extrafieldsobjectkey, $keyprefix = '', $keysuffix = '')
1804
    {
1805
        // global $_POST;
1806
1807
        if (is_string($extrafieldsobjectkey) && is_array($this->attributes[$extrafieldsobjectkey]['label'])) {
1808
            $extralabels = $this->attributes[$extrafieldsobjectkey]['label'];
1809
        } else {
1810
            $extralabels = $extrafieldsobjectkey;
1811
        }
1812
1813
        if (is_array($extralabels)) {
1814
            $array_options = array();
1815
1816
            // Get extra fields
1817
            foreach ($extralabels as $key => $value) {
1818
                $key_type = '';
1819
                if (is_string($extrafieldsobjectkey)) {
1820
                    $key_type = $this->attributes[$extrafieldsobjectkey]['type'][$key];
1821
                }
1822
1823
                if (in_array($key_type, array('date', 'datetime'))) {
1824
                    // Clean parameters
1825
                    $value_key = dol_mktime($_POST[$keysuffix . "options_" . $key . $keyprefix . "hour"], $_POST[$keysuffix . "options_" . $key . $keyprefix . "min"], 0, $_POST[$keysuffix . "options_" . $key . $keyprefix . "month"], $_POST[$keysuffix . "options_" . $key . $keyprefix . "day"], $_POST[$keysuffix . "options_" . $key . $keyprefix . "year"]);
1826
                } else if (in_array($key_type, array('checkbox', 'chkbxlst'))) {
1827
                    $value_arr = GETPOST($keysuffix . "options_" . $key . $keyprefix);
1828
                    // Make sure we get an array even if there's only one checkbox
1829
                    $value_arr = (array) $value_arr;
1830
                    $value_key = implode(',', $value_arr);
1831
                } else if (in_array($key_type, array('price', 'double'))) {
1832
                    $value_arr = GETPOST($keysuffix . "options_" . $key . $keyprefix);
1833
                    $value_key = price2num($value_arr);
1834
                } else {
1835
                    $value_key = GETPOST($keysuffix . "options_" . $key . $keyprefix);
1836
                }
1837
1838
                $array_options[$keysuffix . "options_" . $key] = $value_key; // No keyprefix here. keyprefix is used only for read.
1839
            }
1840
1841
            return $array_options;
1842
        }
1843
1844
        return 0;
1845
    }
1846
}
1847