Passed
Branch develop (f027da)
by
unknown
28:15
created

ExtraFields::update_label()   F

Complexity

Conditions 27
Paths > 20000

Size

Total Lines 121
Code Lines 96

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 27
eloc 96
nc 590080
nop 20
dl 0
loc 121
rs 0
c 0
b 0
f 0

How to fix   Long Method    Complexity    Many Parameters   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

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-2021  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 <https://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
34
35
/**
36
 *	Class to manage standard extra fields
37
 */
38
class ExtraFields
39
{
40
	/**
41
	 * @var DoliDB Database handler.
42
	 */
43
	public $db;
44
45
	/**
46
	 * @var array Array with type of the extra field
47
	 * @deprecated
48
	 */
49
	public $attribute_type;
50
51
	/**
52
	 * @var array Array with label of extra field
53
	 * @deprecated
54
	 */
55
	public $attribute_label;
56
57
	/**
58
	 * @var array Array with list of possible values for some types of extra fields
59
	 * @deprecated
60
	 */
61
	public $attribute_choice;
62
63
64
	/**
65
	 * @var array New array to store extrafields definition
66
	 */
67
	public $attributes;
68
69
	/**
70
	 * @var string Error code (or message)
71
	 */
72
	public $error = '';
73
74
	/**
75
	 * @var string[] Array of Error code (or message)
76
	 */
77
	public $errors = array();
78
79
	/**
80
	 * @var string DB Error number
81
	 */
82
	public $errno;
83
84
85
	public static $type2label = array(
86
		'varchar'=>'String1Line',
87
		'text'=>'TextLongNLines',
88
		'html'=>'HtmlText',
89
		'int'=>'Int',
90
		'double'=>'Float',
91
		'date'=>'Date',
92
		'datetime'=>'DateAndTime',
93
		'boolean'=>'Boolean',
94
		'price'=>'ExtrafieldPrice',
95
		'phone'=>'ExtrafieldPhone',
96
		'mail'=>'ExtrafieldMail',
97
		'url'=>'ExtrafieldUrl',
98
		'password' => 'ExtrafieldPassword',
99
		'select' => 'ExtrafieldSelect',
100
		'sellist' => 'ExtrafieldSelectList',
101
		'radio' => 'ExtrafieldRadio',
102
		'checkbox' => 'ExtrafieldCheckBox',
103
		'chkbxlst' => 'ExtrafieldCheckBoxFromList',
104
		'link' => 'ExtrafieldLink',
105
		'separate' => 'ExtrafieldSeparator',
106
	);
107
108
109
	/**
110
	 *	Constructor
111
	 *
112
	 *  @param		DoliDB		$db      Database handler
113
	 */
114
	public function __construct($db)
115
	{
116
		$this->db = $db;
117
		$this->error = '';
118
		$this->errors = array();
119
		$this->attributes = array();
120
121
		// For old usage
122
		$this->attribute_type = array();
123
		$this->attribute_label = array();
124
	}
125
126
	/**
127
	 *  Add a new extra field parameter
128
	 *
129
	 *  @param	string			$attrname           Code of attribute
130
	 *  @param  string			$label              label of attribute
131
	 *  @param  string			$type               Type of attribute ('boolean','int','varchar','text','html','date','datehour','price','phone','mail','password','url','select','checkbox','separate',...)
132
	 *  @param  int				$pos                Position of attribute
133
	 *  @param  string			$size               Size/length definition of attribute ('5', '24,8', ...). For float, it contains 2 numeric separated with a comma.
134
	 *  @param  string			$elementtype        Element type. Same value than object->table_element (Example 'member', 'product', 'thirdparty', ...)
135
	 *  @param	int				$unique				Is field unique or not
136
	 *  @param	int				$required			Is field required or not
137
	 *  @param	string			$default_value		Defaulted value (In database. use the default_value feature for default value on screen. Example: '', '0', 'null', 'avalue')
138
	 *  @param  array|string	$param				Params for field (ex for select list : array('options' => array(value'=>'label of option')) )
139
	 *  @param  int				$alwayseditable		Is attribute always editable regardless of the document status
140
	 *  @param	string			$perms				Permission to check
141
	 *  @param	string			$list				Visibilty ('0'=never visible, '1'=visible on list+forms, '2'=list only, '3'=form only or 'eval string')
142
	 *  @param	string			$help				Text with help tooltip
143
	 *  @param  string  		$computed           Computed value
144
	 *  @param  string  		$entity    		 	Entity of extrafields (for multicompany modules)
145
	 *  @param  string  		$langfile  		 	Language file
146
	 *  @param  string  		$enabled  		 	Condition to have the field enabled or not
147
	 *  @param	int				$totalizable		Is a measure. Must show a total on lists
148
	 *  @param  int             $printable          Is extrafield displayed on PDF
149
	 *  @return int      							<=0 if KO, >0 if OK
150
	 */
151
	public 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', $totalizable = 0, $printable = 0)
152
	{
153
		if (empty($attrname)) {
154
			return -1;
155
		}
156
		if (empty($label)) {
157
			return -1;
158
		}
159
160
		$result = 0;
161
162
		if ($type == 'separate') {
163
			$unique = 0;
164
			$required = 0;
165
		}	// Force unique and not required if this is a separator field to avoid troubles.
166
		if ($elementtype == 'thirdparty') {
167
			$elementtype = 'societe';
168
		}
169
		if ($elementtype == 'contact') {
170
			$elementtype = 'socpeople';
171
		}
172
173
		// Create field into database except for separator type which is not stored in database
174
		if ($type != 'separate') {
175
			$result = $this->create($attrname, $type, $size, $elementtype, $unique, $required, $default_value, $param, $perms, $list, $computed, $help);
176
		}
177
		$err1 = $this->errno;
178
		if ($result > 0 || $err1 == 'DB_ERROR_COLUMN_ALREADY_EXISTS' || $type == 'separate') {
179
			// Add declaration of field into table
180
			$result2 = $this->create_label($attrname, $label, $type, $pos, $size, $elementtype, $unique, $required, $param, $alwayseditable, $perms, $list, $help, $default_value, $computed, $entity, $langfile, $enabled, $totalizable, $printable);
181
			$err2 = $this->errno;
182
			if ($result2 > 0 || ($err1 == 'DB_ERROR_COLUMN_ALREADY_EXISTS' && $err2 == 'DB_ERROR_RECORD_ALREADY_EXISTS')) {
183
				$this->error = '';
184
				$this->errno = 0;
185
				return 1;
186
			} else {
187
				return -2;
188
			}
189
		} else {
190
			return -1;
191
		}
192
	}
193
194
	/**
195
	 *	Add a new optional attribute.
196
	 *  This is a private method. For public method, use addExtraField.
197
	 *
198
	 *	@param	string	$attrname			code of attribute
199
	 *  @param	int		$type				Type of attribute ('boolean', 'int', 'varchar', 'text', 'html', 'date', 'datehour','price','phone','mail','password','url','select','checkbox', ...)
200
	 *  @param	string	$length				Size/length of attribute ('5', '24,8', ...)
201
	 *  @param  string	$elementtype        Element type ('member', 'product', 'thirdparty', 'contact', ...)
202
	 *  @param	int		$unique				Is field unique or not
203
	 *  @param	int		$required			Is field required or not
204
	 *  @param  string  $default_value		Default value for field (in database)
205
	 *  @param  array	$param				Params for field  (ex for select list : array('options'=>array('value'=>'label of option'))
206
	 *  @param	string	$perms				Permission
207
	 *	@param	string	$list				Into list view by default
208
	 *  @param  string  $computed           Computed value
209
	 *  @param	string	$help				Help on tooltip
210
	 *  @return int      	           		<=0 if KO, >0 if OK
211
	 */
212
	private function create($attrname, $type = 'varchar', $length = 255, $elementtype = 'member', $unique = 0, $required = 0, $default_value = '', $param = '', $perms = '', $list = '0', $computed = '', $help = '')
213
	{
214
		if ($elementtype == 'thirdparty') {
215
			$elementtype = 'societe';
216
		}
217
		if ($elementtype == 'contact') {
218
			$elementtype = 'socpeople';
219
		}
220
221
		$table = $elementtype.'_extrafields';
222
		if ($elementtype == 'categorie') {
223
			$table = 'categories_extrafields';
224
		}
225
226
		if (!empty($attrname) && preg_match("/^\w[a-zA-Z0-9_]*$/", $attrname) && !is_numeric($attrname)) {
227
			if ($type == 'boolean') {
228
				$typedb = 'int';
229
				$lengthdb = '1';
230
			} elseif ($type == 'price') {
231
				$typedb = 'double';
232
				$lengthdb = '24,8';
233
			} elseif ($type == 'phone') {
234
				$typedb = 'varchar';
235
				$lengthdb = '20';
236
			} elseif ($type == 'mail') {
237
				$typedb = 'varchar';
238
				$lengthdb = '128';
239
			} elseif ($type == 'url') {
240
				$typedb = 'varchar';
241
				$lengthdb = '255';
242
			} elseif (($type == 'select') || ($type == 'sellist') || ($type == 'radio') || ($type == 'checkbox') || ($type == 'chkbxlst')) {
243
				$typedb = 'varchar';
244
				$lengthdb = '255';
245
			} elseif ($type == 'link') {
246
				$typedb = 'int';
247
				$lengthdb = '11';
248
			} elseif ($type == 'html') {
249
				$typedb = 'text';
250
				$lengthdb = $length;
251
			} elseif ($type == 'password') {
252
				$typedb = 'varchar';
253
				$lengthdb = '128';
254
			} else {
255
				$typedb = $type;
256
				$lengthdb = $length;
257
				if ($type == 'varchar' && empty($lengthdb)) {
258
					$lengthdb = '255';
259
				}
260
			}
261
			$field_desc = array(
262
				'type'=>$typedb,
263
				'value'=>$lengthdb,
264
				'null'=>($required ? 'NOT NULL' : 'NULL'),
265
				'default' => $default_value
266
			);
267
268
			$result = $this->db->DDLAddField(MAIN_DB_PREFIX.$table, $attrname, $field_desc);
269
			if ($result > 0) {
270
				if ($unique) {
271
					$sql = "ALTER TABLE ".MAIN_DB_PREFIX.$table." ADD UNIQUE INDEX uk_".$table."_".$attrname." (".$attrname.")";
272
					$resql = $this->db->query($sql, 1, 'dml');
273
				}
274
				return 1;
275
			} else {
276
				$this->error = $this->db->lasterror();
277
				$this->errno = $this->db->lasterrno();
278
				return -1;
279
			}
280
		} else {
281
			return 0;
282
		}
283
	}
284
285
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
286
	/**
287
	 *	Add description of a new optional attribute
288
	 *
289
	 *	@param	string			$attrname		code of attribute
290
	 *	@param	string			$label			label of attribute
291
	 *  @param	int				$type			Type of attribute ('int', 'varchar', 'text', 'html', 'date', 'datehour', 'float')
292
	 *  @param	int				$pos			Position of attribute
293
	 *  @param	string			$size			Size/length of attribute ('5', '24,8', ...)
294
	 *  @param  string			$elementtype	Element type ('member', 'product', 'thirdparty', ...)
295
	 *  @param	int				$unique			Is field unique or not
296
	 *  @param	int				$required		Is field required or not
297
	 *  @param  array|string	$param			Params for field  (ex for select list : array('options' => array(value'=>'label of option')) )
298
	 *  @param  int				$alwayseditable	Is attribute always editable regardless of the document status
299
	 *  @param	string			$perms			Permission to check
300
	 *  @param	string			$list			Visibily
301
	 *  @param	string			$help			Help on tooltip
302
	 *  @param  string          $default        Default value (in database. use the default_value feature for default value on screen).
303
	 *  @param  string          $computed       Computed value
304
	 *  @param  string          $entity     	Entity of extrafields
305
	 *  @param	string			$langfile		Language file
306
	 *  @param  string  		$enabled  		Condition to have the field enabled or not
307
	 *  @param	int				$totalizable	Is a measure. Must show a total on lists
308
	 *  @param  int             $printable        Is extrafield displayed on PDF
309
	 *  @return	int								<=0 if KO, >0 if OK
310
	 *  @throws Exception
311
	 */
312
	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', $totalizable = 0, $printable = 0)
313
	{
314
		// phpcs:enable
315
		global $conf, $user;
316
317
		if ($elementtype == 'thirdparty') {
318
			$elementtype = 'societe';
319
		}
320
		if ($elementtype == 'contact') {
321
			$elementtype = 'socpeople';
322
		}
323
324
		// Clean parameters
325
		if (empty($pos)) {
326
			$pos = 0;
327
		}
328
		if (empty($list)) {
329
			$list = '0';
330
		}
331
		if (empty($required)) {
332
			$required = 0;
333
		}
334
		if (empty($unique)) {
335
			$unique = 0;
336
		}
337
		if (empty($printable)) {
338
			$printable = 0;
339
		}
340
		if (empty($alwayseditable)) {
341
			$alwayseditable = 0;
342
		}
343
		if (empty($totalizable)) {
344
			$totalizable = 0;
345
		}
346
347
		if (!empty($attrname) && preg_match("/^\w[a-zA-Z0-9-_]*$/", $attrname) && !is_numeric($attrname)) {
348
			if (is_array($param) && count($param) > 0) {
349
				$params = serialize($param);
350
			} elseif (strlen($param) > 0) {
351
				$params = trim($param);
352
			} else {
353
				$params = '';
354
			}
355
356
			$sql = "INSERT INTO ".MAIN_DB_PREFIX."extrafields(";
357
			$sql .= " name,";
358
			$sql .= " label,";
359
			$sql .= " type,";
360
			$sql .= " pos,";
361
			$sql .= " size,";
362
			$sql .= " entity,";
363
			$sql .= " elementtype,";
364
			$sql .= " fieldunique,";
365
			$sql .= " fieldrequired,";
366
			$sql .= " param,";
367
			$sql .= " alwayseditable,";
368
			$sql .= " perms,";
369
			$sql .= " langs,";
370
			$sql .= " list,";
371
			$sql .= " printable,";
372
			$sql .= " fielddefault,";
373
			$sql .= " fieldcomputed,";
374
			$sql .= " fk_user_author,";
375
			$sql .= " fk_user_modif,";
376
			$sql .= " datec,";
377
			$sql .= " enabled,";
378
			$sql .= " help,";
379
			$sql .= " totalizable";
380
			$sql .= " )";
381
			$sql .= " VALUES('".$this->db->escape($attrname)."',";
382
			$sql .= " '".$this->db->escape($label)."',";
383
			$sql .= " '".$this->db->escape($type)."',";
384
			$sql .= " ".((int) $pos).",";
385
			$sql .= " '".$this->db->escape($size)."',";
386
			$sql .= " ".($entity === '' ? $conf->entity : $entity).",";
387
			$sql .= " '".$this->db->escape($elementtype)."',";
388
			$sql .= " ".((int) $unique).",";
389
			$sql .= " ".((int) $required).",";
390
			$sql .= " '".$this->db->escape($params)."',";
391
			$sql .= " ".((int) $alwayseditable).",";
392
			$sql .= " ".($perms ? "'".$this->db->escape($perms)."'" : "null").",";
393
			$sql .= " ".($langfile ? "'".$this->db->escape($langfile)."'" : "null").",";
394
			$sql .= " '".$this->db->escape($list)."',";
395
			$sql .= " '".$this->db->escape($printable)."',";
396
			$sql .= " ".($default ? "'".$this->db->escape($default)."'" : "null").",";
397
			$sql .= " ".($computed ? "'".$this->db->escape($computed)."'" : "null").",";
398
			$sql .= " ".(is_object($user) ? $user->id : 0).",";
399
			$sql .= " ".(is_object($user) ? $user->id : 0).",";
400
			$sql .= "'".$this->db->idate(dol_now())."',";
401
			$sql .= " ".($enabled ? "'".$this->db->escape($enabled)."'" : "1").",";
402
			$sql .= " ".($help ? "'".$this->db->escape($help)."'" : "null").",";
403
			$sql .= " ".($totalizable ? 'TRUE' : 'FALSE');
404
			$sql .= ')';
405
406
			dol_syslog(get_class($this)."::create_label", LOG_DEBUG);
407
			if ($this->db->query($sql)) {
408
				return 1;
409
			} else {
410
				$this->error = $this->db->lasterror();
411
				$this->errno = $this->db->lasterrno();
412
				return -1;
413
			}
414
		}
415
	}
416
417
	/**
418
	 *	Delete an optional attribute
419
	 *
420
	 *	@param	string	$attrname		Code of attribute to delete
421
	 *  @param  string	$elementtype    Element type ('member', 'product', 'thirdparty', 'contact', ...)
422
	 *  @return int              		< 0 if KO, 0 if nothing is done, 1 if OK
423
	 */
424
	public function delete($attrname, $elementtype = 'member')
425
	{
426
		if ($elementtype == 'thirdparty') {
427
			$elementtype = 'societe';
428
		}
429
		if ($elementtype == 'contact') {
430
			$elementtype = 'socpeople';
431
		}
432
433
		$table = $elementtype.'_extrafields';
434
		if ($elementtype == 'categorie') {
435
			$table = 'categories_extrafields';
436
		}
437
438
		$error = 0;
439
440
		if (!empty($attrname) && preg_match("/^\w[a-zA-Z0-9-_]*$/", $attrname)) {
441
			$result = $this->delete_label($attrname, $elementtype);
442
			if ($result < 0) {
443
				$this->error = $this->db->lasterror();
444
				$this->errors[] = $this->db->lasterror();
445
				$error++;
446
			}
447
448
			if (!$error) {
449
				$sql = "SELECT COUNT(rowid) as nb";
450
				$sql .= " FROM ".MAIN_DB_PREFIX."extrafields";
451
				$sql .= " WHERE elementtype = '".$this->db->escape($elementtype)."'";
452
				$sql .= " AND name = '".$this->db->escape($attrname)."'";
453
				//$sql.= " AND entity IN (0,".$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
454
				$resql = $this->db->query($sql);
455
				if ($resql) {
456
					$obj = $this->db->fetch_object($resql);
457
					if ($obj->nb <= 0) {
458
						$result = $this->db->DDLDropField(MAIN_DB_PREFIX.$table, $attrname); // This also drop the unique key
459
						if ($result < 0) {
460
							$this->error = $this->db->lasterror();
461
							$this->errors[] = $this->db->lasterror();
462
							$error++;
463
						}
464
					}
465
				}
466
			}
467
468
			return $result;
469
		} else {
470
			return 0;
471
		}
472
	}
473
474
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
475
	/**
476
	 *	Delete description of an optional attribute
477
	 *
478
	 *	@param	string	$attrname			Code of attribute to delete
479
	 *  @param  string	$elementtype        Element type ('member', 'product', 'thirdparty', ...)
480
	 *  @return int              			< 0 if KO, 0 if nothing is done, 1 if OK
481
	 */
482
	private function delete_label($attrname, $elementtype = 'member')
483
	{
484
		// phpcs:enable
485
		global $conf;
486
487
		if ($elementtype == 'thirdparty') {
488
			$elementtype = 'societe';
489
		}
490
		if ($elementtype == 'contact') {
491
			$elementtype = 'socpeople';
492
		}
493
494
		if (isset($attrname) && $attrname != '' && preg_match("/^\w[a-zA-Z0-9-_]*$/", $attrname)) {
495
			$sql = "DELETE FROM ".MAIN_DB_PREFIX."extrafields";
496
			$sql .= " WHERE name = '".$this->db->escape($attrname)."'";
497
			$sql .= " AND entity IN  (0,".$conf->entity.')';
498
			$sql .= " AND elementtype = '".$this->db->escape($elementtype)."'";
499
500
			dol_syslog(get_class($this)."::delete_label", LOG_DEBUG);
501
			$resql = $this->db->query($sql);
502
			if ($resql) {
503
				return 1;
504
			} else {
505
				dol_print_error($this->db);
506
				return -1;
507
			}
508
		} else {
509
			return 0;
510
		}
511
	}
512
513
	/**
514
	 * 	Modify type of a personalized attribute
515
	 *
516
	 *  @param	string	$attrname			Name of attribute
517
	 *  @param	string	$label				Label of attribute
518
	 *  @param	string	$type				Type of attribute ('boolean', 'int', 'varchar', 'text', 'html', 'date', 'datehour','price','phone','mail','password','url','select','checkbox', ...)
519
	 *  @param	int		$length				Length of attribute
520
	 *  @param  string	$elementtype        Element type ('member', 'product', 'thirdparty', 'contact', ...)
521
	 *  @param	int		$unique				Is field unique or not
522
	 *  @param	int		$required			Is field required or not
523
	 *  @param	int		$pos				Position of attribute
524
	 *  @param  array	$param				Params for field (ex for select list : array('options' => array(value'=>'label of option')) )
525
	 *  @param  int		$alwayseditable		Is attribute always editable regardless of the document status
526
	 *  @param	string	$perms				Permission to check
527
	 *  @param	string	$list				Visibility
528
	 *  @param	string	$help				Help on tooltip
529
	 *  @param  string  $default            Default value (in database. use the default_value feature for default value on screen).
530
	 *  @param  string  $computed           Computed value
531
	 *  @param  string  $entity	            Entity of extrafields
532
	 *  @param	string	$langfile			Language file
533
	 *  @param  string  $enabled  			Condition to have the field enabled or not
534
	 *  @param  int     $totalizable        Is extrafield totalizable on list
535
	 *  @param  int     $printable        Is extrafield displayed on PDF
536
	 * 	@return	int							>0 if OK, <=0 if KO
537
	 *  @throws Exception
538
	 */
539
	public 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, $printable = 0)
