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

ExtraFields::getAlignFlag()   C

Complexity

Conditions 13
Paths 60

Size

Total Lines 37
Code Lines 27

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 13
eloc 27
nc 60
nop 2
dl 0
loc 37
rs 6.6166
c 0
b 0
f 0

How to fix   Complexity   

Long Method

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

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

Commonly applied refactorings include:

1
<?php
2
/* Copyright (C) 2002-2003  Rodolphe Quiedeville    <[email protected]>
3
 * Copyright (C) 2002-2003  Jean-Louis Bergamo      <[email protected]>
4
 * Copyright (C) 2004       Sebastien Di Cintio     <[email protected]>
5
 * Copyright (C) 2004       Benoit Mortier          <[email protected]>
6
 * Copyright (C) 2009-2012  Laurent Destailleur     <[email protected]>
7
 * Copyright (C) 2009-2012  Regis Houssin           <[email protected]>
8
 * Copyright (C) 2013       Florian Henry           <[email protected]>
9
 * Copyright (C) 2015       Charles-Fr BENKE        <[email protected]>
10
 * Copyright (C) 2016       Raphaël Doursenaud      <[email protected]>
11
 * Copyright (C) 2017       Nicolas ZABOURI         <[email protected]>
12
 * Copyright (C) 2018-2021  Frédéric France         <[email protected]>
13
 *
14
 * This program is free software; you can redistribute it and/or modify
15
 * it under the terms of the GNU General Public License as published by
16
 * the Free Software Foundation; either version 3 of the License, or
17
 * (at your option) any later version.
18
 *
19
 * This program is distributed in the hope that it will be useful,
20
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22
 * GNU General Public License for more details.
23
 *
24
 * You should have received a copy of the GNU General Public License
25
 * along with this program. If not, see <https://www.gnu.org/licenses/>.
26
 */
27
28
/**
29
 * 	\file 		htdocs/core/class/extrafields.class.php
30
 *	\ingroup    core
31
 *	\brief      File of class to manage extra fields
32
 */
33
34
35
/**
36
 *	Class to manage standard extra fields
37
 */
38
class ExtraFields
39
{
40
	/**
41
	 * @var DoliDB Database handler.
42
	 */
43
	public $db;
44
45
	/**
46
	 * @var array Array with type of the extra field
47
	 * @deprecated
48
	 */
49
	public $attribute_type;
50
51
	/**
52
	 * @var array Array with label of extra field
53
	 * @deprecated
54
	 */
55
	public $attribute_label;
56
57
	/**
58
	 * @var array Array with list of possible values for some types of extra fields
59
	 * @deprecated
60
	 */
61
	public $attribute_choice;
62
63
64
	/**
65
	 * @var array New array to store extrafields definition
66
	 */
67
	public $attributes;
68
69
	/**
70
	 * @var 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