Passed
Branch develop (fc0f62)
by
unknown
74:53
created

ExtraFields::create()   F

Complexity

Conditions 25
Paths 536

Size

Total Lines 70
Code Lines 57

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 25
eloc 57
nc 536
nop 12
dl 0
loc 70
rs 0.6444
c 0
b 0
f 0

How to fix   Long Method    Complexity    Many Parameters   

Long Method

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

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

Commonly applied refactorings include:

Many Parameters

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

There are several approaches to avoid long parameter lists:

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