540
	{
541
		global $hookmanager;
542
543
		if ($elementtype == 'thirdparty') {
544
			$elementtype = 'societe';
545
		}
546
		if ($elementtype == 'contact') {
547
			$elementtype = 'socpeople';
548
		}
549
550
		$table = $elementtype.'_extrafields';
551
		if ($elementtype == 'categorie') {
552
			$table = 'categories_extrafields';
553
		}
554
555
		if (isset($attrname) && $attrname != '' && preg_match("/^\w[a-zA-Z0-9-_]*$/", $attrname)) {
556
			if ($type == 'boolean') {
557
				$typedb = 'int';
558
				$lengthdb = '1';
559
			} elseif ($type == 'price') {
560
				$typedb = 'double';
561
				$lengthdb = '24,8';
562
			} elseif ($type == 'phone') {
563
				$typedb = 'varchar';
564
				$lengthdb = '20';
565
			} elseif ($type == 'mail') {
566
				$typedb = 'varchar';
567
				$lengthdb = '128';
568
			} elseif ($type == 'url') {
569
				$typedb = 'varchar';
570
				$lengthdb = '255';
571
			} elseif (($type == 'select') || ($type == 'sellist') || ($type == 'radio') || ($type == 'checkbox') || ($type == 'chkbxlst')) {
572
				$typedb = 'varchar';
573
				$lengthdb = '255';
574
			} elseif ($type == 'html') {
575
				$typedb = 'text';
576
			} elseif ($type == 'link') {
577
				$typedb = 'int';
578
				$lengthdb = '11';
579
			} elseif ($type == 'password') {
580
				$typedb = 'varchar';
581
				$lengthdb = '50';
582
			} else {
583
				$typedb = $type;
584
				$lengthdb = $length;
585
			}
586
			$field_desc = array('type'=>$typedb, 'value'=>$lengthdb, 'null'=>($required ? 'NOT NULL' : 'NULL'), 'default'=>$default);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $lengthdb does not seem to be defined for all execution paths leading up to this point.
Loading history...
587
588
			if (is_object($hookmanager)) {
589
				$hookmanager->initHooks(array('extrafieldsdao'));
590
				$parameters = array('field_desc'=>&$field_desc, 'table'=>$table, 'attr_name'=>$attrname, 'label'=>$label, 'type'=>$type, 'length'=>$length, 'unique'=>$unique, 'required'=>$required, 'pos'=>$pos, 'param'=>$param, 'alwayseditable'=>$alwayseditable, 'perms'=>$perms, 'list'=>$list, 'help'=>$help, 'default'=>$default, 'computed'=>$computed, 'entity'=>$entity, 'langfile'=>$langfile, 'enabled'=>$enabled, 'totalizable'=>$totalizable, 'printable'=>$printable);
591
				$reshook = $hookmanager->executeHooks('updateExtrafields', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $action seems to be never defined.
Loading history...
592
593
				if ($reshook < 0) {
594
					$this->error = $this->db->lasterror();
595
					return -1;
596
				}
597
			}
598
599
			if ($type != 'separate') { // No table update when separate type
600
				$result = $this->db->DDLUpdateField(MAIN_DB_PREFIX.$table, $attrname, $field_desc);
601
			}
602
			if ($result > 0 || $type == 'separate') {
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $result does not seem to be defined for all execution paths leading up to this point.
Loading history...
603
				if ($label) {
604
					$result = $this->update_label($attrname, $label, $type, $length, $elementtype, $unique, $required, $pos, $param, $alwayseditable, $perms, $list, $help, $default, $computed, $entity, $langfile, $enabled, $totalizable, $printable);
605
				}
606
				if ($result > 0) {
607
					$sql = '';
608
					if ($unique) {
609
						$sql = "ALTER TABLE ".MAIN_DB_PREFIX.$table." ADD UNIQUE INDEX uk_".$table."_".$attrname." (".$attrname.")";
610
					} else {
611
						$sql = "ALTER TABLE ".MAIN_DB_PREFIX.$table." DROP INDEX uk_".$table."_".$attrname;
612
					}
613
					dol_syslog(get_class($this).'::update', LOG_DEBUG);
614
					$resql = $this->db->query($sql, 1, 'dml');
615
					return 1;
616
				} else {
617
					$this->error = $this->db->lasterror();
618
					return -1;
619
				}
620
			} else {
621
				$this->error = $this->db->lasterror();
622
				return -1;
623
			}
624
		} else {
625
			return 0;
626
		}
627
	}
628
629
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
630
	/**
631
	 *  Modify description of personalized attribute
632
	 *
633
	 *  @param	string	$attrname			Name of attribute
634
	 *  @param	string	$label				Label of attribute
635
	 *  @param  string	$type               Type of attribute
636
	 *  @param  int		$size		        Length of attribute
637
	 *  @param  string	$elementtype		Element type ('member', 'product', 'thirdparty', ...)
638
	 *  @param	int		$unique				Is field unique or not
639
	 *  @param	int		$required			Is field required or not
640
	 *  @param	int		$pos				Position of attribute
641
	 *  @param  array	$param				Params for field  (ex for select list : array('options' => array(value'=>'label of option')) )
642
	 *  @param  int		$alwayseditable		Is attribute always editable regardless of the document status
643
	 *  @param	string	$perms				Permission to check
644
	 *  @param	string	$list				Visiblity
645
	 *  @param	string	$help				Help on tooltip.
646
	 *  @param  string  $default            Default value (in database. use the default_value feature for default value on screen).
647
	 *  @param  string  $computed           Computed value
648
	 *  @param  string  $entity     		Entity of extrafields
649
	 *  @param	string	$langfile			Language file
650
	 *  @param  string  $enabled  			Condition to have the field enabled or not
651
	 *  @param  int     $totalizable        Is extrafield totalizable on list
652
	 *  @param  int     $printable        Is extrafield displayed on PDF
653
	 *  @return	int							<=0 if KO, >0 if OK
654
	 *  @throws Exception
655
	 */
656
	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, $printable = 0)
