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

ExtraFields::fetch_name_optionals_label()   D

Complexity

Conditions 19
Paths 161

Size

Total Lines 87
Code Lines 55

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 19
eloc 55
nc 161
nop 2
dl 0
loc 87
rs 4.0083
c 0
b 0
f 0

How to fix   Long Method    Complexity   

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:

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