657
	{
658
		// phpcs:enable
659
		global $conf, $user;
660
		dol_syslog(get_class($this)."::update_label ".$attrname.", ".$label.", ".$type.", ".$size.", ".$elementtype.", ".$unique.", ".$required.", ".$pos.", ".$alwayseditable.", ".$perms.", ".$list.", ".$default.", ".$computed.", ".$entity.", ".$langfile.", ".$enabled.", ".$totalizable.", ".$printable);
661
662
		// Clean parameters
663
		if ($elementtype == 'thirdparty') {
664
			$elementtype = 'societe';
665
		}
666
		if ($elementtype == 'contact') {
667
			$elementtype = 'socpeople';
668
		}
669
670
		if (empty($pos)) {
671
			$pos = 0;
672
		}
673
		if (empty($list)) {
674
			$list = '0';
675
		}
676
		if (empty($totalizable)) {
677
			$totalizable = 0;
678
		}
679
		if (empty($required)) {
680
			$required = 0;
681
		}
682
		if (empty($unique)) {
683
			$unique = 0;
684
		}
685
		if (empty($alwayseditable)) {
686
			$alwayseditable = 0;
687
		}
688
689
		if (isset($attrname) && $attrname != '' && preg_match("/^\w[a-zA-Z0-9-_]*$/", $attrname)) {
690
			$this->db->begin();
691
692
			if (is_array($param) && count($param) > 0) {
693
				$params = serialize($param);
694
			} elseif (strlen($param) > 0) {
695
				$params = trim($param);
696
			} else {
697
				$params = '';
698
			}
699
700
			if ($entity === '' || $entity != '0') {
701
				// We dont want on all entities, we delete all and current
702
				$sql_del = "DELETE FROM ".MAIN_DB_PREFIX."extrafields";
703
				$sql_del .= " WHERE name = '".$this->db->escape($attrname)."'";
704
				$sql_del .= " AND entity IN (0, ".($entity === '' ? $conf->entity : $entity).")";
705
				$sql_del .= " AND elementtype = '".$this->db->escape($elementtype)."'";
706
			} else {
707
				// We want on all entities ($entities = '0'), we delete on all only (we keep setup specific to each entity)
708
				$sql_del = "DELETE FROM ".MAIN_DB_PREFIX."extrafields";
709
				$sql_del .= " WHERE name = '".$this->db->escape($attrname)."'";
710
				$sql_del .= " AND entity = 0";
711
				$sql_del .= " AND elementtype = '".$this->db->escape($elementtype)."'";
712
			}
713
			$resql1 = $this->db->query($sql_del);
714
715
			$sql = "INSERT INTO ".MAIN_DB_PREFIX."extrafields(";
716
			$sql .= " name,"; // This is code
717
			$sql .= " entity,";
718
			$sql .= " label,";
719
			$sql .= " type,";
720
			$sql .= " size,";
721
			$sql .= " elementtype,";
722
			$sql .= " fieldunique,";
723
			$sql .= " fieldrequired,";
724
			$sql .= " perms,";
725
			$sql .= " langs,";
726
			$sql .= " pos,";
727
			$sql .= " alwayseditable,";
728
			$sql .= " param,";
729
			$sql .= " list,";
730
			$sql .= " printable,";
731
			$sql .= " totalizable,";
732
			$sql .= " fielddefault,";
733
			$sql .= " fieldcomputed,";
734
			$sql .= " fk_user_author,";
735
			$sql .= " fk_user_modif,";
736
			$sql .= " datec,";
737
			$sql .= " enabled,";
738
			$sql .= " help";
739
			$sql .= ") VALUES (";
740
			$sql .= "'".$this->db->escape($attrname)."',";
741
			$sql .= " ".($entity === '' ? $conf->entity : $entity).",";
742
			$sql .= " '".$this->db->escape($label)."',";
743
			$sql .= " '".$this->db->escape($type)."',";
744
			$sql .= " '".$this->db->escape($size)."',";
745
			$sql .= " '".$this->db->escape($elementtype)."',";
746
			$sql .= " ".$unique.",";
747
			$sql .= " ".$required.",";
748
			$sql .= " ".($perms ? "'".$this->db->escape($perms)."'" : "null").",";
749
			$sql .= " ".($langfile ? "'".$this->db->escape($langfile)."'" : "null").",";
750
			$sql .= " ".$pos.",";
751
			$sql .= " '".$this->db->escape($alwayseditable)."',";
752
			$sql .= " '".$this->db->escape($params)."',";
753
			$sql .= " '".$this->db->escape($list)."', ";
754
			$sql .= " '".$this->db->escape($printable)."', ";
755
			$sql .= " ".($totalizable ? 'TRUE' : 'FALSE').",";
756
			$sql .= " ".(($default != '') ? "'".$this->db->escape($default)."'" : "null").",";
757
			$sql .= " ".($computed ? "'".$this->db->escape($computed)."'" : "null").",";
758
			$sql .= " ".$user->id.",";
759
			$sql .= " ".$user->id.",";
760
			$sql .= "'".$this->db->idate(dol_now())."',";
761
			$sql .= "'".$this->db->escape($enabled)."',";
762
			$sql .= " ".($help ? "'".$this->db->escape($help)."'" : "null");
763
			$sql .= ")";
764
765
			$resql2 = $this->db->query($sql);
766
767
			if ($resql1 && $resql2) {
768
				$this->db->commit();
769
				return 1;
770
			} else {
771
				$this->db->rollback();
772
				dol_print_error($this->db);
773
				return -1;
774
			}
775
		} else {
776
			return 0;
777
		}
778
	}
779
780
781
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
782
	/**
783
	 * 	Load array this->attributes (and some old this->attribute_xxx like attribute_label, attribute_type, ...
784
	 *
785
	 * 	@param	string		$elementtype		Type of element ('' = all or $object->table_element like 'adherent', 'commande', 'thirdparty', 'facture', 'propal', 'product', ...).
786
	 * 	@param	boolean		$forceload			Force load of extra fields whatever is status of cache.
787
	 * 	@return	array							Array of attributes keys+label for all extra fields.
788
	 */
789
	public function fetch_name_optionals_label($elementtype, $forceload = false)
790
	{
791
		// phpcs:enable
792
		global $conf;
793
794
		if (empty($elementtype)) {
795
			return array();
796
		}
797
798
		if ($elementtype == 'thirdparty') {
799
			$elementtype = 'societe';
800
		}
801
		if ($elementtype == 'contact') {
802
			$elementtype = 'socpeople';
803
		}
804
		if ($elementtype == 'order_supplier') {
805
			$elementtype = 'commande_fournisseur';
806
		}
807
		if ($elementtype == 'stock_mouvement') {
808
			$elementtype = 'movement';
809
		}
810
811
		$array_name_label = array();
812
813
		// We should not have several time this request. If we have, there is some optimization to do by calling a simple $extrafields->fetch_optionals() in top of code and not into subcode
814
		$sql = "SELECT rowid, name, label, type, size, elementtype, fieldunique, fieldrequired, param, pos, alwayseditable, perms, langs, list, printable, totalizable, fielddefault, fieldcomputed, entity, enabled, help";
815
		$sql .= " FROM ".MAIN_DB_PREFIX."extrafields";
816
		//$sql.= " WHERE entity IN (0,".$conf->entity.")";    // Filter is done later
817
		if ($elementtype) {
818
			$sql .= " WHERE elementtype = '".$this->db->escape($elementtype)."'"; // Filed with object->table_element
819
		}
820
		$sql .= " ORDER BY pos";
821
822
		$resql = $this->db->query($sql);
823
		if ($resql) {
824
			if ($this->db->num_rows($resql)) {
825
				while ($tab = $this->db->fetch_object($resql)) {
826
					if ($tab->entity != 0 && $tab->entity != $conf->entity) {
827
						// This field is not in current entity. We discard but before we save it into the array of mandatory fields if it is a mandatory field without default value
828
						if ($tab->fieldrequired && is_null($tab->fielddefault)) {
829
							$this->attributes[$tab->elementtype]['mandatoryfieldsofotherentities'][$tab->name] = $tab->type;
830
						}
831
						continue;
832
					}
833
834
					// We can add this attribute to object. TODO Remove this and return $this->attributes[$elementtype]['label']
835
					if ($tab->type != 'separate') {
836
						$array_name_label[$tab->name] = $tab->label;
837
					}
838
839
					// Old usage
840
					$this->attribute_type[$tab->name] = $tab->type;
841
					$this->attribute_label[$tab->name] = $tab->label;
842
843
					// New usage
844
					$this->attributes[$tab->elementtype]['type'][$tab->name] = $tab->type;
845
					$this->attributes[$tab->elementtype]['label'][$tab->name] = $tab->label;
846
					$this->attributes[$tab->elementtype]['size'][$tab->name] = $tab->size;
847
					$this->attributes[$tab->elementtype]['elementtype'][$tab->name] = $tab->elementtype;
848
					$this->attributes[$tab->elementtype]['default'][$tab->name] = $tab->fielddefault;
849
					$this->attributes[$tab->elementtype]['computed'][$tab->name] = $tab->fieldcomputed;
850
					$this->attributes[$tab->elementtype]['unique'][$tab->name] = $tab->fieldunique;
851
					$this->attributes[$tab->elementtype]['required'][$tab->name] = $tab->fieldrequired;
852
					$this->attributes[$tab->elementtype]['param'][$tab->name] = ($tab->param ? jsonOrUnserialize($tab->param) : '');
853
					$this->attributes[$tab->elementtype]['pos'][$tab->name] = $tab->pos;
854
					$this->attributes[$tab->elementtype]['alwayseditable'][$tab->name] = $tab->alwayseditable;
855
					$this->attributes[$tab->elementtype]['perms'][$tab->name] = (strlen($tab->perms) == 0 ? 1 : $tab->perms);
856
					$this->attributes[$tab->elementtype]['langfile'][$tab->name] = $tab->langs;
857
					$this->attributes[$tab->elementtype]['list'][$tab->name] = $tab->list;
858
					$this->attributes[$tab->elementtype]['printable'][$tab->name] = $tab->printable;
859
					$this->attributes[$tab->elementtype]['totalizable'][$tab->name] = ($tab->totalizable ? 1 : 0);
860
					$this->attributes[$tab->elementtype]['entityid'][$tab->name] = $tab->entity;
861
					$this->attributes[$tab->elementtype]['enabled'][$tab->name] = $tab->enabled;
862
					$this->attributes[$tab->elementtype]['help'][$tab->name] = $tab->help;
863
864
					$this->attributes[$tab->elementtype]['loaded'] = 1;
865
				}
866
			}
867
			if ($elementtype) {
868
				$this->attributes[$elementtype]['loaded'] = 1; // If nothing found, we also save tag 'loaded'
869
			}
870
		} else {
871
			$this->error = $this->db->lasterror();
872
			dol_syslog(get_class($this)."::fetch_name_optionals_label ".$this->error, LOG_ERR);
873
		}
874
875
		return $array_name_label;
876
	}
877
878
879
	/**
880
	 * Return HTML string to put an input field into a page
881
	 * Code very similar with showInputField of common object
882
	 *
883
	 * @param  string        $key            		Key of attribute
884
	 * @param  string|array  $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); for dates in filter mode, a range array('start'=><timestamp>, 'end'=><timestamp>) should be provided
885
	 * @param  string        $moreparam      		To add more parameters on html input tag
886
	 * @param  string        $keysuffix      		Prefix string to add after name and id of field (can be used to avoid duplicate names)
887
	 * @param  string        $keyprefix      		Suffix string to add before name and id of field (can be used to avoid duplicate names)
888
	 * @param  string        $morecss        		More css (to defined size of field. Old behaviour: may also be a numeric)
889
	 * @param  int           $objectid       		Current object id
890
	 * @param  string        $extrafieldsobjectkey	If defined (for example $object->table_element), use the new method to get extrafields data
891
	 * @param  string        $mode                  1=Used for search filters
892
	 * @return string
893
	 */
894
	public function showInputField($key, $value, $moreparam = '', $keysuffix = '', $keyprefix = '', $morecss = '', $objectid = 0, $extrafieldsobjectkey = '', $mode = 0)
895
	{
896
		global $conf, $langs, $form;
897
898
		if (!is_object($form)) {
899
			require_once DOL_DOCUMENT_ROOT.'/core/class/html.form.class.php';
900
			$form = new Form($this->db);
901
		}
902
903
		$out = '';
904
905
		if (!preg_match('/options_$/', $keyprefix)) {	// Because we work on extrafields, we add 'options_' to prefix if not already added
906
			$keyprefix = $keyprefix.'options_';
907
		}
908
909
		if (!empty($extrafieldsobjectkey)) {
910
			$label = $this->attributes[$extrafieldsobjectkey]['label'][$key];
911
			$type = $this->attributes[$extrafieldsobjectkey]['type'][$key];
912
			$size = $this->attributes[$extrafieldsobjectkey]['size'][$key];
913
			$default = $this->attributes[$extrafieldsobjectkey]['default'][$key];
914
			$computed = $this->attributes[$extrafieldsobjectkey]['computed'][$key];
915
			$unique = $this->attributes[$extrafieldsobjectkey]['unique'][$key];
916
			$required = $this->attributes[$extrafieldsobjectkey]['required'][$key];
917
			$param = $this->attributes[$extrafieldsobjectkey]['param'][$key];
918
			$perms = dol_eval($this->attributes[$extrafieldsobjectkey]['perms'][$key], 1);
919
			$langfile = $this->attributes[$extrafieldsobjectkey]['langfile'][$key];
920
			$list = dol_eval($this->attributes[$extrafieldsobjectkey]['list'][$key], 1);
921
			$totalizable = $this->attributes[$extrafieldsobjectkey]['totalizable'][$key];
922
			$help = $this->attributes[$extrafieldsobjectkey]['help'][$key];
923
			$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)
924
		} else {
925
			// Old usage
926
			$label = $this->attribute_label[$key];
927
			$type = $this->attribute_type[$key];
928
			$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)
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $list seems to never exist and therefore empty should always be true.
Loading history...
929
		}
930
931
		if ($computed) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $computed does not seem to be defined for all execution paths leading up to this point.
Loading history...
932
			if (!preg_match('/^search_/', $keyprefix)) {
933
				return '<span class="opacitymedium">'.$langs->trans("AutomaticallyCalculated").'</span>';
934
			} else {
935
				return '';
936
			}
937
		}
938
939
		if (empty($morecss)) {
940
			if ($type == 'date') {
941
				$morecss = 'minwidth100imp';
942
			} elseif ($type == 'datetime' || $type == 'link') {
943
				$morecss = 'minwidth200imp';
944
			} elseif (in_array($type, array('int', 'integer', 'double', 'price'))) {
945
				$morecss = 'maxwidth75';
946
			} elseif ($type == 'password') {
947
				$morecss = 'maxwidth100';
948
			} elseif ($type == 'url') {
949
				$morecss = 'minwidth400';
950
			} elseif ($type == 'boolean') {
951
				$morecss = '';
952
			} else {
953
				if (empty($size) || round($size) < 12) {
954
					$morecss = 'minwidth100';
955
				} elseif (round($size) <= 48) {
956
					$morecss = 'minwidth200';
957
				} else {
958
					$morecss = 'minwidth400';
959
				}
960
			}
961
		}
962
963
		if (in_array($type, array('date'))) {
964
			$tmp = explode(',', $size);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $size does not seem to be defined for all execution paths leading up to this point.
Loading history...
965
			$newsize = $tmp[0];
966
			$showtime = 0;
967
968
			// Do not show current date when field not required (see selectDate() method)
969
			if (!$required && $value == '') {
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $required does not seem to be defined for all execution paths leading up to this point.
Loading history...
970
				$value = '-1';
971
			}
972
973
			if ($mode == 1) {
974
				// search filter on a date extrafield shows two inputs to select a date range
975
				$prefill = array(
976
					'start' => isset($value['start']) ? $value['start'] : '',
977
					'end'   => isset($value['end'])   ? $value['end']   : ''
978
				);
979
				$out = '<div ' . ($moreparam ? $moreparam : '') . '><div class="nowrap">';
980
				$out .= $form->selectDate($prefill['start'], $keyprefix.$key.$keysuffix.'_start', 0, 0, 1, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans("From"));
981
				$out .= '</div><div class="nowrap">';
982
				$out .= $form->selectDate($prefill['end'], $keyprefix.$key.$keysuffix.'_end', 0, 0, 1, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans("to"));
983
				$out .= '</div></div>';
984
			} else {
985
				// TODO Must also support $moreparam
986
				$out = $form->selectDate($value, $keyprefix.$key.$keysuffix, $showtime, $showtime, $required, '', 1, (($keyprefix != 'search_' && $keyprefix != 'search_options_') ? 1 : 0), 0, 1);
987
			}
988
		} elseif (in_array($type, array('datetime'))) {
989
			$tmp = explode(',', $size);
990
			$newsize = $tmp[0];
991
			$showtime = 1;
992
993
			// Do not show current date when field not required (see selectDate() method)
994
			if (!$required && $value == '') {
995
				$value = '-1';
996
			}
997
998
			if ($mode == 1) {
999
				// search filter on a date extrafield shows two inputs to select a date range
1000
				$prefill = array(
1001
					'start' => isset($value['start']) ? $value['start'] : '',
1002
					'end'   => isset($value['end'])   ? $value['end']   : ''
1003
				);
1004
				$out = '<div ' . ($moreparam ? $moreparam : '') . '><div class="nowrap">';
1005
				$out .= $form->selectDate($prefill['start'], $keyprefix.$key.$keysuffix.'_start', 1, 1, 1, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans("From"), 'tzuserrel');
1006
				$out .= '</div><div class="nowrap">';
1007
				$out .= $form->selectDate($prefill['end'], $keyprefix.$key.$keysuffix.'_end', 1, 1, 1, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans("to"), 'tzuserrel');
1008
				$out .= '</div></div>';
1009
			} else {
1010
				// TODO Must also support $moreparam
1011
				$out = $form->selectDate($value, $keyprefix.$key.$keysuffix, $showtime, $showtime, $required, '', 1, (($keyprefix != 'search_' && $keyprefix != 'search_options_') ? 1 : 0), 0, 1, '', '', '', 1, '', '', 'tzuserrel');
1012
			}
1013
		} elseif (in_array($type, array('int', 'integer')))	{
1014
			$tmp = explode(',', $size);
1015
			$newsize = $tmp[0];
1016
			$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 : '').'>';
1017
		} elseif (preg_match('/varchar/', $type)) {
1018
			$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 : '').'>';
1019
		} elseif (in_array($type, array('mail', 'phone', 'url'))) {
1020
			$out = '<input type="text" class="flat '.$morecss.' maxwidthonsmartphone" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" value="'.dol_escape_htmltag($value).'" '.($moreparam ? $moreparam : '').'>';
1021
		} elseif ($type == 'text') {
1022
			if (!preg_match('/search_/', $keyprefix)) {		// If keyprefix is search_ or search_options_, we must just use a simple text field
1023
				require_once DOL_DOCUMENT_ROOT.'/core/class/doleditor.class.php';
1024
				$doleditor = new DolEditor($keyprefix.$key.$keysuffix, $value, '', 200, 'dolibarr_notes', 'In', false, false, false, ROWS_5, '90%');
1025
				$out = $doleditor->Create(1);
1026
			} else {
1027
				$out = '<input type="text" class="flat '.$morecss.' maxwidthonsmartphone" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" value="'.dol_escape_htmltag($value).'" '.($moreparam ? $moreparam : '').'>';
1028
			}
1029
		} elseif ($type == 'html') {
1030
			if (!preg_match('/search_/', $keyprefix)) {		// If keyprefix is search_ or search_options_, we must just use a simple text field
1031
				require_once DOL_DOCUMENT_ROOT.'/core/class/doleditor.class.php';
1032
				$doleditor = new DolEditor($keyprefix.$key.$keysuffix, $value, '', 200, 'dolibarr_notes', 'In', false, false, !empty($conf->fckeditor->enabled) && $conf->global->FCKEDITOR_ENABLE_SOCIETE, ROWS_5, '90%');
1033
				$out = $doleditor->Create(1);
1034
			} else {
1035
				$out = '<input type="text" class="flat '.$morecss.' maxwidthonsmartphone" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" value="'.dol_escape_htmltag($value).'" '.($moreparam ? $moreparam : '').'>';
1036
			}
1037
		} elseif ($type == 'boolean') {
1038
			if (empty($mode)) {
1039
				$checked = '';
1040
				if (!empty($value)) {
1041
					$checked = ' checked value="1" ';
1042
				} else {
1043
					$checked = ' value="1" ';
1044
				}
1045
				$out = '<input type="checkbox" class="flat valignmiddle'.($morecss ? ' '.$morecss : '').' maxwidthonsmartphone" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" '.$checked.' '.($moreparam ? $moreparam : '').'>';
1046
			} else {
1047
				$out .= $form->selectyesno($keyprefix.$key.$keysuffix, $value, 1, false, 1);
1048
			}
1049
		} elseif ($type == 'price') {
1050
			if (!empty($value)) {		// $value in memory is a php numeric, we format it into user number format.
1051
				$value = price($value);
1052
			}
1053
			$out = '<input type="text" class="flat '.$morecss.' maxwidthonsmartphone" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" value="'.$value.'" '.($moreparam ? $moreparam : '').'> '.$langs->getCurrencySymbol($conf->currency);
1054
		} elseif ($type == 'double') {
1055
			if (!empty($value)) {		// $value in memory is a php numeric, we format it into user number format.
1056
				$value = price($value);
1057
			}
1058
			$out = '<input type="text" class="flat '.$morecss.' maxwidthonsmartphone" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" value="'.$value.'" '.($moreparam ? $moreparam : '').'> ';
1059
		} elseif ($type == 'select') {
1060
			$out = '';
1061
			if (!empty($conf->use_javascript_ajax) && empty($conf->global->MAIN_EXTRAFIELDS_DISABLE_SELECT2)) {
1062
				include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php';
1063
				$out .= ajax_combobox($keyprefix.$key.$keysuffix, array(), 0);
1064
			}
1065
1066
			$out .= '<select class="flat '.$morecss.' maxwidthonsmartphone" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" '.($moreparam ? $moreparam : '').'>';
1067
			$out .= '<option value="0">&nbsp;</option>';
1068
			foreach ($param['options'] as $key => $val) {
0 ignored issues
show
introduced by
$key is overwriting one of the parameters of this function.
Loading history...
Comprehensibility Best Practice introduced by
The variable $param does not seem to be defined for all execution paths leading up to this point.
Loading history...
1069
				if ((string) $key == '') {
1070
					continue;
1071
				}
1072
				$valarray = explode('|', $val);
1073
				$val = $valarray[0];
1074
				$parent = '';
1075
				if (!empty($valarray[1])) {
1076
					$parent = $valarray[1];
1077
				}
1078
				$out .= '<option value="'.$key.'"';
1079
				$out .= (((string) $value == (string) $key) ? ' selected' : '');
1080
				$out .= (!empty($parent) ? ' parent="'.$parent.'"' : '');
1081
				$out .= '>';
1082
				if ($langfile && $val) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $langfile does not seem to be defined for all execution paths leading up to this point.
Loading history...
1083
					$out .= $langs->trans($val);
1084
				} else {
1085
					$out .= $val;
1086
				}
1087
				$out .= '</option>';
1088
			}
1089
			$out .= '</select>';
1090
		} elseif ($type == 'sellist') {
1091
			$out = '';
1092
			if (!empty($conf->use_javascript_ajax) && empty($conf->global->MAIN_EXTRAFIELDS_DISABLE_SELECT2)) {
1093
				include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php';
1094
				$out .= ajax_combobox($keyprefix.$key.$keysuffix, array(), 0);
1095
			}
1096
1097
			$out .= '<select class="flat '.$morecss.' maxwidthonsmartphone" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" '.($moreparam ? $moreparam : '').'>';
1098
			if (is_array($param['options'])) {
1099
				$param_list = array_keys($param['options']);
1100
				$InfoFieldList = explode(":", $param_list[0]);
1101
				$parentName = '';
1102
				$parentField = '';
1103
				// 0 : tableName
1104
				// 1 : label field name
1105
				// 2 : key fields name (if differ of rowid)
1106
				// 3 : key field parent (for dependent lists)
1107
				// 4 : where clause filter on column or table extrafield, syntax field='value' or extra.field=value
1108
				// 5 : id category type
1109
				// 6 : ids categories list separated by comma for category root
1110
				$keyList = (empty($InfoFieldList[2]) ? 'rowid' : $InfoFieldList[2].' as rowid');
1111
1112
1113
				if (count($InfoFieldList) > 4 && !empty($InfoFieldList[4])) {
1114
					if (strpos($InfoFieldList[4], 'extra.') !== false) {
1115
						$keyList = 'main.'.$InfoFieldList[2].' as rowid';
1116
					} else {
1117
						$keyList = $InfoFieldList[2].' as rowid';
1118
					}
1119
				}
1120
				if (count($InfoFieldList) > 3 && !empty($InfoFieldList[3])) {
1121
					list($parentName, $parentField) = explode('|', $InfoFieldList[3]);
1122
					$keyList .= ', '.$parentField;
1123
				}
1124
1125
				$filter_categorie = false;
1126
				if (count($InfoFieldList) > 5) {
1127
					if ($InfoFieldList[0] == 'categorie') {
1128
						$filter_categorie = true;
1129
					}
1130
				}
1131
1132
				if ($filter_categorie === false) {
1133
					$fields_label = explode('|', $InfoFieldList[1]);
1134
					if (is_array($fields_label)) {
1135
						$keyList .= ', ';
1136
						$keyList .= implode(', ', $fields_label);
1137
					}
1138
1139
					$sqlwhere = '';
1140
					$sql = "SELECT ".$keyList;
1141
					$sql .= ' FROM '.MAIN_DB_PREFIX.$InfoFieldList[0];
1142
					if (!empty($InfoFieldList[4])) {
1143
						// can use curent entity filter
1144
						if (strpos($InfoFieldList[4], '$ENTITY$') !== false) {
1145
							$InfoFieldList[4] = str_replace('$ENTITY$', $conf->entity, $InfoFieldList[4]);
1146
						}
1147
						// can use SELECT request
1148
						if (strpos($InfoFieldList[4], '$SEL$') !== false) {
1149
							$InfoFieldList[4] = str_replace('$SEL$', 'SELECT', $InfoFieldList[4]);
1150
						}
1151
1152
						// current object id can be use into filter
1153
						if (strpos($InfoFieldList[4], '$ID$') !== false && !empty($objectid)) {
1154
							$InfoFieldList[4] = str_replace('$ID$', $objectid, $InfoFieldList[4]);
1155
						} else {
1156
							$InfoFieldList[4] = str_replace('$ID$', '0', $InfoFieldList[4]);
1157
						}
1158
						//We have to join on extrafield table
1159
						if (strpos($InfoFieldList[4], 'extra') !== false) {
1160
							$sql .= ' as main, '.MAIN_DB_PREFIX.$InfoFieldList[0].'_extrafields as extra';
1161
							$sqlwhere .= " WHERE extra.fk_object=main.".$InfoFieldList[2]." AND ".$InfoFieldList[4];
1162
						} else {
1163
							$sqlwhere .= " WHERE ".$InfoFieldList[4];
1164
						}
1165
					} else {
1166
						$sqlwhere .= ' WHERE 1=1';
1167
					}
1168
					// Some tables may have field, some other not. For the moment we disable it.
1169
					if (in_array($InfoFieldList[0], array('tablewithentity'))) {
1170
						$sqlwhere .= ' AND entity = '.((int) $conf->entity);
1171
					}
1172
					$sql .= $sqlwhere;
1173
					//print $sql;
1174
1175
					$sql .= ' ORDER BY '.implode(', ', $fields_label);
1176
1177
					dol_syslog(get_class($this).'::showInputField type=sellist', LOG_DEBUG);
1178
					$resql = $this->db->query($sql);
1179
					if ($resql) {
1180
						$out .= '<option value="0">&nbsp;</option>';
1181
						$num = $this->db->num_rows($resql);
1182
						$i = 0;
1183
						while ($i < $num) {
1184
							$labeltoshow = '';
1185
							$obj = $this->db->fetch_object($resql);
1186
1187
							// Several field into label (eq table:code|libelle:rowid)
1188
							$notrans = false;
1189
							$fields_label = explode('|', $InfoFieldList[1]);
1190
							if (is_array($fields_label) && count($fields_label) > 1) {
1191
								$notrans = true;
1192
								foreach ($fields_label as $field_toshow) {
1193
									$labeltoshow .= $obj->$field_toshow.' ';
1194
								}
1195
							} else {
1196
								$labeltoshow = $obj->{$InfoFieldList[1]};
1197
							}
1198
							$labeltoshow = $labeltoshow;
1199
1200
							if ($value == $obj->rowid) {
1201
								if (!$notrans) {
1202
									foreach ($fields_label as $field_toshow) {
1203
										$translabel = $langs->trans($obj->$field_toshow);
1204
										$labeltoshow = $translabel.' ';
1205
									}
1206
								}
1207
								$out .= '<option value="'.$obj->rowid.'" selected>'.$labeltoshow.'</option>';
1208
							} else {
1209
								if (!$notrans) {
1210
									$translabel = $langs->trans($obj->{$InfoFieldList[1]});
1211
									$labeltoshow = $translabel;
1212
								}
1213
								if (empty($labeltoshow)) {
1214
									$labeltoshow = '(not defined)';
1215
								}
1216
1217
								if (!empty($InfoFieldList[3]) && $parentField) {
1218
									$parent = $parentName.':'.$obj->{$parentField};
1219
								}
1220
1221
								$out .= '<option value="'.$obj->rowid.'"';
1222
								$out .= ($value == $obj->rowid ? ' selected' : '');
1223
								$out .= (!empty($parent) ? ' parent="'.$parent.'"' : '');
1224
								$out .= '>'.$labeltoshow.'</option>';
1225
							}
1226
1227
							$i++;
1228
						}
1229
						$this->db->free($resql);
1230
					} else {
1231
						print 'Error in request '.$sql.' '.$this->db->lasterror().'. Check setup of extra parameters.<br>';
1232
					}
1233
				} else {
1234
					require_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php';
1235
					$data = $form->select_all_categories(Categorie::$MAP_ID_TO_CODE[$InfoFieldList[5]], '', 'parent', 64, $InfoFieldList[6], 1, 1);
1236
					$out .= '<option value="0">&nbsp;</option>';
1237
					foreach ($data as $data_key => $data_value) {
0 ignored issues
show
Bug introduced by
The expression $data of type string is not traversable.
Loading history...
1238
						$out .= '<option value="'.$data_key.'"';
1239
						$out .= ($value == $data_key ? ' selected' : '');
1240
						$out .= '>'.$data_value.'</option>';
1241
					}
1242
				}
1243
			}
1244
			$out .= '</select>';
1245
		} elseif ($type == 'checkbox') {
1246
			$value_arr = $value;
1247
			if (!is_array($value)) {
1248
				$value_arr = explode(',', $value);
1249
			}
1250
			$out = $form->multiselectarray($keyprefix.$key.$keysuffix, (empty($param['options']) ?null:$param['options']), $value_arr, '', 0, '', 0, '100%');
1251
		} elseif ($type == 'radio') {
1252
			$out = '';
1253
			foreach ($param['options'] as $keyopt => $val) {
1254
				$out .= '<input class="flat '.$morecss.'" type="radio" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" '.($moreparam ? $moreparam : '');
1255
				$out .= ' value="'.$keyopt.'"';
1256
				$out .= ' id="'.$keyprefix.$key.$keysuffix.'_'.$keyopt.'"';
1257
				$out .= ($value == $keyopt ? 'checked' : '');
1258
				$out .= '/><label for="'.$keyprefix.$key.$keysuffix.'_'.$keyopt.'">'.$val.'</label><br>';
1259
			}
1260
		} elseif ($type == 'chkbxlst') {
1261
			if (is_array($value)) {
1262
				$value_arr = $value;
1263
			} else {
1264
				$value_arr = explode(',', $value);
1265
			}
1266
1267
			if (is_array($param['options'])) {
1268
				$param_list = array_keys($param['options']);
1269
				$InfoFieldList = explode(":", $param_list[0]);
1270
				$parentName = '';
1271
				$parentField = '';
1272
				// 0 : tableName
1273
				// 1 : label field name
1274
				// 2 : key fields name (if differ of rowid)
1275
				// 3 : key field parent (for dependent lists)
1276
				// 4 : where clause filter on column or table extrafield, syntax field='value' or extra.field=value
1277
				// 5 : id category type
1278
				// 6 : ids categories list separated by comma for category root
1279
				$keyList = (empty($InfoFieldList[2]) ? 'rowid' : $InfoFieldList[2].' as rowid');
1280
1281
				if (count($InfoFieldList) > 3 && !empty($InfoFieldList[3])) {
1282
					list ($parentName, $parentField) = explode('|', $InfoFieldList[3]);
1283
					$keyList .= ', '.$parentField;
1284
				}
1285
				if (count($InfoFieldList) > 4 && !empty($InfoFieldList[4])) {
1286
					if (strpos($InfoFieldList[4], 'extra.') !== false) {
1287
						$keyList = 'main.'.$InfoFieldList[2].' as rowid';
1288
					} else {
1289
						$keyList = $InfoFieldList[2].' as rowid';
1290
					}
1291
				}
1292
1293
				$filter_categorie = false;
1294
				if (count($InfoFieldList) > 5) {
1295
					if ($InfoFieldList[0] == 'categorie') {
1296
						$filter_categorie = true;
1297
					}
1298
				}
1299
1300
				if ($filter_categorie === false) {
1301
					$fields_label = explode('|', $InfoFieldList[1]);
1302
					if (is_array($fields_label)) {
1303
						$keyList .= ', ';
1304
						$keyList .= implode(', ', $fields_label);
1305
					}
1306
1307
					$sqlwhere = '';
1308
					$sql = "SELECT ".$keyList;
1309
					$sql .= ' FROM '.MAIN_DB_PREFIX.$InfoFieldList[0];
1310
					if (!empty($InfoFieldList[4])) {
1311
						// can use SELECT request
1312
						if (strpos($InfoFieldList[4], '$SEL$') !== false) {
1313
							$InfoFieldList[4] = str_replace('$SEL$', 'SELECT', $InfoFieldList[4]);
1314
						}
1315
1316
						// current object id can be use into filter
1317
						if (strpos($InfoFieldList[4], '$ID$') !== false && !empty($objectid)) {
1318
							$InfoFieldList[4] = str_replace('$ID$', $objectid, $InfoFieldList[4]);
1319
						} elseif (preg_match("#^.*list.php$#", $_SERVER["PHP_SELF"])) {
1320
							// Pattern for word=$ID$
1321
							$word = '\b[a-zA-Z0-9-\.-_]+\b=\$ID\$';
1322
1323
							// Removing space arount =, ( and )
1324
							$InfoFieldList[4] = preg_replace('# *(=|\(|\)) *#', '$1', $InfoFieldList[4]);
1325
1326
							$nbPreg = 1;
1327
							// While we have parenthesis
1328
							while ($nbPreg != 0) {
1329
								// Init des compteurs
1330
								$nbPregRepl = $nbPregSel = 0;
1331
								// On retire toutes les parenthèses sans = avant
1332
								$InfoFieldList[4] = preg_replace('#([^=])(\([^)^(]*('.$word.')[^)^(]*\))#', '$1 $3 ', $InfoFieldList[4], -1, $nbPregRepl);
1333
								// On retire les espaces autour des = et parenthèses
1334
								$InfoFieldList[4] = preg_replace('# *(=|\(|\)) *#', '$1', $InfoFieldList[4]);
1335
								// On retire toutes les parenthèses avec = avant
1336
								$InfoFieldList[4] = preg_replace('#\b[a-zA-Z0-9-\.-_]+\b=\([^)^(]*('.$word.')[^)^(]*\)#', '$1 ', $InfoFieldList[4], -1, $nbPregSel);
1337
								// On retire les espaces autour des = et parenthèses
1338
								$InfoFieldList[4] = preg_replace('# *(=|\(|\)) *#', '$1', $InfoFieldList[4]);
1339
1340
								// Calcul du compteur général pour la boucle
1341
								$nbPreg = $nbPregRepl + $nbPregSel;
1342
							}
1343
1344
							// Si l'on a un AND ou un OR, avant ou après
1345
							preg_match('#(AND|OR|) *('.$word.') *(AND|OR|)#', $InfoFieldList[4], $matchCondition);
1346
							while (!empty($matchCondition[0])) {
1347
								// If the two sides differ but are not empty
1348
								if (!empty($matchCondition[1]) && !empty($matchCondition[3]) && $matchCondition[1] != $matchCondition[3]) {
1349
									// Nobody sain would do that without parentheses
1350
									$InfoFieldList[4] = str_replace('$ID$', '0', $InfoFieldList[4]);
1351
								} else {
1352
									if (!empty($matchCondition[1])) {
1353
										$boolCond = (($matchCondition[1] == "AND") ? ' AND TRUE ' : ' OR FALSE ');
1354
										$InfoFieldList[4] = str_replace($matchCondition[0], $boolCond.$matchCondition[3], $InfoFieldList[4]);
1355
									} elseif (!empty($matchCondition[3])) {
1356
										$boolCond = (($matchCondition[3] == "AND") ? ' TRUE AND ' : ' FALSE OR');
1357
										$InfoFieldList[4] = str_replace($matchCondition[0], $boolCond, $InfoFieldList[4]);
1358
									} else {
1359
										$InfoFieldList[4] = " TRUE ";
1360
									}
1361
								}
1362
1363
								// Si l'on a un AND ou un OR, avant ou après
1364
								preg_match('#(AND|OR|) *('.$word.') *(AND|OR|)#', $InfoFieldList[4], $matchCondition);
1365
							}
1366
						} else {
1367
							$InfoFieldList[4] = str_replace('$ID$', '0', $InfoFieldList[4]);
1368
						}
1369
1370
						// We have to join on extrafield table
1371
						if (strpos($InfoFieldList[4], 'extra.') !== false) {
1372
							$sql .= ' as main, '.MAIN_DB_PREFIX.$InfoFieldList[0].'_extrafields as extra';
1373
							$sqlwhere .= " WHERE extra.fk_object=main.".$InfoFieldList[2]." AND ".$InfoFieldList[4];
1374
						} else {
1375
							$sqlwhere .= " WHERE ".$InfoFieldList[4];
1376
						}
1377
					} else {
1378
						$sqlwhere .= ' WHERE 1=1';
1379
					}
1380
					// Some tables may have field, some other not. For the moment we disable it.
1381
					if (in_array($InfoFieldList[0], array('tablewithentity'))) {
1382
						$sqlwhere .= " AND entity = ".((int) $conf->entity);
1383
					}
1384
					// $sql.=preg_replace('/^ AND /','',$sqlwhere);
1385
					// print $sql;
1386
1387
					$sql .= $sqlwhere;
1388
					dol_syslog(get_class($this).'::showInputField type=chkbxlst', LOG_DEBUG);
1389
					$resql = $this->db->query($sql);
1390
					if ($resql) {
1391
						$num = $this->db->num_rows($resql);
1392
						$i = 0;
1393
1394
						$data = array();
1395
1396
						while ($i < $num) {
1397
							$labeltoshow = '';
1398
							$obj = $this->db->fetch_object($resql);
1399
1400
							$notrans = false;
1401
							// Several field into label (eq table:code|libelle:rowid)
1402
							$fields_label = explode('|', $InfoFieldList[1]);
1403
							if (is_array($fields_label)) {
1404
								$notrans = true;
1405
								foreach ($fields_label as $field_toshow) {
1406
									$labeltoshow .= $obj->$field_toshow.' ';
1407
								}
1408
							} else {
1409
								$labeltoshow = $obj->{$InfoFieldList[1]};
1410
							}
1411
							$labeltoshow = dol_trunc($labeltoshow, 45);
1412
1413
							if (is_array($value_arr) && in_array($obj->rowid, $value_arr)) {
1414
								foreach ($fields_label as $field_toshow) {
1415
									$translabel = $langs->trans($obj->$field_toshow);
1416
									if ($translabel != $obj->$field_toshow) {
1417
										$labeltoshow = dol_trunc($translabel, 18).' ';
1418
									} else {
1419
										$labeltoshow = dol_trunc($obj->$field_toshow, 18).' ';
1420
									}
1421
								}
1422
1423
								$data[$obj->rowid] = $labeltoshow;
1424
							} else {
1425
								if (!$notrans) {
1426
									$translabel = $langs->trans($obj->{$InfoFieldList[1]});
1427
									if ($translabel != $obj->{$InfoFieldList[1]}) {
1428
										$labeltoshow = dol_trunc($translabel, 18);
1429
									} else {
1430
										$labeltoshow = dol_trunc($obj->{$InfoFieldList[1]}, 18);
1431
									}
1432
								}
1433
								if (empty($labeltoshow)) {
1434
									$labeltoshow = '(not defined)';
1435
								}
1436
1437
								if (is_array($value_arr) && in_array($obj->rowid, $value_arr)) {
1438
									$data[$obj->rowid] = $labeltoshow;
1439
								}
1440
1441
								if (!empty($InfoFieldList[3]) && $parentField) {
1442
									$parent = $parentName.':'.$obj->{$parentField};
1443
								}
1444
1445
								$data[$obj->rowid] = $labeltoshow;
1446
							}
1447
1448
							$i++;
1449
						}
1450
						$this->db->free($resql);
1451
1452
						$out = $form->multiselectarray($keyprefix.$key.$keysuffix, $data, $value_arr, '', 0, '', 0, '100%');
1453
					} else {
1454
						print 'Error in request '.$sql.' '.$this->db->lasterror().'. Check setup of extra parameters.<br>';
1455
					}
1456
				} else {
1457
					require_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php';
1458
					$data = $form->select_all_categories(Categorie::$MAP_ID_TO_CODE[$InfoFieldList[5]], '', 'parent', 64, $InfoFieldList[6], 1, 1);
1459
					$out = $form->multiselectarray($keyprefix.$key.$keysuffix, $data, $value_arr, '', 0, '', 0, '100%');
1460
				}
1461
			}
1462
		} elseif ($type == 'link') {
1463
			$param_list = array_keys($param['options']); // $param_list='ObjectName:classPath'
1464
			$showempty = (($required && $default != '') ? 0 : 1);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $default does not seem to be defined for all execution paths leading up to this point.
Loading history...
1465
			$out = $form->selectForForms($param_list[0], $keyprefix.$key.$keysuffix, $value, $showempty, '', '', $morecss);
1466
		} elseif ($type == 'password') {
1467
			// If prefix is 'search_', field is used as a filter, we use a common text field.
1468
			$out = '<input style="display:none" type="text" name="fakeusernameremembered">'; // Hidden field to reduce impact of evil Google Chrome autopopulate bug.
1469
			$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 : '').'>';
1470
		}
1471
		if (!empty($hidden)) {
1472
			$out = '<input type="hidden" value="'.$value.'" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'"/>';
1473
		}
1474
		/* Add comments
1475
		 if ($type == 'date') $out.=' (YYYY-MM-DD)';
1476
		 elseif ($type == 'datetime') $out.=' (YYYY-MM-DD HH:MM:SS)';
1477
		 */
1478
		/*if (! empty($help) && $keyprefix != 'search_options_') {
1479
			$out .= $form->textwithpicto('', $help, 1, 'help', '', 0, 3);
1480
		}*/
1481
		return $out;
1482
	}
1483
1484
1485
	/**
1486
	 * Return HTML string to put an output field into a page
1487
	 *
1488
	 * @param   string	$key            		Key of attribute
1489
	 * @param   string	$value          		Value to show
1490
	 * @param	string	$moreparam				To add more parameters on html input tag (only checkbox use html input for output rendering)
1491
	 * @param	string	$extrafieldsobjectkey	If defined (for example $object->table_element), function uses the new method to get extrafields data
1492
	 * @return	string							Formated value
1493
	 */
1494
	public function showOutputField($key, $value, $moreparam = '', $extrafieldsobjectkey = '')
1495
	{
1496
		global $conf, $langs;
1497
1498
		if (!empty($extrafieldsobjectkey)) {
1499
			$label = $this->attributes[$extrafieldsobjectkey]['label'][$key];
1500
			$type = $this->attributes[$extrafieldsobjectkey]['type'][$key];
1501
			$size = $this->attributes[$extrafieldsobjectkey]['size'][$key];			// Can be '255', '24,8'...
1502
			$default = $this->attributes[$extrafieldsobjectkey]['default'][$key];
1503
			$computed = $this->attributes[$extrafieldsobjectkey]['computed'][$key];
1504
			$unique = $this->attributes[$extrafieldsobjectkey]['unique'][$key];
1505
			$required = $this->attributes[$extrafieldsobjectkey]['required'][$key];
1506
			$param = $this->attributes[$extrafieldsobjectkey]['param'][$key];
1507
			$perms = dol_eval($this->attributes[$extrafieldsobjectkey]['perms'][$key], 1);
1508
			$langfile = $this->attributes[$extrafieldsobjectkey]['langfile'][$key];
1509
			$list = dol_eval($this->attributes[$extrafieldsobjectkey]['list'][$key], 1);
1510
			$help = $this->attributes[$extrafieldsobjectkey]['help'][$key];
1511
			$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)
1512
		} else {
1513
			// Old usage
1514
			$label = $this->attribute_label[$key];
1515
			$type = $this->attribute_type[$key];
1516
			$help = ''; // Not supported with old syntax
1517
			$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)
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $list seems to never exist and therefore empty should always be true.
Loading history...
1518
		}
1519
1520
		if ($hidden) {
1521
			return ''; // This is a protection. If field is hidden, we should just not call this method.
1522
		}
1523
1524
		//if ($computed) $value =		// $value is already calculated into $value before calling this method
1525
1526
		$showsize = 0;
1527
		if ($type == 'date') {
1528
			$showsize = 10;
1529
			if ($value !== '') {
1530
				$value = dol_print_date($value, 'day');	// For date without hour, date is always GMT for storage and output
1531
			}
1532
		} elseif ($type == 'datetime') {
1533
			$showsize = 19;
1534
			if ($value !== '') {
1535
				$value = dol_print_date($value, 'dayhour', 'tzuserrel');
1536
			}
1537
		} elseif ($type == 'int') {
1538
			$showsize = 10;
1539
		} elseif ($type == 'double') {
1540
			if (!empty($value)) {
1541
				//$value=price($value);
1542
				$sizeparts = explode(",", $size);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $size does not seem to be defined for all execution paths leading up to this point.
Loading history...
1543
				$number_decimals = $sizeparts[1];
1544
				$value = price($value, 0, $langs, 0, 0, $number_decimals, '');
1545
			}
1546
		} elseif ($type == 'boolean') {
1547
			$checked = '';
1548
			if (!empty($value)) {
1549
				$checked = ' checked ';
1550
			}
1551
			$value = '<input type="checkbox" '.$checked.' '.($moreparam ? $moreparam : '').' readonly disabled>';
1552
		} elseif ($type == 'mail') {
1553
			$value = dol_print_email($value, 0, 0, 0, 64, 1, 1);
1554
		} elseif ($type == 'url') {
1555
			$value = dol_print_url($value, '_blank', 32, 1);
1556
		} elseif ($type == 'phone') {
1557
			$value = dol_print_phone($value, '', 0, 0, '', '&nbsp;', 'phone');
1558
		} elseif ($type == 'price') {
1559
			//$value = price($value, 0, $langs, 0, 0, -1, $conf->currency);
1560
			if ($value || $value == '0') {
1561
				$value = price($value, 0, $langs, 0, 0, -1);
1562
			}
1563
		} elseif ($type == 'select') {
1564
			$valstr = (!empty($param['options'][$value]) ? $param['options'][$value] : '');
1565
			if (($pos = strpos($valstr, "|")) !== false) {
1566
				$valstr = substr($valstr, 0, $pos);
1567
			}
1568
			if ($langfile && $valstr) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $langfile does not seem to be defined for all execution paths leading up to this point.
Loading history...
1569
				$value = $langs->trans($valstr);
1570
			} else {
1571
				$value = $valstr;
1572
			}
1573
		} elseif ($type == 'sellist') {
1574
			$param_list = array_keys($param['options']);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $param does not seem to be defined for all execution paths leading up to this point.
Loading history...
1575
			$InfoFieldList = explode(":", $param_list[0]);
1576
1577
			$selectkey = "rowid";
1578
			$keyList = 'rowid';
1579
1580
			if (count($InfoFieldList) >= 3) {
1581
				$selectkey = $InfoFieldList[2];
1582
				$keyList = $InfoFieldList[2].' as rowid';
1583
			}
1584
1585
			$fields_label = explode('|', $InfoFieldList[1]);
1586
			if (is_array($fields_label)) {
1587
				$keyList .= ', ';
1588
				$keyList .= implode(', ', $fields_label);
1589
			}
1590
1591
			$filter_categorie = false;
1592
			if (count($InfoFieldList) > 5) {
1593
				if ($InfoFieldList[0] == 'categorie') {
1594
					$filter_categorie = true;
1595
				}
1596
			}
1597
1598
			$sql = "SELECT ".$keyList;
1599
			$sql .= ' FROM '.MAIN_DB_PREFIX.$InfoFieldList[0];
1600
			if (!empty($InfoFieldList[4]) && strpos($InfoFieldList[4], 'extra') !== false) {
1601
				$sql .= ' as main';
1602
			}
1603
			if ($selectkey == 'rowid' && empty($value)) {
1604
				$sql .= " WHERE ".$selectkey." = 0";
1605
			} elseif ($selectkey == 'rowid') {
1606
				$sql .= " WHERE ".$selectkey." = ".((int) $value);
1607
			} else {
1608
				$sql .= " WHERE ".$selectkey." = '".$this->db->escape($value)."'";
1609
			}
1610
1611
			//$sql.= ' AND entity = '.$conf->entity;
1612
1613
			dol_syslog(get_class($this).':showOutputField:$type=sellist', LOG_DEBUG);
1614
			$resql = $this->db->query($sql);
1615
			if ($resql) {
1616
				if ($filter_categorie === false) {
1617
					$value = ''; // value was used, so now we reste it to use it to build final output
1618
1619
					$obj = $this->db->fetch_object($resql);
1620
1621
					// Several field into label (eq table:code|libelle:rowid)
1622
					$fields_label = explode('|', $InfoFieldList[1]);
1623
1624
					if (is_array($fields_label) && count($fields_label) > 1) {
1625
						foreach ($fields_label as $field_toshow) {
1626
							$translabel = '';
1627
							if (!empty($obj->$field_toshow)) {
1628
								$translabel = $langs->trans($obj->$field_toshow);
1629
							}
1630
							if ($translabel != $field_toshow) {
1631
								$value .= dol_trunc($translabel, 18).' ';
1632
							} else {
1633
								$value .= $obj->$field_toshow.' ';
1634
							}
1635
						}
1636
					} else {
1637
						$translabel = '';
1638
						if (!empty($obj->{$InfoFieldList[1]})) {
1639
							$translabel = $langs->trans($obj->{$InfoFieldList[1]});
1640
						}
1641
						if ($translabel != $obj->{$InfoFieldList[1]}) {
1642
							$value = dol_trunc($translabel, 18);
1643
						} else {
1644
							$value = $obj->{$InfoFieldList[1]};
1645
						}
1646
					}
1647
				} else {
1648
					require_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php';
1649
1650
					$toprint = array();
1651
					$obj = $this->db->fetch_object($resql);
1652
					$c = new Categorie($this->db);
1653
					$c->fetch($obj->rowid);
1654
					$ways = $c->print_all_ways(); // $ways[0] = "ccc2 >> ccc2a >> ccc2a1" with html formatted text
1655
					foreach ($ways as $way) {
1656
						$toprint[] = '<li class="select2-search-choice-dolibarr noborderoncategories"'.($c->color ? ' style="background: #'.$c->color.';"' : ' style="background: #bbb"').'>'.img_object('', 'category').' '.$way.'</li>';
1657
					}
1658
					$value = '<div class="select2-container-multi-dolibarr" style="width: 90%;"><ul class="select2-choices-dolibarr">'.implode(' ', $toprint).'</ul></div>';
1659
				}
1660
			} else {
1661
				dol_syslog(get_class($this).'::showOutputField error '.$this->db->lasterror(), LOG_WARNING);
1662
			}
1663
		} elseif ($type == 'radio') {
1664
			$value = $param['options'][$value];
1665
		} elseif ($type == 'checkbox') {
1666
			$value_arr = explode(',', $value);
1667
			$value = '';
1668
			$toprint = array();
1669
			if (is_array($value_arr)) {
1670
				foreach ($value_arr as $keyval => $valueval) {
1671
					$toprint[] = '<li class="select2-search-choice-dolibarr noborderoncategories" style="background: #bbb">'.$param['options'][$valueval].'</li>';
1672
				}
1673
			}
1674
			$value = '<div class="select2-container-multi-dolibarr" style="width: 90%;"><ul class="select2-choices-dolibarr">'.implode(' ', $toprint).'</ul></div>';
1675
		} elseif ($type == 'chkbxlst') {
1676
			$value_arr = explode(',', $value);
1677
1678
			$param_list = array_keys($param['options']);
1679
			$InfoFieldList = explode(":", $param_list[0]);
1680
1681
			$selectkey = "rowid";
1682
			$keyList = 'rowid';
1683
1684
			if (count($InfoFieldList) >= 3) {
1685
				$selectkey = $InfoFieldList[2];
1686
				$keyList = $InfoFieldList[2].' as rowid';
1687
			}
1688
1689
			$fields_label = explode('|', $InfoFieldList[1]);
1690
			if (is_array($fields_label)) {
1691
				$keyList .= ', ';
1692
				$keyList .= implode(', ', $fields_label);
1693
			}
1694
1695
			$filter_categorie = false;
1696
			if (count($InfoFieldList) > 5) {
1697
				if ($InfoFieldList[0] == 'categorie') {
1698
					$filter_categorie = true;
1699
				}
1700
			}
1701
1702
			$sql = "SELECT ".$keyList;
1703
			$sql .= " FROM ".MAIN_DB_PREFIX.$InfoFieldList[0];
1704
			if (strpos($InfoFieldList[4], 'extra') !== false) {
1705
				$sql .= ' as main';
1706
			}
1707
			// $sql.= " WHERE ".$selectkey."='".$this->db->escape($value)."'";
1708
			// $sql.= ' AND entity = '.$conf->entity;
1709
1710
			dol_syslog(get_class($this).':showOutputField:$type=chkbxlst', LOG_DEBUG);
1711
			$resql = $this->db->query($sql);
1712
			if ($resql) {
1713
				if ($filter_categorie === false) {
1714
					$value = ''; // value was used, so now we reste it to use it to build final output
1715
					$toprint = array();
1716
					while ($obj = $this->db->fetch_object($resql)) {
1717
						// Several field into label (eq table:code|libelle:rowid)
1718
						$fields_label = explode('|', $InfoFieldList[1]);
1719
						if (is_array($value_arr) && in_array($obj->rowid, $value_arr)) {
1720
							if (is_array($fields_label) && count($fields_label) > 1) {
1721
								foreach ($fields_label as $field_toshow) {
1722
									$translabel = '';
1723
									if (!empty($obj->$field_toshow)) {
1724
										$translabel = $langs->trans($obj->$field_toshow);
1725
									}
1726
									if ($translabel != $field_toshow) {
1727
										$toprint[] = '<li class="select2-search-choice-dolibarr noborderoncategories" style="background: #bbb">'.dol_trunc($translabel, 18).'</li>';
1728
									} else {
1729
										$toprint[] = '<li class="select2-search-choice-dolibarr noborderoncategories" style="background: #bbb">'.$obj->$field_toshow.'</li>';
1730
									}
1731
								}
1732
							} else {
1733
								$translabel = '';
1734
								if (!empty($obj->{$InfoFieldList[1]})) {
1735
									$translabel = $langs->trans($obj->{$InfoFieldList[1]});
1736
								}
1737
								if ($translabel != $obj->{$InfoFieldList[1]}) {
1738
									$toprint[] = '<li class="select2-search-choice-dolibarr noborderoncategories" style="background: #bbb">'.dol_trunc($translabel, 18).'</li>';
1739
								} else {
1740
									$toprint[] = '<li class="select2-search-choice-dolibarr noborderoncategories" style="background: #bbb">'.$obj->{$InfoFieldList[1]}.'</li>';
1741
								}
1742
							}
1743
						}
1744
					}
1745
				} else {
1746
					require_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php';
1747
1748
					$toprint = array();
1749
					while ($obj = $this->db->fetch_object($resql)) {
1750
						if (is_array($value_arr) && in_array($obj->rowid, $value_arr)) {
1751
							$c = new Categorie($this->db);
1752
							$c->fetch($obj->rowid);
1753
							$ways = $c->print_all_ways(); // $ways[0] = "ccc2 >> ccc2a >> ccc2a1" with html formatted text
1754
							foreach ($ways as $way) {
1755
								$toprint[] = '<li class="select2-search-choice-dolibarr noborderoncategories"'.($c->color ? ' style="background: #'.$c->color.';"' : ' style="background: #bbb"').'>'.img_object('', 'category').' '.$way.'</li>';
1756
							}
1757
						}
1758
					}
1759
				}
1760
				$value = '<div class="select2-container-multi-dolibarr" style="width: 90%;"><ul class="select2-choices-dolibarr">'.implode(' ', $toprint).'</ul></div>';
1761
			} else {
1762
				dol_syslog(get_class($this).'::showOutputField error '.$this->db->lasterror(), LOG_WARNING);
1763
			}
1764
		} elseif ($type == 'link') {
1765
			$out = '';
1766
1767
			// Only if something to display (perf)
1768
			if ($value) {		// If we have -1 here, pb is into insert, not into ouptut (fix insert instead of changing code here to compensate)
1769
				$param_list = array_keys($param['options']); // $param_list='ObjectName:classPath'
1770
1771
				$InfoFieldList = explode(":", $param_list[0]);
1772
				$classname = $InfoFieldList[0];
1773
				$classpath = $InfoFieldList[1];
1774
				if (!empty($classpath)) {
1775
					dol_include_once($InfoFieldList[1]);
1776
					if ($classname && class_exists($classname)) {
1777
						$object = new $classname($this->db);
1778
						$object->fetch($value);
1779
						$value = $object->getNomUrl(3);
1780
					}
1781
				} else {
1782
					dol_syslog('Error bad setup of extrafield', LOG_WARNING);
1783
					return 'Error bad setup of extrafield';
1784
				}
1785
			}
1786
		} elseif ($type == 'text') {
1787
			$value = dol_htmlentitiesbr($value);
1788
		} elseif ($type == 'html') {
1789
			$value = dol_htmlentitiesbr($value);
1790
		} elseif ($type == 'password') {
1791
			$value = dol_trunc(preg_replace('/./i', '*', $value), 8, 'right', 'UTF-8', 1);
1792
		} else {
1793
			$showsize = round((float) $size);
1794
			if ($showsize > 48) {
1795
				$showsize = 48;
1796
			}
1797
		}
1798
1799
		//print $type.'-'.$size;
1800
		$out = $value;
1801
1802
		return $out;
1803
	}
1804
1805
	/**
1806
	 * Return tag to describe alignement to use for this extrafield
1807
	 *
1808
	 * @param   string	$key            		Key of attribute
1809
	 * @param	string	$extrafieldsobjectkey	If defined, use the new method to get extrafields data
1810
	 * @return	string							Formated value
1811
	 */
1812
	public function getAlignFlag($key, $extrafieldsobjectkey = '')
1813
	{
1814
		global $conf, $langs;
1815
1816
		if (!empty($extrafieldsobjectkey)) {
1817
			$type = $this->attributes[$extrafieldsobjectkey]['type'][$key];
1818
		} else {
1819
			$type = $this->attribute_type[$key];
1820
		}
1821
1822
		$align = '';
1823
1824
		if ($type == 'date') {
1825
			$align = "center";
1826
		} elseif ($type == 'datetime') {
1827
			$align = "center";
1828
		} elseif ($type == 'int') {
1829
			$align = "right";
1830
		} elseif ($type == 'price') {
1831
			$align = "right";
1832
		} elseif ($type == 'double') {
1833
			$align = "right";
1834
		} elseif ($type == 'boolean') {
1835
			$align = "center";
1836
		} elseif ($type == 'radio') {
1837
			$align = "center";
1838
		} elseif ($type == 'checkbox') {
1839
			$align = "center";
1840
		} elseif ($type == 'price') {
1841
			$align = "right";
1842
		}
1843
1844
		return $align;
1845
	}
1846
1847
	/**
1848
	 * Return HTML string to print separator extrafield
1849
	 *
1850
	 * @param   string	$key            Key of attribute
1851
	 * @param	string	$object			Object
1852
	 * @param	int		$colspan		Value of colspan to use (it must includes the first column with title)
1853
	 * @param	string	$display_type	"card" for form display, "line" for document line display (extrafields on propal line, order line, etc...)
1854
	 * @return 	string					HTML code with line for separator
1855
	 */
1856
	public function showSeparator($key, $object, $colspan = 2, $display_type = 'card')
1857
	{
1858
		global $conf, $langs;
1859
1860
		$tagtype='tr';
1861
		$tagtype_dyn='td';
1862
1863
		if ($display_type=='line') {
1864
			$tagtype='div';
1865
			$tagtype_dyn='span';
1866
			$colspan=0;
1867
		}
1868
1869
		$out = '<'.$tagtype.' id="trextrafieldseparator'.$key.(!empty($object->id)?'_'.$object->id:'').'" class="trextrafieldseparator trextrafieldseparator'.$key.(!empty($object->id)?'_'.$object->id:'').'">';
0 ignored issues
show
Bug introduced by
The property id does not exist on string.
Loading history...
1870
		$out .= '<'.$tagtype_dyn.' '.(!empty($colspan)?'colspan="' . $colspan . '"':'').'>';
1871
		// Some js code will be injected here to manage the collapsing of extrafields
1872
		$out .='<strong>';
1873
		$out .= $langs->trans($this->attributes[$object->table_element]['label'][$key]);
0 ignored issues
show
Bug introduced by
The property table_element does not exist on string.
Loading history...
1874
		$out .= '</strong>';
1875
		$out .= '</'.$tagtype_dyn.'>';
1876
		$out .= '</'.$tagtype.'>';
1877
1878
		$extrafield_param = $this->attributes[$object->table_element]['param'][$key];
1879
		if (!empty($extrafield_param) && is_array($extrafield_param)) {
1880
			$extrafield_param_list = array_keys($extrafield_param['options']);
1881
1882
			if (count($extrafield_param_list) > 0) {
1883
				$extrafield_collapse_display_value = intval($extrafield_param_list[0]);
1884
				if ($extrafield_collapse_display_value == 1 || $extrafield_collapse_display_value == 2) {
1885
					// Set the collapse_display status to cookie in priority or if ignorecollapsesetup is 1, if cookie and ignorecollapsesetup not defined, use the setup.
1886
					$collapse_display = ((isset($_COOKIE['DOLCOLLAPSE_'.$object->table_element.'_extrafields_'.$key]) || GETPOST('ignorecollapsesetup', 'int')) ? ($_COOKIE['DOLCOLLAPSE_'.$object->table_element.'_extrafields_'.$key] ? true : false) : ($extrafield_collapse_display_value == 2 ? false : true));
1887
					$extrafields_collapse_num = $this->attributes[$object->table_element]['pos'][$key].(!empty($object->id)?'_'.$object->id:'');
1888
1889
					if (!empty($conf->use_javascript_ajax)) {
1890
						$out .= '<!-- Add js script to manage the collapse/uncollapse of extrafields separators '.$key.' -->'."\n";
1891
						$out .= '<script type="text/javascript">'."\n";
1892
						$out .= 'jQuery(document).ready(function(){'."\n";
1893
						if ($collapse_display === false) {
1894
							$out .= '   console.log("Inject js for the collapsing of extrafield '.$key.' - hide");';
1895
							$out .= '   jQuery("#trextrafieldseparator'.$key.(!empty($object->id)?'_'.$object->id:'').' '.$tagtype_dyn.'").prepend("<span class=\"cursorpointer far fa-plus-square\"></span>&nbsp;");'."\n";
1896
							$out .= '   jQuery(".trextrafields_collapse'.$extrafields_collapse_num.'").hide();'."\n";
1897
						} else {
1898
							$out .= '   console.log("Inject js for collapsing of extrafield '.$key.' - keep visible and set cookie");';
1899
							$out .= '   jQuery("#trextrafieldseparator'.$key.(!empty($object->id)?'_'.$object->id:'').' '.$tagtype_dyn.'").prepend("<span class=\"cursorpointer far fa-minus-square\"></span>&nbsp;");'."\n";
1900
							$out .= '   document.cookie = "DOLCOLLAPSE_'.$object->table_element.'_extrafields_'.$key.'=1; path='.$_SERVER["PHP_SELF"].'"'."\n";
1901
						}
1902
						$out .= '   jQuery("#trextrafieldseparator'.$key.(!empty($object->id)?'_'.$object->id:'').'").click(function(){'."\n";
1903
						$out .= '       console.log("We click on collapse/uncollapse .trextrafields_collapse'.$extrafields_collapse_num.'");'."\n";
1904
						$out .= '       jQuery(".trextrafields_collapse'.$extrafields_collapse_num.'").toggle(100, function(){'."\n";
1905
						$out .= '           if (jQuery(".trextrafields_collapse'.$extrafields_collapse_num.'").is(":hidden")) {'."\n";
1906
						$out .= '               jQuery("#trextrafieldseparator'.$key.(!empty($object->id)?'_'.$object->id:'').' '.$tagtype_dyn.' span").addClass("fa-plus-square").removeClass("fa-minus-square");'."\n";
1907
						$out .= '               document.cookie = "DOLCOLLAPSE_'.$object->table_element.'_extrafields_'.$key.'=0; path='.$_SERVER["PHP_SELF"].'"'."\n";
1908
						$out .= '           } else {'."\n";
1909
						$out .= '               jQuery("#trextrafieldseparator'.$key.(!empty($object->id)?'_'.$object->id:'').' '.$tagtype_dyn.' span").addClass("fa-minus-square").removeClass("fa-plus-square");'."\n";
1910
						$out .= '               document.cookie = "DOLCOLLAPSE_'.$object->table_element.'_extrafields_'.$key.'=1; path='.$_SERVER["PHP_SELF"].'"'."\n";
1911
						$out .= '           }'."\n";
1912
						$out .= '       });'."\n";
1913
						$out .= '   });'."\n";
1914
						$out .= '});'."\n";
1915
						$out .= '</script>'."\n";
1916
					}
1917
				}
1918
			}
1919
		}
1920
1921
		return $out;
1922
	}
1923
1924
	/**
1925
	 * Fill array_options property of object by extrafields value (using for data sent by forms)
1926
	 *
1927
	 * @param   array	$extralabels    Deprecated (old $array of extrafields, now set this to null)
1928
	 * @param   object	$object         Object
1929
	 * @param	string	$onlykey		Only some keys are filled:
1930
	 *                                  'string' => When we make update of only one extrafield ($action = 'update_extras'), calling page can set this to avoid to have other extrafields being reset.
1931
	 *                                  '@GETPOSTISSET' => When we make update of several extrafields ($action = 'update'), calling page can set this to avoid to have fields not into POST being reset.
1932
	 * @return	int						1 if array_options set, 0 if no value, -1 if error (field required missing for example)
1933
	 */
1934
	public function setOptionalsFromPost($extralabels, &$object, $onlykey = '')
1935
	{
1936
		global $_POST, $langs;
1937
1938
		$nofillrequired = 0; // For error when required field left blank
1939
		$error_field_required = array();
1940
1941
		if (isset($this->attributes[$object->table_element]['label']) && is_array($this->attributes[$object->table_element]['label'])) {
1942
			$extralabels = $this->attributes[$object->table_element]['label'];
1943
		}
1944
1945
		if (is_array($extralabels)) {
1946
			// Get extra fields
1947
			foreach ($extralabels as $key => $value) {
1948
				if (!empty($onlykey) && $onlykey != '@GETPOSTISSET' && $key != $onlykey) {
1949
					continue;
1950
				}
1951
				if (!empty($onlykey) && $onlykey == '@GETPOSTISSET' && !GETPOSTISSET('options_'.$key)) {
1952
					continue;
1953
				}
1954
1955
				$key_type = $this->attributes[$object->table_element]['type'][$key];
1956
				if ($key_type == 'separate') {
1957
					continue;
1958
				}
1959
1960
				$enabled = 1;
1961
				if (isset($this->attributes[$object->table_element]['enabled'][$key])) {	// 'enabled' is often a condition on module enabled or not
1962
					$enabled = dol_eval($this->attributes[$object->table_element]['enabled'][$key], 1);
1963
				}
1964
1965
				$visibility = 1;
1966
				if (isset($this->attributes[$object->table_element]['list'][$key])) {		// 'list' is option for visibility
1967
					$visibility = dol_eval($this->attributes[$object->table_element]['list'][$key], 1);
1968
				}
1969
1970
				$perms = 1;
1971
				if (isset($this->attributes[$object->table_element]['perms'][$key])) {
1972
					$perms = dol_eval($this->attributes[$object->table_element]['perms'][$key], 1);
1973
				}
1974
				if (empty($enabled)) {
1975
					continue;
1976
				}
1977
				if (empty($visibility)) {
1978
					continue;
1979
				}
1980
				if (empty($perms)) {
1981
					continue;
1982
				}
1983
1984
				if ($this->attributes[$object->table_element]['required'][$key]) {	// Value is required
1985
					// Check if functionally empty without using GETPOST (depending on the type of extrafield, a
1986
					// technically non-empty value may be treated as empty functionally).
1987
					// value can be alpha, int, array, etc...
1988
					if ((!is_array($_POST["options_".$key]) && empty($_POST["options_".$key]) && $this->attributes[$object->table_element]['type'][$key] != 'select' && $_POST["options_".$key] != '0')
1989
						|| (!is_array($_POST["options_".$key]) && empty($_POST["options_".$key]) && $this->attributes[$object->table_element]['type'][$key] == 'select')
1990
						|| (!is_array($_POST["options_".$key]) && isset($_POST["options_".$key]) && $this->attributes[$object->table_element]['type'][$key] == 'sellist' && $_POST['options_'.$key] == '0')
1991
						|| (is_array($_POST["options_".$key]) && empty($_POST["options_".$key]))) {
1992
						//print 'ccc'.$value.'-'.$this->attributes[$object->table_element]['required'][$key];
1993
						$nofillrequired++;
1994
						$error_field_required[] = $langs->transnoentitiesnoconv($value);
1995
					}
1996
				}
1997
1998
				if (in_array($key_type, array('date'))) {
1999
					// Clean parameters
2000
					$value_key = dol_mktime(12, 0, 0, GETPOST("options_".$key."month", 'int'), GETPOST("options_".$key."day", 'int'), GETPOST("options_".$key."year", 'int'));
2001
				} elseif (in_array($key_type, array('datetime'))) {
2002
					// Clean parameters
2003
					$value_key = dol_mktime(GETPOST("options_".$key."hour", 'int'), GETPOST("options_".$key."min", 'int'), GETPOST("options_".$key."sec", 'int'), GETPOST("options_".$key."month", 'int'), GETPOST("options_".$key."day", 'int'), GETPOST("options_".$key."year", 'int'), 'tzuserrel');
2004
				} elseif (in_array($key_type, array('checkbox', 'chkbxlst'))) {
2005
					$value_arr = GETPOST("options_".$key, 'array'); // check if an array
2006
					if (!empty($value_arr)) {
2007
						$value_key = implode($value_arr, ',');
2008
					} else {
2009
						$value_key = '';
2010
					}
2011
				} elseif (in_array($key_type, array('price', 'double'))) {
2012
					$value_arr = GETPOST("options_".$key, 'alpha');
2013
					$value_key = price2num($value_arr);
2014
				} elseif (in_array($key_type, array('html'))) {
2015
					$value_key = GETPOST("options_".$key, 'restricthtml');
2016
				} elseif (in_array($key_type, array('text'))) {
2017
					$value_key = GETPOST("options_".$key, 'alphanohtml');
2018
				} else {
2019
					$value_key = GETPOST("options_".$key);
2020
					if (in_array($key_type, array('link')) && $value_key == '-1') {
2021
						$value_key = '';
2022
					}
2023
				}
2024
2025
				$object->array_options["options_".$key] = $value_key;
2026
			}
2027
2028
			if ($nofillrequired) {
2029
				$langs->load('errors');
2030
				setEventMessages($langs->trans('ErrorFieldsRequired').' : '.implode(', ', $error_field_required), null, 'errors');
2031
				return -1;
2032
			} else {
2033
				return 1;
2034
			}
2035
		} else {
2036
			return 0;
2037
		}
2038
	}
2039
2040
	/**
2041
	 * return array_options array of data of extrafields value of object sent by a search form
2042
	 *
2043
	 * @param  array|string		$extrafieldsobjectkey  	array of extrafields (old usage) or value of object->table_element (new usage)
2044
	 * @param  string			$keyprefix      		Prefix string to add into name and id of field (can be used to avoid duplicate names)
2045
	 * @param  string			$keysuffix      		Suffix string to add into name and id of field (can be used to avoid duplicate names)
2046
	 * @return array|int								array_options set or 0 if no value
2047
	 */
2048
	public function getOptionalsFromPost($extrafieldsobjectkey, $keyprefix = '', $keysuffix = '')
2049
	{
2050
		global $_POST;
2051
2052
		if (is_string($extrafieldsobjectkey) && !empty($this->attributes[$extrafieldsobjectkey]['label']) && is_array($this->attributes[$extrafieldsobjectkey]['label'])) {
2053
			$extralabels = $this->attributes[$extrafieldsobjectkey]['label'];
2054
		} else {
2055
			$extralabels = $extrafieldsobjectkey;
2056
		}
2057
2058
		if (is_array($extralabels)) {
2059
			$array_options = array();
2060
2061
			// Get extra fields
2062
			foreach ($extralabels as $key => $value) {
2063
				$key_type = '';
2064
				if (is_string($extrafieldsobjectkey)) {
2065
					$key_type = $this->attributes[$extrafieldsobjectkey]['type'][$key];
2066
				}
2067
2068
				if (in_array($key_type, array('date'))) {
2069
					$dateparamname_start = $keysuffix . 'options_' . $key . $keyprefix . '_start';
2070
					$dateparamname_end   = $keysuffix . 'options_' . $key . $keyprefix . '_end';
2071
					if (GETPOSTISSET($dateparamname_start . 'year') && GETPOSTISSET($dateparamname_end . 'year')) {
2072
						// values provided as a date pair (start date + end date), each date being broken down as year, month, day, etc.
2073
						$value_key = array(
2074
							'start' => dol_mktime(0, 0, 0, GETPOST($dateparamname_start . 'month', 'int'), GETPOST($dateparamname_start . 'day', 'int'), GETPOST($dateparamname_start . 'year', 'int')),
2075
							'end' => dol_mktime(23, 59, 59, GETPOST($dateparamname_end . 'month', 'int'), GETPOST($dateparamname_end . 'day', 'int'), GETPOST($dateparamname_end . 'year', 'int'))
2076
						);
2077
					} elseif (GETPOSTISSET($keysuffix."options_".$key.$keyprefix."year")) {
2078
						// Clean parameters
2079
						$value_key = dol_mktime(12, 0, 0, GETPOST($keysuffix."options_".$key.$keyprefix."month", 'int'), GETPOST($keysuffix."options_".$key.$keyprefix."day", 'int'), GETPOST($keysuffix."options_".$key.$keyprefix."year", 'int'));
2080
					} else {
2081
						continue; // Value was not provided, we should not set it.
2082
					}
2083
				} elseif (in_array($key_type, array('datetime'))) {
2084
					$dateparamname_start = $keysuffix . 'options_' . $key . $keyprefix . '_start';
2085
					$dateparamname_end   = $keysuffix . 'options_' . $key . $keyprefix . '_end';
2086
					if (GETPOSTISSET($dateparamname_start . 'year') && GETPOSTISSET($dateparamname_end . 'year')) {
2087
						// values provided as a date pair (start date + end date), each date being broken down as year, month, day, etc.
2088
						$value_key = array(
2089
							'start' => dol_mktime(GETPOST($dateparamname_start . 'hour', 'int'), GETPOST($dateparamname_start . 'min', 'int'), GETPOST($dateparamname_start . 'sec', 'int'), GETPOST($dateparamname_start . 'month', 'int'), GETPOST($dateparamname_start . 'day', 'int'), GETPOST($dateparamname_start . 'year', 'int'), 'tzuserrel'),
2090
							'end' => dol_mktime(GETPOST($dateparamname_end . 'hour', 'int'), GETPOST($dateparamname_start . 'min', 'int'), GETPOST($dateparamname_start . 'sec', 'int'), GETPOST($dateparamname_end . 'month', 'int'), GETPOST($dateparamname_end . 'day', 'int'), GETPOST($dateparamname_end . 'year', 'int'), 'tzuserrel')
2091
						);
2092
					} elseif (GETPOSTISSET($keysuffix."options_".$key.$keyprefix."year")) {
2093
						// Clean parameters
2094
						$value_key = dol_mktime(GETPOST($keysuffix."options_".$key.$keyprefix."hour", 'int'), GETPOST($keysuffix."options_".$key.$keyprefix."min", 'int'), GETPOST($keysuffix."options_".$key.$keyprefix."sec", 'int'), GETPOST($keysuffix."options_".$key.$keyprefix."month", 'int'), GETPOST($keysuffix."options_".$key.$keyprefix."day", 'int'), GETPOST($keysuffix."options_".$key.$keyprefix."year", 'int'), 'tzuserrel');
2095
					} else {
2096
						continue; // Value was not provided, we should not set it.
2097
					}
2098
				} elseif (in_array($key_type, array('checkbox', 'chkbxlst'))) {
2099
					if (!GETPOSTISSET($keysuffix."options_".$key.$keyprefix)) {
2100
						continue; // Value was not provided, we should not set it.
2101
					}
2102
					$value_arr = GETPOST($keysuffix."options_".$key.$keyprefix);
2103
					// Make sure we get an array even if there's only one checkbox
2104
					$value_arr = (array) $value_arr;
2105
					$value_key = implode(',', $value_arr);
2106
				} elseif (in_array($key_type, array('price', 'double', 'int'))) {
2107
					if (!GETPOSTISSET($keysuffix."options_".$key.$keyprefix)) {
2108
						continue; // Value was not provided, we should not set it.
2109
					}
2110
					$value_arr = GETPOST($keysuffix."options_".$key.$keyprefix);
2111
					if ($keysuffix != 'search_') {    // If value is for a search, we must keep complex string like '>100 <=150'
2112
						$value_key = price2num($value_arr);
2113
					} else {
2114
						$value_key = $value_arr;
2115
					}
2116
				} elseif (in_array($key_type, array('boolean'))) {
2117
					if (!GETPOSTISSET($keysuffix."options_".$key.$keyprefix)) {
2118
						$value_key = '';
2119
					} else {
2120
						$value_arr = GETPOST($keysuffix."options_".$key.$keyprefix);
2121
						$value_key = $value_arr;
2122
					}
2123
				} else {
2124
					if (!GETPOSTISSET($keysuffix."options_".$key.$keyprefix)) {
2125
						continue; // Value was not provided, we should not set it.
2126
					}
2127
					$value_key = GETPOST($keysuffix."options_".$key.$keyprefix);
2128
				}
2129
2130
				$array_options[$keysuffix."options_".$key] = $value_key; // No keyprefix here. keyprefix is used only for read.
2131
			}
2132
2133
			return $array_options;
2134
		}
2135
2136
		return 0;
2137
	}
2138
}
2139