dolibarr 21.0.0-beta
extrafields.class.php
Go to the documentation of this file.
1<?php
2/* Copyright (C) 2002-2003 Rodolphe Quiedeville <rodolphe@quiedeville.org>
3 * Copyright (C) 2002-2003 Jean-Louis Bergamo <jlb@j1b.org>
4 * Copyright (C) 2004 Sebastien Di Cintio <sdicintio@ressource-toi.org>
5 * Copyright (C) 2004 Benoit Mortier <benoit.mortier@opensides.be>
6 * Copyright (C) 2009-2012 Laurent Destailleur <eldy@users.sourceforge.net>
7 * Copyright (C) 2009-2012 Regis Houssin <regis.houssin@inodbox.com>
8 * Copyright (C) 2013 Florian Henry <forian.henry@open-concept.pro>
9 * Copyright (C) 2015-2023 Charlene BENKE <charlene@patas-monkey.com>
10 * Copyright (C) 2016 Raphaël Doursenaud <rdoursenaud@gpcsolutions.fr>
11 * Copyright (C) 2017 Nicolas ZABOURI <info@inovea-conseil.com>
12 * Copyright (C) 2018-2024 Frédéric France <frederic.france@free.fr>
13 * Copyright (C) 2022 Antonin MARCHAL <antonin@letempledujeu.fr>
14 * Copyright (C) 2024 MDW <mdeweerd@users.noreply.github.com>
15 * Copyright (C) 2024 Benoît PASCAL <contact@p-ben.com>
16 *
17 * This program is free software; you can redistribute it and/or modify
18 * it under the terms of the GNU General Public License as published by
19 * the Free Software Foundation; either version 3 of the License, or
20 * (at your option) any later version.
21 *
22 * This program is distributed in the hope that it will be useful,
23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 * GNU General Public License for more details.
26 *
27 * You should have received a copy of the GNU General Public License
28 * along with this program. If not, see <https://www.gnu.org/licenses/>.
29 */
30
42{
46 public $db;
47
51 public $attributes = array();
52
56 public $expand_display;
57
61 public $error = '';
62
66 public $errors = array();
67
71 public $errno;
72
76 public static $type2label = array(
77 'varchar' => 'String1Line',
78 'text' => 'TextLongNLines',
79 'html' => 'HtmlText',
80 'int' => 'Int',
81 'double' => 'Float',
82 'date' => 'Date',
83 'datetime' => 'DateAndTime',
84 'duration' => 'Duration',
85 //'datetimegmt'=>'DateAndTimeUTC',
86 'boolean' => 'Boolean',
87 'price' => 'ExtrafieldPrice',
88 'pricecy' => 'ExtrafieldPriceWithCurrency',
89 'phone' => 'ExtrafieldPhone',
90 'mail' => 'ExtrafieldMail',
91 'url' => 'ExtrafieldUrl',
92 'ip' => 'ExtrafieldIP',
93 'icon' => 'Icon',
94 'password' => 'ExtrafieldPassword',
95 'radio' => 'ExtrafieldRadio',
96 'select' => 'ExtrafieldSelect',
97 'sellist' => 'ExtrafieldSelectList',
98 'checkbox' => 'ExtrafieldCheckBox',
99 'chkbxlst' => 'ExtrafieldCheckBoxFromList',
100 'link' => 'ExtrafieldLink',
101 'point' => 'ExtrafieldPointGeo',
102 'multipts' => 'ExtrafieldMultiPointGeo',
103 'linestrg' => 'ExtrafieldLinestringGeo',
104 'polygon' => 'ExtrafieldPolygonGeo',
105 'separate' => 'ExtrafieldSeparator',
106 'stars' => 'ExtrafieldStars',
107 );
108
114 public function __construct($db)
115 {
116 $this->db = $db;
117 }
118
145 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, $moreparams = array())
146 {
147 if (empty($attrname)) {
148 return -1;
149 }
150 if (empty($label)) {
151 return -1;
152 }
153
154 $result = 0;
155
156 // Clean properties
157 if ($type == 'separator' || $type == 'separate') {
158 $type = 'separate';
159 $unique = 0;
160 $required = 0;
161 } // Force unique and not required if this is a separator field to avoid troubles.
162 if ($elementtype == 'thirdparty') {
163 $elementtype = 'societe';
164 }
165 if ($elementtype == 'contact') {
166 $elementtype = 'socpeople';
167 }
168 // If property has a computed formula, it must not be a required or unique field
169 if (!empty($computed)) {
170 $required = 0;
171 $unique = 0;
172 }
173
174 // Create field into database except for separator type which is not stored in database
175 if ($type != 'separate') {
176 $result = $this->create($attrname, $type, $size, $elementtype, $unique, $required, $default_value, $param, $perms, $list, $computed, $help, $moreparams);
177 }
178 $err1 = $this->errno;
179 if ($result > 0 || $err1 == 'DB_ERROR_COLUMN_ALREADY_EXISTS' || $type == 'separate') {
180 // Add declaration of field into table
181 $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, $moreparams);
182 $err2 = $this->errno;
183 if ($result2 > 0
184 || ($err1 == 'DB_ERROR_COLUMN_ALREADY_EXISTS' && $err2 == 'DB_ERROR_RECORD_ALREADY_EXISTS')
185 || ($type == 'separate' && $err2 == 'DB_ERROR_RECORD_ALREADY_EXISTS')) {
186 $this->error = '';
187 $this->errno = '0';
188 return 1;
189 } else {
190 return -2;
191 }
192 } else {
193 return -1;
194 }
195 }
196
223 public function updateExtraField($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, $moreparams = array())
224 {
225 if (empty($attrname)) {
226 return -1;
227 }
228 if (empty($label)) {
229 return -1;
230 }
231
232 $result = 0;
233
234 if ($type == 'separator' || $type == 'separate') {
235 $type = 'separate';
236 $unique = 0;
237 $required = 0;
238 } // Force unique and not required if this is a separator field to avoid troubles.
239 if ($elementtype == 'thirdparty') {
240 $elementtype = 'societe';
241 }
242 if ($elementtype == 'contact') {
243 $elementtype = 'socpeople';
244 }
245
246 // Create field into database except for separator type which is not stored in database
247 if ($type != 'separate') {
248 dol_syslog(get_class($this).'::thisupdate', LOG_DEBUG);
249 $result = $this->update($attrname, $label, $type, $size, $elementtype, $unique, $required, $pos, $param, $alwayseditable, $perms, $list, $help, $default_value, $computed, $entity, $langfile, $enabled, $totalizable, $printable, $moreparams);
250 }
251 $err1 = $this->errno;
252 if ($result > 0 || $err1 == 'DB_ERROR_COLUMN_ALREADY_EXISTS' || $type == 'separate') {
253 // Add declaration of field into table
254 dol_syslog(get_class($this).'::thislabel', LOG_DEBUG);
255 $result2 = $this->update_label($attrname, $label, $type, $size, $elementtype, $unique, $required, $pos, $param, $alwayseditable, $perms, $list, $help, $default_value, $computed, $entity, $langfile, $enabled, $totalizable, $printable, $moreparams);
256 $err2 = $this->errno;
257 if ($result2 > 0 || ($err1 == 'DB_ERROR_COLUMN_ALREADY_EXISTS' && $err2 == 'DB_ERROR_RECORD_ALREADY_EXISTS')) {
258 $this->error = '';
259 $this->errno = '0';
260 return 1;
261 } else {
262 return -2;
263 }
264 } else {
265 return -1;
266 }
267 }
268
288 private function create($attrname, $type = 'varchar', $length = '255', $elementtype = '', $unique = 0, $required = 0, $default_value = '', $param = array(), $perms = '', $list = '0', $computed = '', $help = '', $moreparams = array())
289 {
290 if ($elementtype == 'thirdparty') {
291 $elementtype = 'societe';
292 }
293 if ($elementtype == 'contact') {
294 $elementtype = 'socpeople';
295 }
296
297 $table = $elementtype.'_extrafields';
298 if ($elementtype == 'categorie') {
299 $table = 'categories_extrafields';
300 }
301
302 if (!empty($attrname) && preg_match("/^\w[a-zA-Z0-9_]*$/", $attrname) && !is_numeric($attrname)) {
303 if ($type == 'boolean') {
304 $typedb = 'int';
305 $lengthdb = '1';
306 } elseif ($type == 'price') {
307 $typedb = 'double';
308 $lengthdb = '24,8';
309 } elseif ($type == 'pricecy') {
310 $typedb = 'varchar';
311 $lengthdb = '64';
312 } elseif ($type == 'phone') {
313 $typedb = 'varchar';
314 $lengthdb = '20';
315 } elseif ($type == 'mail' || $type == 'ip' || $type == 'icon') {
316 $typedb = 'varchar';
317 $lengthdb = '128';
318 } elseif ($type == 'url') {
319 $typedb = 'varchar';
320 $lengthdb = '255';
321 } elseif (($type == 'select') || ($type == 'sellist') || ($type == 'radio') || ($type == 'checkbox') || ($type == 'chkbxlst')) {
322 $typedb = 'varchar';
323 $lengthdb = '255';
324 } elseif ($type == 'link') {
325 $typedb = 'int';
326 $lengthdb = '11';
327 } elseif ($type == 'duration') {
328 $typedb = 'int';
329 $lengthdb = '11';
330 } elseif ($type == 'point') {
331 $typedb = 'point';
332 $lengthdb = '';
333 } elseif ($type == 'multipts') {
334 $typedb = 'multipoint';
335 $lengthdb = '';
336 } elseif ($type == 'linestrg') {
337 $typedb = 'linestring';
338 $lengthdb = '';
339 } elseif ($type == 'polygon') {
340 $typedb = 'polygon';
341 $lengthdb = '';
342 } elseif ($type == 'html') {
343 $typedb = 'text';
344 $lengthdb = $length;
345 } elseif ($type == 'password') {
346 $typedb = 'varchar';
347 $lengthdb = '128';
348 } elseif ($type == 'stars') {
349 $typedb = 'int';
350 $lengthdb = $length;
351 } else {
352 $typedb = $type;
353 $lengthdb = $length;
354 if ($type == 'varchar' && empty($lengthdb)) {
355 $lengthdb = '255';
356 }
357 }
358 $field_desc = array(
359 'type' => $typedb,
360 'value' => $lengthdb,
361 'null' => ($required ? 'NOT NULL' : 'NULL'),
362 'default' => $default_value
363 );
364
365 $result = $this->db->DDLAddField($this->db->prefix().$this->db->sanitize($table), $attrname, $field_desc);
366 if ($result > 0) {
367 if ($unique) {
368 $sql = "ALTER TABLE ".$this->db->prefix().$this->db->sanitize($table)." ADD UNIQUE INDEX uk_".$this->db->sanitize($table)."_".$attrname." (".$attrname.")";
369 $resql = $this->db->query($sql, 1, 'dml');
370 }
371 return 1;
372 } else {
373 $this->error = $this->db->lasterror();
374 $this->errno = $this->db->lasterrno();
375 return -1;
376 }
377 } else {
378 return 0;
379 }
380 }
381
382 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
410 private function create_label($attrname, $label = '', $type = '', $pos = 0, $size = '', $elementtype = '', $unique = 0, $required = 0, $param = '', $alwayseditable = 0, $perms = '', $list = '-1', $help = '', $default = '', $computed = '', $entity = '', $langfile = '', $enabled = '1', $totalizable = 0, $printable = 0, $moreparams = array())
411 {
412 // phpcs:enable
413 global $conf, $user;
414
415 if ($elementtype == 'thirdparty') {
416 $elementtype = 'societe';
417 }
418 if ($elementtype == 'contact') {
419 $elementtype = 'socpeople';
420 }
421
422 // Clean parameters
423 if (empty($pos)) {
424 $pos = 0;
425 }
426 if (empty($list)) {
427 $list = '0';
428 }
429 if (empty($required)) {
430 $required = 0;
431 }
432 if (empty($unique)) {
433 $unique = 0;
434 }
435 if (empty($printable)) {
436 $printable = 0;
437 }
438 if (empty($alwayseditable)) {
439 $alwayseditable = 0;
440 }
441 if (empty($totalizable)) {
442 $totalizable = 0;
443 }
444
445 $css = '';
446 if (!empty($moreparams) && !empty($moreparams['css'])) {
447 $css = $moreparams['css'];
448 }
449 $csslist = '';
450 if (!empty($moreparams) && !empty($moreparams['csslist'])) {
451 $csslist = $moreparams['csslist'];
452 }
453 $cssview = '';
454 if (!empty($moreparams) && !empty($moreparams['cssview'])) {
455 $cssview = $moreparams['cssview'];
456 }
457
458 if (!empty($attrname) && preg_match("/^\w[a-zA-Z0-9-_]*$/", $attrname) && !is_numeric($attrname)) {
459 if (is_array($param) && count($param) > 0) {
460 $params = serialize($param);
461 } elseif (strlen($param) > 0) {
462 $params = trim($param);
463 } else {
464 $params = '';
465 }
466
467 $sql = "INSERT INTO ".$this->db->prefix()."extrafields(";
468 $sql .= " name,";
469 $sql .= " label,";
470 $sql .= " type,";
471 $sql .= " pos,";
472 $sql .= " size,";
473 $sql .= " entity,";
474 $sql .= " elementtype,";
475 $sql .= " fieldunique,";
476 $sql .= " fieldrequired,";
477 $sql .= " param,";
478 $sql .= " alwayseditable,";
479 $sql .= " perms,";
480 $sql .= " langs,";
481 $sql .= " list,";
482 $sql .= " printable,";
483 $sql .= " fielddefault,";
484 $sql .= " fieldcomputed,";
485 $sql .= " fk_user_author,";
486 $sql .= " fk_user_modif,";
487 $sql .= " datec,";
488 $sql .= " enabled,";
489 $sql .= " help,";
490 $sql .= " totalizable,";
491 $sql .= " css,";
492 $sql .= " csslist,";
493 $sql .= " cssview";
494 $sql .= " )";
495 $sql .= " VALUES('".$this->db->escape($attrname)."',";
496 $sql .= " '".$this->db->escape($label)."',";
497 $sql .= " '".$this->db->escape($type)."',";
498 $sql .= " ".((int) $pos).",";
499 $sql .= " '".$this->db->escape($size)."',";
500 $sql .= " ".($entity === '' ? $conf->entity : $entity).",";
501 $sql .= " '".$this->db->escape($elementtype)."',";
502 $sql .= " ".((int) $unique).",";
503 $sql .= " ".((int) $required).",";
504 $sql .= " '".$this->db->escape($params)."',";
505 $sql .= " ".((int) $alwayseditable).",";
506 $sql .= " ".($perms ? "'".$this->db->escape($perms)."'" : "null").",";
507 $sql .= " ".($langfile ? "'".$this->db->escape($langfile)."'" : "null").",";
508 $sql .= " '".$this->db->escape($list)."',";
509 $sql .= " '".$this->db->escape($printable)."',";
510 $sql .= " ".($default ? "'".$this->db->escape($default)."'" : "null").",";
511 $sql .= " ".($computed ? "'".$this->db->escape($computed)."'" : "null").",";
512 $sql .= " ".(is_object($user) ? $user->id : 0).",";
513 $sql .= " ".(is_object($user) ? $user->id : 0).",";
514 $sql .= "'".$this->db->idate(dol_now())."',";
515 $sql .= " ".($enabled ? "'".$this->db->escape($enabled)."'" : "1").",";
516 $sql .= " ".($help ? "'".$this->db->escape($help)."'" : "null").",";
517 $sql .= " ".($totalizable ? 'TRUE' : 'FALSE').",";
518 $sql .= " ".($css ? "'".$this->db->escape($css)."'" : "null").",";
519 $sql .= " ".($csslist ? "'".$this->db->escape($csslist)."'" : "null").",";
520 $sql .= " ".($cssview ? "'".$this->db->escape($cssview)."'" : "null");
521 $sql .= ')';
522
523 if ($this->db->query($sql)) {
524 dol_syslog(get_class($this)."::create_label_success", LOG_DEBUG);
525 return 1;
526 } else {
527 dol_syslog(get_class($this)."::create_label_error", LOG_DEBUG);
528 $this->error = $this->db->lasterror();
529 $this->errno = $this->db->lasterrno();
530 return -1;
531 }
532 }
533 return -1;
534 }
535
543 public function delete($attrname, $elementtype = '')
544 {
545 if ($elementtype == 'thirdparty') {
546 $elementtype = 'societe';
547 }
548 if ($elementtype == 'contact') {
549 $elementtype = 'socpeople';
550 }
551
552 $table = $elementtype.'_extrafields';
553 if ($elementtype == 'categorie') {
554 $table = 'categories_extrafields';
555 }
556
557 $error = 0;
558
559 if (!empty($attrname) && preg_match("/^\w[a-zA-Z0-9-_]*$/", $attrname)) {
560 $result = $this->delete_label($attrname, $elementtype);
561 if ($result < 0) {
562 $this->error = $this->db->lasterror();
563 $this->errors[] = $this->db->lasterror();
564 $error++;
565 }
566
567 if (!$error) {
568 $sql = "SELECT COUNT(rowid) as nb";
569 $sql .= " FROM ".$this->db->prefix()."extrafields";
570 $sql .= " WHERE elementtype = '".$this->db->escape($elementtype)."'";
571 $sql .= " AND name = '".$this->db->escape($attrname)."'";
572 //$sql.= " AND entity IN (0,".$conf->entity.")"; Do not test on entity here. We want to see if there is still on field remaining in other entities before deleting field in table
573 $resql = $this->db->query($sql);
574 if ($resql) {
575 $obj = $this->db->fetch_object($resql);
576 if ($obj->nb <= 0) {
577 $result = $this->db->DDLDropField($this->db->prefix().$table, $attrname); // This also drop the unique key
578 if ($result < 0) {
579 $this->error = $this->db->lasterror();
580 $this->errors[] = $this->db->lasterror();
581 $error++;
582 }
583 }
584 } else {
585 $this->error = $this->db->lasterror();
586 $this->errors[] = $this->db->lasterror();
587 $error++;
588 }
589 }
590 if (empty($error)) {
591 return $result;
592 } else {
593 return $error * -1;
594 }
595 } else {
596 return 0;
597 }
598 }
599
600 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
608 private function delete_label($attrname, $elementtype = '')
609 {
610 // phpcs:enable
611 global $conf;
612
613 if ($elementtype == 'thirdparty') {
614 $elementtype = 'societe';
615 }
616 if ($elementtype == 'contact') {
617 $elementtype = 'socpeople';
618 }
619
620 if (isset($attrname) && $attrname != '' && preg_match("/^\w[a-zA-Z0-9-_]*$/", $attrname)) {
621 $sql = "DELETE FROM ".$this->db->prefix()."extrafields";
622 $sql .= " WHERE name = '".$this->db->escape($attrname)."'";
623 $sql .= " AND entity IN (0,".$conf->entity.')';
624 if (!empty($elementtype)) {
625 $sql .= " AND elementtype = '".$this->db->escape($elementtype)."'";
626 }
627
628 dol_syslog(get_class($this)."::delete_label", LOG_DEBUG);
629 $resql = $this->db->query($sql);
630 if ($resql) {
631 return 1;
632 } else {
633 dol_print_error($this->db);
634 return -1;
635 }
636 } else {
637 return 0;
638 }
639 }
640
668 public function update($attrname, $label, $type, $length, $elementtype, $unique = 0, $required = 0, $pos = 0, $param = array(), $alwayseditable = 0, $perms = '', $list = '', $help = '', $default = '', $computed = '', $entity = '', $langfile = '', $enabled = '1', $totalizable = 0, $printable = 0, $moreparams = array())
669 {
670 global $action, $hookmanager;
671
672 $result = 0;
673
674 if ($elementtype == 'thirdparty') {
675 $elementtype = 'societe';
676 }
677 if ($elementtype == 'contact') {
678 $elementtype = 'socpeople';
679 }
680
681 $table = $elementtype.'_extrafields';
682 if ($elementtype == 'categorie') {
683 $table = 'categories_extrafields';
684 }
685
686 if (isset($attrname) && $attrname != '' && preg_match("/^\w[a-zA-Z0-9-_]*$/", $attrname)) {
687 // Clean parameters
688 if ($type == 'boolean') {
689 $typedb = 'int';
690 $lengthdb = '1';
691 } elseif ($type == 'price') {
692 $typedb = 'double';
693 $lengthdb = '24,8';
694 } elseif ($type == 'pricecy') {
695 $typedb = 'varchar';
696 $lengthdb = '64';
697 } elseif ($type == 'phone') {
698 $typedb = 'varchar';
699 $lengthdb = '20';
700 } elseif ($type == 'mail' || $type == 'ip' || $type == 'icon') {
701 $typedb = 'varchar';
702 $lengthdb = '128';
703 } elseif ($type == 'url') {
704 $typedb = 'varchar';
705 $lengthdb = '255';
706 } elseif (($type == 'select') || ($type == 'sellist') || ($type == 'radio') || ($type == 'checkbox') || ($type == 'chkbxlst')) {
707 $typedb = 'varchar';
708 $lengthdb = '255';
709 } elseif ($type == 'html') {
710 $typedb = 'text';
711 $lengthdb = $length;
712 } elseif ($type == 'link') {
713 $typedb = 'int';
714 $lengthdb = '11';
715 } elseif ($type == 'duration') {
716 $typedb = 'int';
717 $lengthdb = '11';
718 } elseif ($type == 'point') {
719 $typedb = 'point';
720 $lengthdb = '';
721 } elseif ($type == 'multipts') {
722 $typedb = 'multipoint';
723 $lengthdb = '';
724 } elseif ($type == 'linestrg') {
725 $typedb = 'linestring';
726 $lengthdb = '';
727 } elseif ($type == 'polygon') {
728 $typedb = 'polygon';
729 $lengthdb = '';
730 } elseif ($type == 'password') {
731 $typedb = 'varchar';
732 $lengthdb = '128';
733 } elseif ($type == 'stars') {
734 $typedb = 'int';
735 $lengthdb = $length;
736 } else {
737 $typedb = $type;
738 $lengthdb = $length;
739 }
740 $field_desc = array('type' => $typedb, 'value' => $lengthdb, 'null' => ($required ? 'NOT NULL' : 'NULL'), 'default' => $default);
741
742 // If property has a computed formula, it must not be a required or unique field
743 if (!empty($computed)) {
744 $required = 0;
745 $unique = 0;
746 }
747
748 if (is_object($hookmanager)) {
749 $hookmanager->initHooks(array('extrafieldsdao'));
750 $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);
751 $reshook = $hookmanager->executeHooks('updateExtrafields', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
752
753 if ($reshook < 0) {
754 $this->error = $this->db->lasterror();
755 return -1;
756 }
757 }
758
759 dol_syslog(get_class($this).'::DDLUpdateField', LOG_DEBUG);
760 if ($type != 'separate') { // No table update when separate type
761 $result = $this->db->DDLUpdateField($this->db->prefix().$table, $attrname, $field_desc);
762 }
763 if ($result > 0 || $type == 'separate') {
764 if ($label) {
765 dol_syslog(get_class($this).'::update_label', LOG_DEBUG);
766 $result = $this->update_label($attrname, $label, $type, $length, $elementtype, $unique, $required, $pos, $param, $alwayseditable, $perms, $list, $help, $default, $computed, $entity, $langfile, $enabled, $totalizable, $printable, $moreparams);
767 }
768 if ($result > 0) {
769 $sql = '';
770 if ($unique) {
771 dol_syslog(get_class($this).'::update_unique', LOG_DEBUG);
772 $sql = "ALTER TABLE ".$this->db->prefix().$table." ADD UNIQUE INDEX uk_".$table."_".$this->db->sanitize($attrname)." (".$this->db->sanitize($attrname).")";
773 } else {
774 dol_syslog(get_class($this).'::update_common', LOG_DEBUG);
775 $sql = "ALTER TABLE ".$this->db->prefix().$table." DROP INDEX IF EXISTS uk_".$table."_".$this->db->sanitize($attrname);
776 }
777 dol_syslog(get_class($this).'::update', LOG_DEBUG);
778 $resql = $this->db->query($sql, 1, 'dml');
779 /*if ($resql < 0) {
780 $this->error = $this->db->lasterror();
781 return -1;
782 }*/
783 return 1;
784 } else {
785 $this->error = $this->db->lasterror();
786 return -1;
787 }
788 } else {
789 $this->error = $this->db->lasterror();
790 return -1;
791 }
792 } else {
793 return 0;
794 }
795 }
796
797 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
826 private function update_label($attrname, $label, $type, $size, $elementtype, $unique = 0, $required = 0, $pos = 0, $param = array(), $alwayseditable = 0, $perms = '', $list = '0', $help = '', $default = '', $computed = '', $entity = '', $langfile = '', $enabled = '1', $totalizable = 0, $printable = 0, $moreparams = array())
827 {
828 // phpcs:enable
829 global $conf, $user;
830 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);
831
832 // Clean parameters
833 if ($elementtype == 'thirdparty') {
834 $elementtype = 'societe';
835 }
836 if ($elementtype == 'contact') {
837 $elementtype = 'socpeople';
838 }
839
840 if (empty($pos)) {
841 $pos = 0;
842 }
843 if (empty($list)) {
844 $list = '0';
845 }
846 if (empty($totalizable)) {
847 $totalizable = 0;
848 }
849 if (empty($required)) {
850 $required = 0;
851 }
852 if (empty($unique)) {
853 $unique = 0;
854 }
855 if (empty($alwayseditable)) {
856 $alwayseditable = 0;
857 }
858
859 $css = '';
860 if (!empty($moreparams) && !empty($moreparams['css'])) {
861 $css = $moreparams['css'];
862 }
863 $csslist = '';
864 if (!empty($moreparams) && !empty($moreparams['csslist'])) {
865 $csslist = $moreparams['csslist'];
866 }
867 $cssview = '';
868 if (!empty($moreparams) && !empty($moreparams['cssview'])) {
869 $cssview = $moreparams['cssview'];
870 }
871
872 if (isset($attrname) && $attrname != '' && preg_match("/^\w[a-zA-Z0-9-_]*$/", $attrname)) {
873 $this->db->begin();
874
875 if (is_array($param) && count($param) > 0) {
876 $params = serialize($param);
877 } elseif (is_array($param)) {
878 $params = '';
879 } elseif (strlen($param) > 0) {
880 $params = trim($param);
881 } else {
882 $params = '';
883 }
884
885 if ($entity === '' || $entity != '0') {
886 // We don't want on all entities, we delete all and current
887 $sql_del = "DELETE FROM ".$this->db->prefix()."extrafields";
888 $sql_del .= " WHERE name = '".$this->db->escape($attrname)."'";
889 $sql_del .= " AND entity IN (0, ".($entity === '' ? $conf->entity : $entity).")";
890 $sql_del .= " AND elementtype = '".$this->db->escape($elementtype)."'";
891 } else {
892 // We want on all entities ($entities = '0'), we delete on all only (we keep setup specific to each entity)
893 $sql_del = "DELETE FROM ".$this->db->prefix()."extrafields";
894 $sql_del .= " WHERE name = '".$this->db->escape($attrname)."'";
895 $sql_del .= " AND entity = 0";
896 $sql_del .= " AND elementtype = '".$this->db->escape($elementtype)."'";
897 }
898 $resql1 = $this->db->query($sql_del);
899
900 $sql = "INSERT INTO ".$this->db->prefix()."extrafields(";
901 $sql .= " name,"; // This is code
902 $sql .= " entity,";
903 $sql .= " label,";
904 $sql .= " type,";
905 $sql .= " size,";
906 $sql .= " elementtype,";
907 $sql .= " fieldunique,";
908 $sql .= " fieldrequired,";
909 $sql .= " perms,";
910 $sql .= " langs,";
911 $sql .= " pos,";
912 $sql .= " alwayseditable,";
913 $sql .= " param,";
914 $sql .= " list,";
915 $sql .= " printable,";
916 $sql .= " totalizable,";
917 $sql .= " fielddefault,";
918 $sql .= " fieldcomputed,";
919 $sql .= " fk_user_author,";
920 $sql .= " fk_user_modif,";
921 $sql .= " datec,";
922 $sql .= " enabled,";
923 $sql .= " help,";
924 $sql .= " css,";
925 $sql .= " csslist,";
926 $sql .= " cssview";
927 $sql .= ") VALUES (";
928 $sql .= "'".$this->db->escape($attrname)."',";
929 $sql .= " ".($entity === '' ? $conf->entity : $entity).",";
930 $sql .= " '".$this->db->escape($label)."',";
931 $sql .= " '".$this->db->escape($type)."',";
932 $sql .= " '".$this->db->escape($size)."',";
933 $sql .= " '".$this->db->escape($elementtype)."',";
934 $sql .= " ".((int) $unique).",";
935 $sql .= " ".((int) $required).",";
936 $sql .= " ".($perms ? "'".$this->db->escape($perms)."'" : "null").",";
937 $sql .= " ".($langfile ? "'".$this->db->escape($langfile)."'" : "null").",";
938 $sql .= " ".((int) $pos).",";
939 $sql .= " '".$this->db->escape($alwayseditable)."',";
940 $sql .= " '".$this->db->escape($params)."',";
941 $sql .= " '".$this->db->escape($list)."',";
942 $sql .= " ".((int) $printable).",";
943 $sql .= " ".($totalizable ? 'TRUE' : 'FALSE').",";
944 $sql .= " ".(($default != '') ? "'".$this->db->escape($default)."'" : "null").",";
945 $sql .= " ".($computed ? "'".$this->db->escape($computed)."'" : "null").",";
946 $sql .= " ".((int) $user->id).",";
947 $sql .= " ".((int) $user->id).",";
948 $sql .= "'".$this->db->idate(dol_now())."',";
949 $sql .= "'".$this->db->escape($enabled)."',";
950 $sql .= " ".($help ? "'".$this->db->escape($help)."'" : "null").",";
951 $sql .= " ".($css ? "'".$this->db->escape($css)."'" : "null").",";
952 $sql .= " ".($csslist ? "'".$this->db->escape($csslist)."'" : "null").",";
953 $sql .= " ".($cssview ? "'".$this->db->escape($cssview)."'" : "null");
954 $sql .= ")";
955
956 $resql2 = $this->db->query($sql);
957
958 if ($resql1 && $resql2) {
959 $this->db->commit();
960 return 1;
961 } else {
962 $this->db->rollback();
963 dol_print_error($this->db);
964 return -1;
965 }
966 } else {
967 return 0;
968 }
969 }
970
971 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
981 public function fetch_name_optionals_label($elementtype, $forceload = false, $attrname = '')
982 {
983 // phpcs:enable
984 global $conf;
985
986 if (empty($elementtype)) {
987 return array();
988 }
989
990 if ($elementtype == 'thirdparty') {
991 $elementtype = 'societe';
992 }
993 if ($elementtype == 'contact') {
994 $elementtype = 'socpeople';
995 }
996 if ($elementtype == 'order_supplier') {
997 $elementtype = 'commande_fournisseur';
998 }
999
1000 // Test cache $this->attributes[$elementtype]['loaded'] to see if we must do something
1001 // TODO
1002
1003 $array_name_label = array();
1004
1005 // 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
1006 $sql = "SELECT rowid, name, label, type, size, elementtype, fieldunique, fieldrequired, param, pos, alwayseditable, perms, langs, list, printable, totalizable, fielddefault, fieldcomputed, entity, enabled, help,";
1007 $sql .= " css, cssview, csslist";
1008 $sql .= " FROM ".$this->db->prefix()."extrafields";
1009 //$sql.= " WHERE entity IN (0,".$conf->entity.")"; // Filter is done later
1010 if ($elementtype && $elementtype != 'all') {
1011 $sql .= " WHERE elementtype = '".$this->db->escape($elementtype)."'"; // Filed with object->table_element
1012 }
1013 if ($attrname && $elementtype && $elementtype != 'all') {
1014 $sql .= " AND name = '".$this->db->escape($attrname)."'";
1015 }
1016 $sql .= " ORDER BY pos";
1017
1018 $resql = $this->db->query($sql);
1019 if ($resql) {
1020 $count = 0;
1021 if ($this->db->num_rows($resql)) {
1022 while ($tab = $this->db->fetch_object($resql)) {
1023 if ($tab->entity != 0 && $tab->entity != $conf->entity) {
1024 // 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
1025 if ($tab->fieldrequired && is_null($tab->fielddefault)) {
1026 $this->attributes[$tab->elementtype]['mandatoryfieldsofotherentities'][$tab->name] = $tab->type;
1027 }
1028 continue;
1029 }
1030
1031 // We can add this attribute to object. TODO Remove this and return $this->attributes[$elementtype]['label']
1032 if ($tab->type != 'separate') {
1033 $array_name_label[$tab->name] = $tab->label;
1034 }
1035
1036
1037 $this->attributes[$tab->elementtype]['type'][$tab->name] = $tab->type;
1038 $this->attributes[$tab->elementtype]['label'][$tab->name] = $tab->label;
1039 $this->attributes[$tab->elementtype]['size'][$tab->name] = $tab->size;
1040 $this->attributes[$tab->elementtype]['elementtype'][$tab->name] = $tab->elementtype;
1041 $this->attributes[$tab->elementtype]['default'][$tab->name] = $tab->fielddefault;
1042 $this->attributes[$tab->elementtype]['computed'][$tab->name] = $tab->fieldcomputed;
1043 $this->attributes[$tab->elementtype]['unique'][$tab->name] = $tab->fieldunique;
1044 $this->attributes[$tab->elementtype]['required'][$tab->name] = $tab->fieldrequired;
1045 $this->attributes[$tab->elementtype]['param'][$tab->name] = ($tab->param ? jsonOrUnserialize($tab->param) : '');
1046 $this->attributes[$tab->elementtype]['pos'][$tab->name] = $tab->pos;
1047 $this->attributes[$tab->elementtype]['alwayseditable'][$tab->name] = $tab->alwayseditable;
1048 $this->attributes[$tab->elementtype]['perms'][$tab->name] = ((is_null($tab->perms) || strlen($tab->perms) == 0) ? 1 : $tab->perms);
1049 $this->attributes[$tab->elementtype]['langfile'][$tab->name] = $tab->langs;
1050 $this->attributes[$tab->elementtype]['list'][$tab->name] = $tab->list;
1051 $this->attributes[$tab->elementtype]['printable'][$tab->name] = $tab->printable;
1052 $this->attributes[$tab->elementtype]['totalizable'][$tab->name] = ($tab->totalizable ? 1 : 0);
1053 $this->attributes[$tab->elementtype]['entityid'][$tab->name] = $tab->entity;
1054 $this->attributes[$tab->elementtype]['enabled'][$tab->name] = $tab->enabled;
1055 $this->attributes[$tab->elementtype]['help'][$tab->name] = $tab->help;
1056 $this->attributes[$tab->elementtype]['css'][$tab->name] = $tab->css;
1057 $this->attributes[$tab->elementtype]['cssview'][$tab->name] = $tab->cssview;
1058 $this->attributes[$tab->elementtype]['csslist'][$tab->name] = $tab->csslist;
1059
1060 $this->attributes[$tab->elementtype]['loaded'] = 1;
1061 $count++;
1062 }
1063 }
1064 if ($elementtype) {
1065 $this->attributes[$elementtype]['loaded'] = 1; // Note: If nothing is found, we also set the key 'loaded' to 1.
1066 $this->attributes[$elementtype]['count'] = $count;
1067 }
1068 } else {
1069 $this->error = $this->db->lasterror();
1070 dol_syslog(get_class($this)."::fetch_name_optionals_label ".$this->error, LOG_ERR);
1071 }
1072
1073 return $array_name_label;
1074 }
1075
1076
1092 public function showInputField($key, $value, $moreparam = '', $keysuffix = '', $keyprefix = '', $morecss = '', $object = 0, $extrafieldsobjectkey = '', $mode = 0)
1093 {
1094 global $conf, $langs, $form;
1095
1096 if (!is_object($form)) {
1097 require_once DOL_DOCUMENT_ROOT.'/core/class/html.form.class.php';
1098 $form = new Form($this->db);
1099 }
1100
1101 $objectid = (is_numeric($object) ? $object : $object->id);
1102
1103 $out = '';
1104
1105 if (!preg_match('/options_$/', $keyprefix)) { // Because we work on extrafields, we add 'options_' to prefix if not already added
1106 $keyprefix .= 'options_';
1107 }
1108
1109 if (empty($extrafieldsobjectkey)) {
1110 dol_syslog(get_class($this).'::showInputField extrafieldsobjectkey required', LOG_ERR);
1111 return 'BadValueForParamExtraFieldsObjectKey';
1112 }
1113
1114 $label = $this->attributes[$extrafieldsobjectkey]['label'][$key];
1115 $type = $this->attributes[$extrafieldsobjectkey]['type'][$key];
1116 $size = $this->attributes[$extrafieldsobjectkey]['size'][$key];
1117 $default = $this->attributes[$extrafieldsobjectkey]['default'][$key];
1118 $computed = $this->attributes[$extrafieldsobjectkey]['computed'][$key];
1119 $unique = $this->attributes[$extrafieldsobjectkey]['unique'][$key];
1120 $required = $this->attributes[$extrafieldsobjectkey]['required'][$key];
1121 $param = $this->attributes[$extrafieldsobjectkey]['param'][$key];
1122 $perms = (int) dol_eval($this->attributes[$extrafieldsobjectkey]['perms'][$key], 1, 1, '2');
1123 $langfile = $this->attributes[$extrafieldsobjectkey]['langfile'][$key];
1124 $list = (string) dol_eval($this->attributes[$extrafieldsobjectkey]['list'][$key], 1, 1, '2');
1125 $totalizable = $this->attributes[$extrafieldsobjectkey]['totalizable'][$key];
1126 $help = $this->attributes[$extrafieldsobjectkey]['help'][$key];
1127 $alwayseditable = $this->attributes[$extrafieldsobjectkey]['alwayseditable'][$key];
1128 $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)
1129
1130 //var_dump('key='.$key.' '.$value.' '.$moreparam.' '.$keysuffix.' '.$keyprefix.' '.$objectid.' '.$extrafieldsobjectkey.' '.$mode);
1131 //var_dump('label='.$label.' type='.$type.' param='.var_export($param, 1));
1132
1133 if ($computed) {
1134 if (!preg_match('/^search_/', $keyprefix)) {
1135 return '<span class="opacitymedium">'.$langs->trans("AutomaticallyCalculated").'</span>';
1136 } else {
1137 return '';
1138 }
1139 }
1140
1141 //
1142 // 'css' is used in creation and update. 'cssview' is used in view mode. 'csslist' is used for columns in lists. For example: 'css'=>'minwidth300 maxwidth500 widthcentpercentminusx', 'cssview'=>'wordbreak', 'csslist'=>'tdoverflowmax200'
1143 if (empty($morecss)) {
1144 // Add automatic css
1145 if ($type == 'date') {
1146 $morecss = 'minwidth100imp';
1147 } elseif ($type == 'datetime' || $type == 'datetimegmt' || $type == 'link') {
1148 $morecss = 'minwidth200imp';
1149 } elseif (in_array($type, array('int', 'integer', 'double', 'price'))) {
1150 $morecss = 'maxwidth75';
1151 } elseif ($type == 'password') {
1152 $morecss = 'maxwidth100';
1153 } elseif ($type == 'url') {
1154 $morecss = 'minwidth400';
1155 } elseif ($type == 'boolean') {
1156 $morecss = '';
1157 } elseif ($type == 'radio') {
1158 $morecss = 'width25';
1159 } else {
1160 if (empty($size) || round((float) $size) < 12) {
1161 $morecss = 'minwidth100';
1162 } elseif (round((float) $size) <= 48) {
1163 $morecss = 'minwidth200';
1164 } else {
1165 $morecss = 'minwidth400';
1166 }
1167 }
1168 // If css forced in attribute, we use this one
1169 if (!empty($this->attributes[$extrafieldsobjectkey]['css'][$key])) {
1170 $morecss = $this->attributes[$extrafieldsobjectkey]['css'][$key];
1171 }
1172 }
1173
1174 if (in_array($type, array('date'))) {
1175 $tmp = explode(',', $size);
1176 $newsize = $tmp[0];
1177 $showtime = 0;
1178
1179 // Do not show current date when field not required (see selectDate() method)
1180 if (!$required && $value == '') {
1181 $value = '-1';
1182 }
1183
1184 if ($mode == 1) {
1185 // search filter on a date extrafield shows two inputs to select a date range
1186 $prefill = array(
1187 'start' => isset($value['start']) ? $value['start'] : '',
1188 'end' => isset($value['end']) ? $value['end'] : ''
1189 );
1190 $out = '<div ' . ($moreparam ? $moreparam : '') . '><div class="nowrap">';
1191 $out .= $form->selectDate($prefill['start'], $keyprefix.$key.$keysuffix.'_start', 0, 0, 1, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans("From"));
1192 $out .= '</div><div class="nowrap">';
1193 $out .= $form->selectDate($prefill['end'], $keyprefix.$key.$keysuffix.'_end', 0, 0, 1, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans("to"));
1194 $out .= '</div></div>';
1195 } else {
1196 // TODO Must also support $moreparam
1197 $out = $form->selectDate($value, $keyprefix.$key.$keysuffix, $showtime, $showtime, $required, '', 1, (($keyprefix != 'search_' && $keyprefix != 'search_options_') ? 1 : 0), 0, 1);
1198 }
1199 } elseif (in_array($type, array('datetime', 'datetimegmt'))) {
1200 $tmp = explode(',', $size);
1201 $newsize = $tmp[0];
1202 $showtime = 1;
1203
1204 // Do not show current date when field not required (see selectDate() method)
1205 if (!$required && $value == '') {
1206 $value = '-1';
1207 }
1208
1209 if ($mode == 1) {
1210 // search filter on a date extrafield shows two inputs to select a date range
1211 $prefill = array(
1212 'start' => isset($value['start']) ? $value['start'] : '',
1213 'end' => isset($value['end']) ? $value['end'] : ''
1214 );
1215 $out = '<div ' . ($moreparam ? $moreparam : '') . '><div class="nowrap">';
1216 $out .= $form->selectDate($prefill['start'], $keyprefix.$key.$keysuffix.'_start', 1, 1, 1, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans("From"), 'tzuserrel');
1217 $out .= '</div><div class="nowrap">';
1218 $out .= $form->selectDate($prefill['end'], $keyprefix.$key.$keysuffix.'_end', 1, 1, 1, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans("to"), 'tzuserrel');
1219 $out .= '</div></div>';
1220 } else {
1221 // TODO Must also support $moreparam
1222 $out = $form->selectDate($value, $keyprefix.$key.$keysuffix, $showtime, $showtime, $required, '', 1, (($keyprefix != 'search_' && $keyprefix != 'search_options_') ? 1 : 0), 0, 1, '', '', '', 1, '', '', 'tzuserrel');
1223 }
1224 } elseif (in_array($type, array('int', 'integer'))) {
1225 $tmp = explode(',', $size);
1226 $newsize = $tmp[0];
1227 $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 : '').'>';
1228 } elseif (preg_match('/varchar/', $type)) {
1229 $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 : '').'>';
1230 } elseif (in_array($type, array('mail', 'ip', 'phone', 'url'))) {
1231 $out = '<input type="text" class="flat '.$morecss.' maxwidthonsmartphone" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" value="'.dol_escape_htmltag($value).'" '.($moreparam ? $moreparam : '').'>';
1232 } elseif ($type == 'icon') {
1233 /* External lib inclusion are not allowed in backoffice. Also lib is included several time if there is several icon file.
1234 Some code must be added into main when MAIN_ADD_ICONPICKER_JS is set to add of lib in html header
1235 $out ='<link rel="stylesheet" href="'.dol_buildpath('/myfield/css/fontawesome-iconpicker.min.css', 1).'">';
1236 $out.='<script src="'.dol_buildpath('/myfield/js/fontawesome-iconpicker.min.js', 1).'"></script>';
1237 */
1238 $out .= '<input type="text" class="form-control icp icp-auto iconpicker-element iconpicker-input flat '.$morecss.' maxwidthonsmartphone"';
1239 $out .= ' name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" value="'.dol_escape_htmltag($value).'" '.($moreparam ? $moreparam : '').'>';
1240 if (getDolGlobalInt('MAIN_ADD_ICONPICKER_JS')) {
1241 $out .= '<script>';
1242 $options = "{ title: '<b>".$langs->trans("IconFieldSelector")."</b>', placement: 'right', showFooter: false, templates: {";
1243 $options .= "iconpicker: '<div class=\"iconpicker\"><div style=\"background-color:#EFEFEF;\" class=\"iconpicker-items\"></div></div>',";
1244 $options .= "iconpickerItem: '<a role=\"button\" href=\"#\" class=\"iconpicker-item\" style=\"background-color:#DDDDDD;\"><i></i></a>',";
1245 // $options.="buttons: '<button style=\"background-color:#FFFFFF;\" class=\"iconpicker-btn iconpicker-btn-cancel btn btn-default btn-sm\">".$langs->trans("Cancel")."</button>";
1246 // $options.="<button style=\"background-color:#FFFFFF;\" class=\"iconpicker-btn iconpicker-btn-accept btn btn-primary btn-sm\">".$langs->trans("Save")."</button>',";
1247 $options .= "footer: '<div class=\"popover-footer\" style=\"background-color:#EFEFEF;\"></div>',";
1248 $options .= "search: '<input type=\"search\" class\"form-control iconpicker-search\" placeholder=\"".$langs->trans("TypeToFilter")."\" />',";
1249 $options .= "popover: '<div class=\"iconpicker-popover popover\">";
1250 $options .= " <div class=\"arrow\" ></div>";
1251 $options .= " <div class=\"popover-title\" style=\"text-align:center;background-color:#EFEFEF;\"></div>";
1252 $options .= " <div class=\"popover-content \" ></div>";
1253 $options .= "</div>'}}";
1254 $out .= "$('#".$keyprefix.$key.$keysuffix."').iconpicker(".$options.");";
1255 $out .= '</script>';
1256 }
1257 } elseif ($type == 'text') {
1258 if (!preg_match('/search_/', $keyprefix)) { // If keyprefix is search_ or search_options_, we must just use a simple text field
1259 require_once DOL_DOCUMENT_ROOT.'/core/class/doleditor.class.php';
1260 $doleditor = new DolEditor($keyprefix.$key.$keysuffix, $value, '', 200, 'dolibarr_notes', 'In', false, false, false, ROWS_5, '90%');
1261 $out = (string) $doleditor->Create(1);
1262 } else {
1263 $out = '<input type="text" class="flat '.$morecss.' maxwidthonsmartphone" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" value="'.dol_escape_htmltag($value).'" '.($moreparam ? $moreparam : '').'>';
1264 }
1265 } elseif ($type == 'html') {
1266 if (!preg_match('/search_/', $keyprefix)) { // If keyprefix is search_ or search_options_, we must just use a simple text field
1267 require_once DOL_DOCUMENT_ROOT.'/core/class/doleditor.class.php';
1268 $doleditor = new DolEditor($keyprefix.$key.$keysuffix, $value, '', 200, 'dolibarr_notes', 'In', false, false, isModEnabled('fckeditor') && getDolGlobalInt('FCKEDITOR_ENABLE_SOCIETE'), ROWS_5, '90%');
1269 $out = (string) $doleditor->Create(1);
1270 } else {
1271 $out = '<input type="text" class="flat '.$morecss.' maxwidthonsmartphone" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" value="'.dol_escape_htmltag($value).'" '.($moreparam ? $moreparam : '').'>';
1272 }
1273 } elseif ($type == 'boolean') {
1274 if (empty($mode)) {
1275 $checked = '';
1276 if (!empty($value)) {
1277 $checked = ' checked value="1" ';
1278 } else {
1279 $checked = ' value="1" ';
1280 }
1281 $out = '<input type="checkbox" class="flat valignmiddle'.($morecss ? ' '.$morecss : '').' maxwidthonsmartphone" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" '.$checked.' '.($moreparam ? $moreparam : '').'>';
1282 } else {
1283 $out = $form->selectyesno($keyprefix.$key.$keysuffix, $value, 1, false, 1, 1, 'width75 yesno');
1284 }
1285 $out .= '<input type="hidden" name="'.$keyprefix.$key.$keysuffix.'_boolean" value="1">'; // A hidden field ending with "_boolean" that is always set to 1.
1286 } elseif ($type == 'price') {
1287 if (!empty($value)) { // $value in memory is a php numeric, we format it into user number format.
1288 $value = price($value);
1289 }
1290 $out = '<input type="text" class="flat '.$morecss.' maxwidthonsmartphone right" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" value="'.$value.'" '.($moreparam ? $moreparam : '').' placeholder="'.$langs->getCurrencySymbol($conf->currency).'">';
1291 } elseif ($type == 'pricecy') {
1292 $currency = $conf->currency;
1293 if (!empty($value)) {
1294 // $value in memory is a php string like '10.01:USD'
1295 $pricetmp = explode(':', $value);
1296 $currency = !empty($pricetmp[1]) ? $pricetmp[1] : $conf->currency;
1297 $value = price($pricetmp[0]);
1298 }
1299 $out = '<input type="text" class="flat '.$morecss.' maxwidthonsmartphone" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" value="'.$value.'" '.($moreparam ? $moreparam : '').'> ';
1300 $out .= $form->selectCurrency($currency, $keyprefix.$key.$keysuffix.'currency_id');
1301 } elseif ($type == 'duration') {
1302 $value = intval($value);
1303 $out = $form->select_duration($keyprefix . $key, $value, 0, 'text', 0, 1);
1304 } elseif ($type == 'double') {
1305 if (!empty($value)) { // $value in memory is a php numeric, we format it into user number format.
1306 $value = price($value);
1307 }
1308 $out = '<input type="text" class="flat '.$morecss.' maxwidthonsmartphone" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" value="'.$value.'" '.($moreparam ? $moreparam : '').'> ';
1309 } elseif ($type == 'select') {
1310 $out = '';
1311 if ($mode) {
1312 $options = array();
1313 foreach ($param['options'] as $okey => $val) {
1314 if ((string) $okey == '') {
1315 continue;
1316 }
1317
1318 $valarray = explode('|', $val);
1319 $val = $valarray[0];
1320
1321 if ($langfile && $val) {
1322 $options[$okey] = $langs->trans($val);
1323 } else {
1324 $options[$okey] = $val;
1325 }
1326 }
1327 $selected = array();
1328 if (!is_array($value)) {
1329 $selected = explode(',', $value);
1330 }
1331
1332 $out .= $form->multiselectarray($keyprefix.$key.$keysuffix, $options, $selected, 0, 0, $morecss, 0, 0, '', '', '', !empty($conf->use_javascript_ajax) && !getDolGlobalString('MAIN_EXTRAFIELDS_DISABLE_SELECT2'));
1333 } else {
1334 if (!empty($conf->use_javascript_ajax) && !getDolGlobalString('MAIN_EXTRAFIELDS_DISABLE_SELECT2')) {
1335 include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php';
1336 $out .= ajax_combobox($keyprefix.$key.$keysuffix, array(), 0);
1337 }
1338
1339 $out .= '<select class="flat '.$morecss.' maxwidthonsmartphone" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" '.($moreparam ? $moreparam : '').'>';
1340 $out .= '<option value="0">&nbsp;</option>';
1341 foreach ($param['options'] as $key2 => $val2) {
1342 if ((string) $key2 == '') {
1343 continue;
1344 }
1345 $valarray = explode('|', $val2);
1346 $val2 = $valarray[0];
1347 $parent = '';
1348 if (!empty($valarray[1])) {
1349 $parent = $valarray[1];
1350 }
1351 $out .= '<option value="'.$key2.'"';
1352 $out .= (((string) $value == (string) $key2) ? ' selected' : '');
1353 $out .= (!empty($parent) ? ' parent="'.$parent.'"' : '');
1354 $out .= '>';
1355 if ($langfile && $val2) {
1356 $out .= $langs->trans($val2);
1357 } else {
1358 $out .= $val2;
1359 }
1360 $out .= '</option>';
1361 }
1362 $out .= '</select>';
1363 }
1364 } elseif ($type == 'sellist') { // List of values selected from a table (1 choice)
1365 $out = '';
1366 if (!empty($conf->use_javascript_ajax) && !getDolGlobalString('MAIN_EXTRAFIELDS_DISABLE_SELECT2')) {
1367 include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php';
1368 $out .= ajax_combobox($keyprefix.$key.$keysuffix, array(), 0);
1369 }
1370
1371 $out .= '<select class="flat '.$morecss.' maxwidthonsmartphone" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" '.($moreparam ? $moreparam : '').'>';
1372 if (is_array($param['options'])) {
1373 $tmpparamoptions = array_keys($param['options']);
1374 $paramoptions = preg_split('/[\r\n]+/', $tmpparamoptions[0]);
1375
1376 $InfoFieldList = explode(":", $paramoptions[0], 5);
1377 // 0 : tableName
1378 // 1 : label field name
1379 // 2 : key fields name (if different of rowid)
1380 // optional parameters...
1381 // 3 : key field parent (for dependent lists). How this is used ?
1382 // 4 : where clause filter on column or table extrafield, syntax field='value' or extra.field=value. Or use USF on the second line.
1383 // 5 : string category type. This replace the filter.
1384 // 6 : ids categories list separated by comma for category root. This replace the filter.
1385 // 7 : sort field (not used here but used into format for commobject)
1386
1387 // If there is a filter, we extract it by taking all content inside parenthesis.
1388 if (! empty($InfoFieldList[4])) {
1389 $pos = 0; // $pos will be position of ending filter
1390 $parenthesisopen = 0;
1391 while (substr($InfoFieldList[4], $pos, 1) !== '' && ($parenthesisopen || $pos == 0 || substr($InfoFieldList[4], $pos, 1) != ':')) {
1392 if (substr($InfoFieldList[4], $pos, 1) == '(') {
1393 $parenthesisopen++;
1394 }
1395 if (substr($InfoFieldList[4], $pos, 1) == ')') {
1396 $parenthesisopen--;
1397 }
1398 $pos++;
1399 }
1400 $tmpbefore = substr($InfoFieldList[4], 0, $pos);
1401 $tmpafter = substr($InfoFieldList[4], $pos + 1);
1402 //var_dump($InfoFieldList[4].' -> '.$pos); var_dump($tmpafter);
1403 $InfoFieldList[4] = $tmpbefore;
1404 if ($tmpafter !== '') {
1405 $InfoFieldList = array_merge($InfoFieldList, explode(':', $tmpafter));
1406 }
1407
1408 // Fix better compatibility with some old extrafield syntax filter "(field=123)"
1409 $reg = array();
1410 if (preg_match('/^\‍(?([a-z0-9]+)([=<>]+)(\d+)\‍)?$/i', $InfoFieldList[4], $reg)) {
1411 $InfoFieldList[4] = '('.$reg[1].':'.$reg[2].':'.$reg[3].')';
1412 }
1413
1414 //var_dump($InfoFieldList);
1415 }
1416
1417 //$Usf = empty($paramoptions[1]) ? '' :$paramoptions[1];
1418
1419 $parentName = '';
1420 $parentField = '';
1421 $keyList = (empty($InfoFieldList[2]) ? 'rowid' : $InfoFieldList[2].' as rowid');
1422
1423 if (count($InfoFieldList) > 3 && !empty($InfoFieldList[3])) {
1424 list($parentName, $parentField) = explode('|', $InfoFieldList[3]);
1425 $keyList .= ', '.$parentField;
1426 }
1427 if (count($InfoFieldList) > 4 && !empty($InfoFieldList[4])) {
1428 if (strpos($InfoFieldList[4], 'extra.') !== false) {
1429 $keyList = 'main.'.$InfoFieldList[2].' as rowid';
1430 } else {
1431 $keyList = $InfoFieldList[2].' as rowid';
1432 }
1433 }
1434
1435 $filter_categorie = false;
1436 if (count($InfoFieldList) > 5) {
1437 if ($InfoFieldList[0] == 'categorie') {
1438 $filter_categorie = true;
1439 }
1440 }
1441
1442 if (!$filter_categorie) {
1443 $fields_label = explode('|', $InfoFieldList[1]);
1444 if (is_array($fields_label)) {
1445 $keyList .= ', ';
1446 $keyList .= implode(', ', $fields_label);
1447 }
1448
1449 $sqlwhere = '';
1450 $sql = "SELECT ".$keyList;
1451 $sql .= ' FROM '.$this->db->prefix().$InfoFieldList[0];
1452
1453 // Add filter from 4th field
1454 if (!empty($InfoFieldList[4])) {
1455 // can use current entity filter
1456 if (strpos($InfoFieldList[4], '$ENTITY$') !== false) {
1457 $InfoFieldList[4] = str_replace('$ENTITY$', (string) $conf->entity, $InfoFieldList[4]);
1458 }
1459 // can use SELECT request
1460 if (strpos($InfoFieldList[4], '$SEL$') !== false) {
1461 $InfoFieldList[4] = str_replace('$SEL$', 'SELECT', $InfoFieldList[4]);
1462 }
1463
1464 // current object id can be use into filter
1465 if (strpos($InfoFieldList[4], '$ID$') !== false && !empty($objectid)) {
1466 $InfoFieldList[4] = str_replace('$ID$', (string) $objectid, $InfoFieldList[4]);
1467 } else {
1468 $InfoFieldList[4] = str_replace('$ID$', '0', $InfoFieldList[4]);
1469 }
1470
1471 // We have to join on extrafield table
1472 $errstr = '';
1473 if (strpos($InfoFieldList[4], 'extra.') !== false) {
1474 $sql .= ' as main, '.$this->db->sanitize($this->db->prefix().$InfoFieldList[0]).'_extrafields as extra';
1475 $sqlwhere .= " WHERE extra.fk_object = main.".$this->db->sanitize($InfoFieldList[2]);
1476 $sqlwhere .= " AND " . forgeSQLFromUniversalSearchCriteria($InfoFieldList[4], $errstr, 1);
1477 } else {
1478 $sqlwhere .= " WHERE " . forgeSQLFromUniversalSearchCriteria($InfoFieldList[4], $errstr, 1);
1479 }
1480 } else {
1481 $sqlwhere .= ' WHERE 1=1';
1482 }
1483
1484 // Add Usf filter on second line
1485 /*
1486 if ($Usf) {
1487 $errorstr = '';
1488 $sqlusf .= forgeSQLFromUniversalSearchCriteria($Usf, $errorstr);
1489 if (!$errorstr) {
1490 $sqlwhere .= $sqlusf;
1491 } else {
1492 $sqlwhere .= " AND invalid_usf_filter_of_extrafield";
1493 }
1494 }
1495 */
1496
1497 // Some tables may have field, some other not. For the moment we disable it.
1498 if (in_array($InfoFieldList[0], array('tablewithentity'))) {
1499 $sqlwhere .= ' AND entity = '.((int) $conf->entity);
1500 }
1501 $sql .= $sqlwhere;
1502 //print $sql;
1503
1504 $sql .= $this->db->order(implode(',', $fields_label));
1505
1506 dol_syslog(get_class($this).'::showInputField type=sellist', LOG_DEBUG);
1507 $resql = $this->db->query($sql);
1508 if ($resql) {
1509 $out .= '<option value="0">&nbsp;</option>';
1510 $num = $this->db->num_rows($resql);
1511 $i = 0;
1512 while ($i < $num) {
1513 $labeltoshow = '';
1514 $obj = $this->db->fetch_object($resql);
1515
1516 // Several field into label (eq table:code|label:rowid)
1517 $notrans = false;
1518 $fields_label = explode('|', $InfoFieldList[1]);
1519 if (is_array($fields_label) && count($fields_label) > 1) {
1520 $notrans = true;
1521 foreach ($fields_label as $field_toshow) {
1522 $labeltoshow .= $obj->$field_toshow.' ';
1523 }
1524 } else {
1525 $labeltoshow = $obj->{$InfoFieldList[1]};
1526 }
1527
1528 if ($value == $obj->rowid) {
1529 if (!$notrans) {
1530 foreach ($fields_label as $field_toshow) {
1531 $translabel = $langs->trans($obj->$field_toshow);
1532 $labeltoshow = $translabel.' ';
1533 }
1534 }
1535 $out .= '<option value="'.$obj->rowid.'" selected>'.$labeltoshow.'</option>';
1536 } else {
1537 if (!$notrans) {
1538 $translabel = $langs->trans($obj->{$InfoFieldList[1]});
1539 $labeltoshow = $translabel;
1540 }
1541 if (empty($labeltoshow)) {
1542 $labeltoshow = '(not defined)';
1543 }
1544
1545 if (!empty($InfoFieldList[3]) && $parentField) {
1546 $parent = $parentName.':'.$obj->{$parentField};
1547 }
1548
1549 $out .= '<option value="'.$obj->rowid.'"';
1550 $out .= ($value == $obj->rowid ? ' selected' : '');
1551 $out .= (!empty($parent) ? ' parent="'.$parent.'"' : '');
1552 $out .= '>'.$labeltoshow.'</option>';
1553 }
1554
1555 $i++;
1556 }
1557 $this->db->free($resql);
1558 } else {
1559 print 'Error in request '.$sql.' '.$this->db->lasterror().'. Check setup of extra parameters.<br>';
1560 }
1561 } else {
1562 require_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php';
1563 $data = $form->select_all_categories(Categorie::$MAP_ID_TO_CODE[$InfoFieldList[5]], '', 'parent', 64, $InfoFieldList[6], 1, 1);
1564 $out .= '<option value="0">&nbsp;</option>';
1565 if (is_array($data)) {
1566 foreach ($data as $data_key => $data_value) {
1567 $out .= '<option value="'.$data_key.'"';
1568 $out .= ($value == $data_key ? ' selected' : '');
1569 $out .= '>'.$data_value.'</option>';
1570 }
1571 }
1572 }
1573 }
1574 $out .= '</select>';
1575 } elseif ($type == 'checkbox') {
1576 $value_arr = $value;
1577 if (!is_array($value)) {
1578 $value_arr = explode(',', $value);
1579 }
1580 $out = $form->multiselectarray($keyprefix.$key.$keysuffix, (empty($param['options']) ? null : $param['options']), $value_arr, 0, 0, '', 0, '100%');
1581 } elseif ($type == 'radio') {
1582 $out = '';
1583 foreach ($param['options'] as $keyopt => $val) {
1584 $out .= '<input class="flat '.$morecss.'" type="radio" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" '.($moreparam ? $moreparam : '');
1585 $out .= ' value="'.$keyopt.'"';
1586 $out .= ' id="'.$keyprefix.$key.$keysuffix.'_'.$keyopt.'"';
1587 $out .= ($value == $keyopt ? 'checked' : '');
1588 $out .= '/><label for="'.$keyprefix.$key.$keysuffix.'_'.$keyopt.'">'.$langs->trans($val).'</label><br>';
1589 }
1590 } elseif ($type == 'chkbxlst') { // List of values selected from a table (n choices)
1591 if (is_array($value)) {
1592 $value_arr = $value;
1593 } else {
1594 $value_arr = explode(',', $value);
1595 }
1596
1597 if (is_array($param['options'])) {
1598 $tmpparamoptions = array_keys($param['options']);
1599 $paramoptions = preg_split('/[\r\n]+/', $tmpparamoptions[0]);
1600
1601 $InfoFieldList = explode(":", $paramoptions[0], 5);
1602 // 0 : tableName
1603 // 1 : label field name
1604 // 2 : key fields name (if different of rowid)
1605 // optional parameters...
1606 // 3 : key field parent (for dependent lists). How this is used ?
1607 // 4 : where clause filter on column or table extrafield, syntax field='value' or extra.field=value. Or use USF on the second line.
1608 // 5 : string category type. This replace the filter.
1609 // 6 : ids categories list separated by comma for category root. This replace the filter.
1610 // 7 : sort field (not used here but used into format for commobject)
1611
1612 // If there is a filter, we extract it by taking all content inside parenthesis.
1613 if (! empty($InfoFieldList[4])) {
1614 $pos = 0;
1615 $parenthesisopen = 0;
1616 while (substr($InfoFieldList[4], $pos, 1) !== '' && ($parenthesisopen || $pos == 0 || substr($InfoFieldList[4], $pos, 1) != ':')) {
1617 if (substr($InfoFieldList[4], $pos, 1) == '(') {
1618 $parenthesisopen++;
1619 }
1620 if (substr($InfoFieldList[4], $pos, 1) == ')') {
1621 $parenthesisopen--;
1622 }
1623 $pos++;
1624 }
1625 $tmpbefore = substr($InfoFieldList[4], 0, $pos);
1626 $tmpafter = substr($InfoFieldList[4], $pos + 1);
1627 //var_dump($InfoFieldList[4].' -> '.$pos); var_dump($tmpafter);
1628 $InfoFieldList[4] = $tmpbefore;
1629 if ($tmpafter !== '') {
1630 $InfoFieldList = array_merge($InfoFieldList, explode(':', $tmpafter));
1631 }
1632
1633 // Fix better compatibility with some old extrafield syntax filter "(field=123)"
1634 $reg = array();
1635 if (preg_match('/^\‍(?([a-z0-9]+)([=<>]+)(\d+)\‍)?$/i', $InfoFieldList[4], $reg)) {
1636 $InfoFieldList[4] = '('.$reg[1].':'.$reg[2].':'.$reg[3].')';
1637 }
1638
1639 //var_dump($InfoFieldList);
1640 }
1641
1642 //$Usf = empty($paramoptions[1]) ? '' :$paramoptions[1];
1643
1644 $parentName = '';
1645 $parentField = '';
1646 $keyList = (empty($InfoFieldList[2]) ? 'rowid' : $InfoFieldList[2].' as rowid');
1647
1648 if (count($InfoFieldList) > 3 && !empty($InfoFieldList[3])) {
1649 list($parentName, $parentField) = explode('|', $InfoFieldList[3]);
1650 $keyList .= ', '.$parentField;
1651 }
1652 if (count($InfoFieldList) > 4 && !empty($InfoFieldList[4])) {
1653 if (strpos($InfoFieldList[4], 'extra.') !== false) {
1654 $keyList = 'main.'.$InfoFieldList[2].' as rowid';
1655 } else {
1656 $keyList = $InfoFieldList[2].' as rowid';
1657 }
1658 }
1659
1660 $filter_categorie = false;
1661 if (count($InfoFieldList) > 5) {
1662 if ($InfoFieldList[0] == 'categorie') {
1663 $filter_categorie = true;
1664 }
1665 }
1666
1667 if (!$filter_categorie) {
1668 $fields_label = explode('|', $InfoFieldList[1]);
1669 if (is_array($fields_label)) {
1670 $keyList .= ', ';
1671 $keyList .= implode(', ', $fields_label);
1672 }
1673
1674 $sqlwhere = '';
1675 $sql = "SELECT ".$keyList;
1676 $sql .= ' FROM '.$this->db->prefix().$InfoFieldList[0];
1677
1678 // Add filter from 4th field
1679 if (!empty($InfoFieldList[4])) {
1680 // can use current entity filter
1681 if (strpos($InfoFieldList[4], '$ENTITY$') !== false) {
1682 $InfoFieldList[4] = str_replace('$ENTITY$', (string) $conf->entity, $InfoFieldList[4]);
1683 }
1684 // can use SELECT request
1685 if (strpos($InfoFieldList[4], '$SEL$') !== false) {
1686 $InfoFieldList[4] = str_replace('$SEL$', 'SELECT', $InfoFieldList[4]);
1687 }
1688
1689 // current object id can be use into filter
1690 if (strpos($InfoFieldList[4], '$ID$') !== false && !empty($objectid)) {
1691 $InfoFieldList[4] = str_replace('$ID$', (string) $objectid, $InfoFieldList[4]);
1692 } elseif (preg_match("#^.*list.php$#", $_SERVER["PHP_SELF"])) {
1693 // Pattern for word=$ID$
1694 $word = '\b[a-zA-Z0-9-\.-_]+\b=\$ID\$';
1695
1696 // Removing spaces around =, ( and )
1697 $InfoFieldList[4] = preg_replace('# *(=|\‍(|\‍)) *#', '$1', $InfoFieldList[4]);
1698
1699 $nbPreg = 1;
1700 // While we have parenthesis
1701 while ($nbPreg != 0) {
1702 // Initialise counters
1703 $nbPregRepl = $nbPregSel = 0;
1704 // Remove all parenthesis not preceded with '=' sign
1705 $InfoFieldList[4] = preg_replace('#([^=])(\‍([^)^(]*('.$word.')[^)^(]*\‍))#', '$1 $3 ', $InfoFieldList[4], -1, $nbPregRepl);
1706 // Remove all escape characters around '=' and parenthesis
1707 $InfoFieldList[4] = preg_replace('# *(=|\‍(|\‍)) *#', '$1', $InfoFieldList[4]);
1708 // Remove all parentheses preceded with '='
1709 $InfoFieldList[4] = preg_replace('#\b[a-zA-Z0-9-\.-_]+\b=\‍([^)^(]*('.$word.')[^)^(]*\‍)#', '$1 ', $InfoFieldList[4], -1, $nbPregSel);
1710 // On retire les escapes autour des = et parenthèses
1711 $InfoFieldList[4] = preg_replace('# *(=|\‍(|\‍)) *#', '$1', $InfoFieldList[4]);
1712
1713 // UPdate the totals counter for the loop
1714 $nbPreg = $nbPregRepl + $nbPregSel;
1715 }
1716
1717 // In case there is AND ou OR, before or after
1718 $matchCondition = array();
1719 preg_match('#(AND|OR|) *('.$word.') *(AND|OR|)#', $InfoFieldList[4], $matchCondition);
1720 while (!empty($matchCondition[0])) {
1721 // If the two sides differ but are not empty
1722 if (!empty($matchCondition[1]) && !empty($matchCondition[3]) && $matchCondition[1] != $matchCondition[3]) {
1723 // Nobody sain would do that without parentheses
1724 $InfoFieldList[4] = str_replace('$ID$', '0', $InfoFieldList[4]);
1725 } else {
1726 if (!empty($matchCondition[1])) {
1727 $boolCond = (($matchCondition[1] == "AND") ? ' AND TRUE ' : ' OR FALSE ');
1728 $InfoFieldList[4] = str_replace($matchCondition[0], $boolCond.$matchCondition[3], $InfoFieldList[4]);
1729 } elseif (!empty($matchCondition[3])) {
1730 $boolCond = (($matchCondition[3] == "AND") ? ' TRUE AND ' : ' FALSE OR');
1731 $InfoFieldList[4] = str_replace($matchCondition[0], $boolCond, $InfoFieldList[4]);
1732 } else {
1733 $InfoFieldList[4] = " TRUE ";
1734 }
1735 }
1736
1737 // In case there is AND ou OR, before or after
1738 preg_match('#(AND|OR|) *('.$word.') *(AND|OR|)#', $InfoFieldList[4], $matchCondition);
1739 }
1740 } else {
1741 $InfoFieldList[4] = str_replace('$ID$', '0', $InfoFieldList[4]);
1742 }
1743
1744 // We have to join on extrafield table
1745 $errstr = '';
1746 if (strpos($InfoFieldList[4], 'extra.') !== false) {
1747 $sql .= ' as main, '.$this->db->sanitize($this->db->prefix().$InfoFieldList[0]).'_extrafields as extra';
1748 $sqlwhere .= " WHERE extra.fk_object = main.".$this->db->sanitize($InfoFieldList[2]);
1749 $sqlwhere .= " AND " . forgeSQLFromUniversalSearchCriteria($InfoFieldList[4], $errstr, 1);
1750 } else {
1751 $sqlwhere .= " WHERE " . forgeSQLFromUniversalSearchCriteria($InfoFieldList[4], $errstr, 1);
1752 }
1753 } else {
1754 $sqlwhere .= ' WHERE 1=1';
1755 }
1756
1757 // Add Usf filter on second line
1758 /*
1759 if ($Usf) {
1760 $errorstr = '';
1761 $sqlusf .= forgeSQLFromUniversalSearchCriteria($Usf, $errorstr);
1762 if (!$errorstr) {
1763 $sqlwhere .= $sqlusf;
1764 } else {
1765 $sqlwhere .= " AND invalid_usf_filter_of_extrafield";
1766 }
1767 }
1768 */
1769
1770 // Some tables may have field, some other not. For the moment we disable it.
1771 if (in_array($InfoFieldList[0], array('tablewithentity'))) {
1772 $sqlwhere .= " AND entity = ".((int) $conf->entity);
1773 }
1774 // $sql.=preg_replace('/^ AND /','',$sqlwhere);
1775 // print $sql;
1776
1777 $sql .= $sqlwhere;
1778 $sql .= ' ORDER BY '.implode(', ', $fields_label);
1779
1780 dol_syslog(get_class($this).'::showInputField type=chkbxlst', LOG_DEBUG);
1781 $resql = $this->db->query($sql);
1782 if ($resql) {
1783 $num = $this->db->num_rows($resql);
1784 $i = 0;
1785
1786 $data = array();
1787
1788 while ($i < $num) {
1789 $labeltoshow = '';
1790 $obj = $this->db->fetch_object($resql);
1791
1792 $notrans = false;
1793 // Several field into label (eq table:code|label:rowid)
1794 $fields_label = explode('|', $InfoFieldList[1]);
1795 if (is_array($fields_label)) {
1796 $notrans = true;
1797 foreach ($fields_label as $field_toshow) {
1798 $labeltoshow .= $obj->$field_toshow.' ';
1799 }
1800 } else {
1801 $labeltoshow = $obj->{$InfoFieldList[1]};
1802 }
1803 $labeltoshow = dol_trunc($labeltoshow, 45);
1804
1805 if (is_array($value_arr) && in_array($obj->rowid, $value_arr)) {
1806 $labeltoshow = '';
1807 foreach ($fields_label as $field_toshow) {
1808 $translabel = $langs->trans($obj->$field_toshow);
1809 if ($translabel != $obj->$field_toshow) {
1810 $labeltoshow .= ' '.dol_trunc($translabel, 18).' ';
1811 } else {
1812 $labeltoshow .= ' '.dol_trunc($obj->$field_toshow, 18).' ';
1813 }
1814 }
1815 $data[$obj->rowid] = $labeltoshow;
1816 } else {
1817 if (!$notrans) {
1818 $translabel = $langs->trans($obj->{$InfoFieldList[1]});
1819 if ($translabel != $obj->{$InfoFieldList[1]}) {
1820 $labeltoshow = dol_trunc($translabel, 18);
1821 } else {
1822 $labeltoshow = dol_trunc($obj->{$InfoFieldList[1]}, 18);
1823 }
1824 }
1825 if (empty($labeltoshow)) {
1826 $labeltoshow = '(not defined)';
1827 }
1828
1829 if (is_array($value_arr) && in_array($obj->rowid, $value_arr)) {
1830 $data[$obj->rowid] = $labeltoshow;
1831 }
1832
1833 if (!empty($InfoFieldList[3]) && $parentField) {
1834 $parent = $parentName.':'.$obj->{$parentField};
1835 }
1836
1837 $data[$obj->rowid] = $labeltoshow;
1838 }
1839
1840 $i++;
1841 }
1842 $this->db->free($resql);
1843
1844 $out = $form->multiselectarray($keyprefix.$key.$keysuffix, $data, $value_arr, 0, 0, '', 0, '100%');
1845 } else {
1846 print 'Error in request '.$sql.' '.$this->db->lasterror().'. Check setup of extra parameters.<br>';
1847 }
1848 } else {
1849 require_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php';
1850 $data = $form->select_all_categories(Categorie::$MAP_ID_TO_CODE[$InfoFieldList[5]], '', 'parent', 64, $InfoFieldList[6], 1, 1);
1851 $out = $form->multiselectarray($keyprefix.$key.$keysuffix, $data, $value_arr, 0, 0, '', 0, '100%');
1852 }
1853 }
1854 } elseif ($type == 'link') {
1855 $param_list = array_keys($param['options']); // $param_list[0] = 'ObjectName:classPath' but can also be 'ObjectName:classPath:1:(status:=:1)'
1856 /* Removed.
1857 The selectForForms is called with parameter $objectfield defined, so the app can retrieve the filter inside the ajax component instead of being provided as parameters. The
1858 filter was used to pass SQL requests leading to serious SQL injection problem. This should not be possible. Also the call of the ajax was broken by some WAF.
1859 if (strpos($param_list[0], '$ID$') !== false && !empty($objectid)) {
1860 $param_list[0] = str_replace('$ID$', $objectid, $param_list[0]);
1861 }*/
1862 $showempty = (($required && $default != '') ? 0 : 1);
1863
1864 $tmparray = explode(':', $param_list[0]);
1865
1866 $element = $extrafieldsobjectkey; // $extrafieldsobjectkey comes from $object->table_element but we need $object->element
1867 if ($element == 'socpeople') {
1868 $element = 'contact';
1869 } elseif ($element == 'projet') {
1870 $element = 'project';
1871 }
1872
1873 //$objectdesc = $param_list[0]; // Example: 'ObjectName:classPath:1:(status:=:1)' Replaced by next line: this was propagated also a filter by ajax call that was blocked by some WAF
1874 $objectdesc = $tmparray[0]; // Example: 'ObjectName:classPath' To not propagate any filter (selectForForms do ajax call and propagating SQL filter is blocked by some WAF). Also we should use the one into the definition in the ->fields of $elem if found.
1875 $objectfield = $element.':options_'.$key; // Example: 'actioncomm:options_fff' To be used in priority to know object linked with all its definition (including filters)
1876
1877 $out = $form->selectForForms($objectdesc, $keyprefix.$key.$keysuffix, $value, $showempty, '', '', $morecss, '', 0, 0, '', $objectfield);
1878 } elseif (in_array($type, ['point', 'multipts', 'linestrg', 'polygon'])) {
1879 require_once DOL_DOCUMENT_ROOT.'/core/class/dolgeophp.class.php';
1880 $dolgeophp = new DolGeoPHP($this->db);
1881 $geojson = '{}';
1882 $centroidjson = getDolGlobalString('MAIN_INFO_SOCIETE_GEO_COORDINATES', '{}');
1883 if (!empty($value)) {
1884 $tmparray = $dolgeophp->parseGeoString($value);
1885 $geojson = $tmparray['geojson'];
1886 $centroidjson = $tmparray['centroidjson'];
1887 }
1888 if (!preg_match('/search_/', $keyprefix)) {
1889 require_once DOL_DOCUMENT_ROOT.'/core/class/geomapeditor.class.php';
1890 $geomapeditor = new GeoMapEditor();
1891 $out .= $geomapeditor->getHtml($keyprefix.$key.$keysuffix, $geojson, $centroidjson, $type);
1892 } else {
1893 // If keyprefix is search_ or search_options_, we must just use a simple text field
1894 $out = '';
1895 }
1896 } elseif ($type == 'password') {
1897 // If prefix is 'search_', field is used as a filter, we use a common text field.
1898 $out = '<input style="display:none" type="text" name="fakeusernameremembered">'; // Hidden field to reduce impact of evil Google Chrome autopopulate bug.
1899 $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 : '').'>';
1900 } elseif ($type == 'stars') {
1901 $out = '<input type="hidden" class="flat '.$morecss.'" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" value="'.dol_escape_htmltag($value).'"'.($moreparam ? $moreparam : '').'>';
1902 $out .= '<div class="star-selection" id="'.$keyprefix.$key.$keysuffix.'_selection">';
1903 $i = 1;
1904 while ($i <= $size) {
1905 $out .= '<span class="star" data-value="'.$i.'">'.img_picto('', 'fontawesome_star_fas').'</span>';
1906 $i++;
1907 }
1908 $out .= '</div>';
1909 $out .= '<script>
1910 jQuery(function($) {
1911 let container = $("#'.$keyprefix.$key.$keysuffix.'_selection");
1912 let selectedStars = parseInt($("#'.$keyprefix.$key.$keysuffix.'").val()) || 0;
1913 container.find(".star").each(function() {
1914 $(this).toggleClass("active", $(this).data("value") <= selectedStars);
1915 });
1916 container.find(".star").on("mouseover", function() {
1917 let selectedStar = $(this).data("value");
1918 container.find(".star").each(function() {
1919 $(this).toggleClass("active", $(this).data("value") <= selectedStar);
1920 });
1921 });
1922 container.on("mouseout", function() {
1923 container.find(".star").each(function() {
1924 $(this).toggleClass("active", $(this).data("value") <= selectedStars);
1925 });
1926 });
1927 container.find(".star").off("click").on("click", function() {
1928 selectedStars = $(this).data("value");
1929 if (selectedStars === 1 && $("#'.$keyprefix.$key.$keysuffix.'").val() == 1) {
1930 selectedStars = 0;
1931 }
1932 $("#'.$keyprefix.$key.$keysuffix.'").val(selectedStars);
1933 container.find(".star").each(function() {
1934 $(this).toggleClass("active", $(this).data("value") <= selectedStars);
1935 });
1936 });
1937 });
1938 </script>';
1939 }
1940 if (!empty($hidden)) {
1941 $out = '<input type="hidden" value="'.$value.'" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'"/>';
1942 }
1943
1944 // If alwayseditable is false, and object is not in draft, then showOutputField
1945 // @phan-suppress-next-line PhanUndeclaredConstantOfClass
1946 if ($alwayseditable == 0 && is_object($object) && isset($object->status) && defined(get_class($object)."::STATUS_DRAFT") && $object->status != $object::STATUS_DRAFT) {
1947 $out = $this->showOutputField($key, $value, $moreparam, $extrafieldsobjectkey, null, $object);
1948 }
1949 /* Add comments
1950 if ($type == 'date') $out.=' (YYYY-MM-DD)';
1951 elseif ($type == 'datetime') $out.=' (YYYY-MM-DD HH:MM:SS)';
1952 */
1953 /*if (!empty($help) && $keyprefix != 'search_options_') {
1954 $out .= $form->textwithpicto('', $help, 1, 'help', '', 0, 3);
1955 }*/
1956 return $out;
1957 }
1958
1959
1971 public function showOutputField($key, $value, $moreparam = '', $extrafieldsobjectkey = '', $outputlangs = null, $object = null)
1972 {
1973 global $conf, $langs;
1974
1975 if (is_null($outputlangs) || !is_object($outputlangs)) {
1976 $outputlangs = $langs;
1977 }
1978
1979 if (empty($extrafieldsobjectkey)) {
1980 dol_syslog(get_class($this).'::showOutputField extrafieldsobjectkey required', LOG_ERR);
1981 return 'BadValueForParamExtraFieldsObjectKey';
1982 }
1983
1984 $label = $this->attributes[$extrafieldsobjectkey]['label'][$key];
1985 $type = $this->attributes[$extrafieldsobjectkey]['type'][$key];
1986 $size = $this->attributes[$extrafieldsobjectkey]['size'][$key]; // Can be '255', '24,8'...
1987 $default = $this->attributes[$extrafieldsobjectkey]['default'][$key];
1988 $computed = $this->attributes[$extrafieldsobjectkey]['computed'][$key];
1989 $unique = $this->attributes[$extrafieldsobjectkey]['unique'][$key];
1990 $required = $this->attributes[$extrafieldsobjectkey]['required'][$key];
1991 $param = $this->attributes[$extrafieldsobjectkey]['param'][$key];
1992 $perms = (int) dol_eval($this->attributes[$extrafieldsobjectkey]['perms'][$key], 1, 1, '2');
1993 $langfile = $this->attributes[$extrafieldsobjectkey]['langfile'][$key];
1994 $list = (string) dol_eval($this->attributes[$extrafieldsobjectkey]['list'][$key], 1, 1, '2');
1995 $help = $this->attributes[$extrafieldsobjectkey]['help'][$key];
1996 $cssview = $this->attributes[$extrafieldsobjectkey]['cssview'][$key];
1997 $alwayseditable = $this->attributes[$extrafieldsobjectkey]['alwayseditable'][$key];
1998
1999 // If alwayseditable is false, and object is not in draft, then we show value instead of input field
2000 $showValueInsteadOfInputField = 0; // Variable used to disable update of fields via ajax
2001 // @phan-suppress-next-line PhanUndeclaredConstantOfClass
2002 if ($alwayseditable == 0 && is_object($object) && isset($object->status) && defined(get_class($object)."::STATUS_DRAFT") && $object->status != $object::STATUS_DRAFT) {
2003 $showValueInsteadOfInputField = 1;
2004 }
2005
2006 $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)
2007
2008 if ($hidden) {
2009 return ''; // This is a protection. If field is hidden, we should just not call this method.
2010 }
2011
2012 //if ($computed) $value = // $value is already calculated into $value before calling this method
2013
2014 $showsize = 0;
2015 if ($type == 'date') {
2016 $showsize = 10;
2017 if ($value !== '') {
2018 $value = dol_print_date($value, 'day'); // For date without hour, date is always GMT for storage and output
2019 }
2020 } elseif ($type == 'datetime') {
2021 $showsize = 19;
2022 if ($value !== '') {
2023 $value = dol_print_date($value, 'dayhour', 'tzuserrel');
2024 }
2025 } elseif ($type == 'duration') {
2026 $showsize = 10;
2027 if ($value !== '') {
2028 $value = intval($value);
2029 $value = convertSecondToTime($value);
2030 }
2031 } elseif ($type == 'datetimegmt') {
2032 $showsize = 19;
2033 if ($value !== '') {
2034 $value = dol_print_date($value, 'dayhour', 'gmt');
2035 }
2036 } elseif ($type == 'int') {
2037 $showsize = 10;
2038 } elseif ($type == 'double') {
2039 if (!empty($value)) {
2040 //$value=price($value);
2041 $sizeparts = explode(",", $size);
2042 $number_decimals = array_key_exists(1, $sizeparts) ? $sizeparts[1] : 0;
2043 $value = price($value, 0, $outputlangs, 0, 0, $number_decimals, '');
2044 }
2045 } elseif ($type == 'boolean') {
2046 $checked = '';
2047 if (!empty($value)) {
2048 $checked = ' checked ';
2049 }
2050 if (getDolGlobalInt('MAIN_OPTIMIZEFORTEXTBROWSER') < 2) {
2051 $value = '<input type="checkbox" '.$checked.' '.($moreparam ? $moreparam : '').' readonly disabled>';
2052 } else {
2053 $value = yn($value ? 1 : 0);
2054 }
2055 } elseif ($type == 'mail') {
2056 $value = dol_print_email($value, 0, 0, 0, 64, 1, 1);
2057 } elseif ($type == 'ip') {
2058 $value = dol_print_ip($value, 0);
2059 } elseif ($type == 'icon') {
2060 $value = '<span class="'.$value.'"></span>';
2061 } elseif ($type == 'url') {
2062 $value = dol_print_url($value, '_blank', 32, 1);
2063 } elseif ($type == 'phone') {
2064 $value = dol_print_phone($value, '', 0, 0, '', '&nbsp;', 'phone');
2065 } elseif ($type == 'price') {
2066 //$value = price($value, 0, $langs, 0, 0, -1, $conf->currency);
2067 if ($value || $value == '0') {
2068 $value = price($value, 0, $outputlangs, 0, $conf->global->MAIN_MAX_DECIMALS_TOT, -1).' '.$outputlangs->getCurrencySymbol($conf->currency);
2069 }
2070 } elseif ($type == 'pricecy') {
2071 $currency = $conf->currency;
2072 if (!empty($value)) {
2073 // $value in memory is a php string like '0.01:EUR'
2074 $pricetmp = explode(':', $value);
2075 $currency = !empty($pricetmp[1]) ? $pricetmp[1] : $conf->currency;
2076 $value = $pricetmp[0];
2077 }
2078 if ($value || $value == '0') {
2079 $value = price($value, 0, $outputlangs, 0, $conf->global->MAIN_MAX_DECIMALS_TOT, -1, $currency);
2080 }
2081 } elseif ($type == 'select') {
2082 $valstr = (!empty($param['options'][$value]) ? $param['options'][$value] : '');
2083 if (($pos = strpos($valstr, "|")) !== false) {
2084 $valstr = substr($valstr, 0, $pos);
2085 }
2086 if ($langfile && $valstr) {
2087 $value = $outputlangs->trans($valstr);
2088 } else {
2089 $value = $valstr;
2090 }
2091 } elseif ($type == 'sellist') {
2092 $param_list = array_keys($param['options']);
2093 $InfoFieldList = explode(":", $param_list[0]);
2094
2095 $selectkey = "rowid";
2096 $keyList = 'rowid';
2097
2098 if (count($InfoFieldList) >= 3) {
2099 $selectkey = $InfoFieldList[2];
2100 $keyList = $InfoFieldList[2].' as rowid';
2101 }
2102
2103 $fields_label = explode('|', $InfoFieldList[1]);
2104 if (is_array($fields_label)) {
2105 $keyList .= ', ';
2106 $keyList .= implode(', ', $fields_label);
2107 }
2108
2109 $filter_categorie = false;
2110 if (count($InfoFieldList) > 5) {
2111 if ($InfoFieldList[0] == 'categorie') {
2112 $filter_categorie = true;
2113 }
2114 }
2115
2116 $sql = "SELECT ".$keyList;
2117 $sql .= ' FROM '.$this->db->prefix().$InfoFieldList[0];
2118 if (!empty($InfoFieldList[4]) && strpos($InfoFieldList[4], 'extra.') !== false) {
2119 $sql .= ' as main';
2120 }
2121 if ($selectkey == 'rowid' && empty($value)) {
2122 $sql .= " WHERE ".$selectkey." = 0";
2123 } elseif ($selectkey == 'rowid') {
2124 $sql .= " WHERE ".$selectkey." = ".((int) $value);
2125 } else {
2126 $sql .= " WHERE ".$selectkey." = '".$this->db->escape($value)."'";
2127 }
2128
2129 //$sql.= ' AND entity = '.$conf->entity;
2130
2131 dol_syslog(get_class($this).':showOutputField:$type=sellist', LOG_DEBUG);
2132 $resql = $this->db->query($sql);
2133 if ($resql) {
2134 if (!$filter_categorie) {
2135 $value = ''; // value was used, so now we reset it to use it to build final output
2136
2137 $obj = $this->db->fetch_object($resql);
2138
2139 // Several field into label (eq table:code|label:rowid)
2140 $fields_label = explode('|', $InfoFieldList[1]);
2141
2142 if (is_array($fields_label) && count($fields_label) > 1) {
2143 foreach ($fields_label as $field_toshow) {
2144 $translabel = '';
2145 if (!empty($obj->$field_toshow)) {
2146 $translabel = $outputlangs->trans($obj->$field_toshow);
2147
2148 if ($translabel != $obj->$field_toshow) {
2149 $value .= dol_trunc($translabel, 24) . ' ';
2150 } else {
2151 $value .= $obj->$field_toshow . ' ';
2152 }
2153 }
2154 }
2155 } else {
2156 $translabel = '';
2157 $tmppropname = $InfoFieldList[1];
2158 //$obj->$tmppropname = '';
2159 if (!empty(isset($obj->$tmppropname) ? $obj->$tmppropname : '')) {
2160 $translabel = $outputlangs->trans($obj->$tmppropname);
2161 }
2162 if ($translabel != (isset($obj->$tmppropname) ? $obj->$tmppropname : '')) {
2163 $value = dol_trunc($translabel, 18);
2164 } else {
2165 $value = isset($obj->$tmppropname) ? $obj->$tmppropname : '';
2166 }
2167 }
2168 } else {
2169 $toprint = array();
2170 $obj = $this->db->fetch_object($resql);
2171 if ($obj->rowid) {
2172 require_once DOL_DOCUMENT_ROOT . '/categories/class/categorie.class.php';
2173 $c = new Categorie($this->db);
2174 $result = $c->fetch($obj->rowid);
2175 if ($result > 0) {
2176 $ways = $c->print_all_ways(); // $ways[0] = "ccc2 >> ccc2a >> ccc2a1" with html formatted text
2177 foreach ($ways as $way) {
2178 $toprint[] = '<li class="select2-search-choice-dolibarr noborderoncategories"' . ($c->color ? ' style="background: #' . $c->color . ';"' : ' style="background: #bbb"') . '>' . img_object('', 'category') . ' ' . $way . '</li>';
2179 }
2180 }
2181 }
2182 $value = '<div class="select2-container-multi-dolibarr" style="width: 90%;"><ul class="select2-choices-dolibarr">'.implode(' ', $toprint).'</ul></div>';
2183 }
2184 } else {
2185 dol_syslog(get_class($this).'::showOutputField error '.$this->db->lasterror(), LOG_WARNING);
2186 }
2187 } elseif ($type == 'radio') {
2188 if (!isset($param['options'][$value])) {
2189 $outputlangs->load('errors');
2190 $value = $outputlangs->trans('ErrorNoValueForRadioType');
2191 } else {
2192 $value = $outputlangs->trans($param['options'][$value]);
2193 }
2194 } elseif ($type == 'checkbox') {
2195 $value_arr = explode(',', $value);
2196 $value = '';
2197 $toprint = array();
2198 if (is_array($value_arr)) {
2199 foreach ($value_arr as $keyval => $valueval) {
2200 if (!empty($valueval)) {
2201 $toprint[] = '<li class="select2-search-choice-dolibarr noborderoncategories" style="background: #bbb">'.$param['options'][$valueval].'</li>';
2202 }
2203 }
2204 }
2205 $value = '<div class="select2-container-multi-dolibarr" style="width: 90%;"><ul class="select2-choices-dolibarr">'.implode(' ', $toprint).'</ul></div>';
2206 } elseif ($type == 'chkbxlst') {
2207 $value_arr = explode(',', $value);
2208
2209 $param_list = array_keys($param['options']);
2210 $InfoFieldList = explode(":", $param_list[0]);
2211
2212 $selectkey = "rowid";
2213 $keyList = 'rowid';
2214
2215 if (count($InfoFieldList) >= 3) {
2216 $selectkey = $InfoFieldList[2];
2217 $keyList = $InfoFieldList[2].' as rowid';
2218 }
2219
2220 $fields_label = explode('|', $InfoFieldList[1]);
2221 if (is_array($fields_label)) {
2222 $keyList .= ', ';
2223 $keyList .= implode(', ', $fields_label);
2224 }
2225
2226 $filter_categorie = false;
2227 if (count($InfoFieldList) > 5) {
2228 if ($InfoFieldList[0] == 'categorie') {
2229 $filter_categorie = true;
2230 }
2231 }
2232
2233 $sql = "SELECT ".$keyList;
2234 $sql .= " FROM ".$this->db->prefix().$InfoFieldList[0];
2235 if (strpos($InfoFieldList[4], 'extra.') !== false) {
2236 $sql .= ' as main';
2237 }
2238 // $sql.= " WHERE ".$selectkey."='".$this->db->escape($value)."'";
2239 // $sql.= ' AND entity = '.$conf->entity;
2240
2241 dol_syslog(get_class($this).':showOutputField:$type=chkbxlst', LOG_DEBUG);
2242 $resql = $this->db->query($sql);
2243 if ($resql) {
2244 if (!$filter_categorie) {
2245 $value = ''; // value was used, so now we reset it to use it to build final output
2246 $toprint = array();
2247 while ($obj = $this->db->fetch_object($resql)) {
2248 // Several field into label (eq table:code|label:rowid)
2249 $fields_label = explode('|', $InfoFieldList[1]);
2250 if (is_array($value_arr) && in_array($obj->rowid, $value_arr)) {
2251 if (is_array($fields_label) && count($fields_label) > 1) {
2252 $label = '<li class="select2-search-choice-dolibarr noborderoncategories" style="background: #bbb">';
2253 foreach ($fields_label as $field_toshow) {
2254 $translabel = '';
2255 if (!empty($obj->$field_toshow)) {
2256 $translabel = $outputlangs->trans($obj->$field_toshow);
2257 }
2258 if ($translabel != $field_toshow) {
2259 $label .= ' '.dol_trunc($translabel, 18);
2260 } else {
2261 $label .= ' '.$obj->$field_toshow;
2262 }
2263 }
2264 $label .= '</li>';
2265 $toprint[] = $label;
2266 } else {
2267 $translabel = '';
2268 if (!empty($obj->{$InfoFieldList[1]})) {
2269 $translabel = $outputlangs->trans($obj->{$InfoFieldList[1]});
2270 }
2271 if ($translabel != $obj->{$InfoFieldList[1]}) {
2272 $toprint[] = '<li class="select2-search-choice-dolibarr noborderoncategories" style="background: #bbb">'.dol_trunc($translabel, 18).'</li>';
2273 } else {
2274 $toprint[] = '<li class="select2-search-choice-dolibarr noborderoncategories" style="background: #bbb">'.$obj->{$InfoFieldList[1]}.'</li>';
2275 }
2276 }
2277 }
2278 }
2279 } else {
2280 require_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php';
2281
2282 $toprint = array();
2283 while ($obj = $this->db->fetch_object($resql)) {
2284 if (is_array($value_arr) && in_array($obj->rowid, $value_arr)) {
2285 $c = new Categorie($this->db);
2286 $c->fetch($obj->rowid);
2287 $ways = $c->print_all_ways(); // $ways[0] = "ccc2 >> ccc2a >> ccc2a1" with html formatted text
2288 foreach ($ways as $way) {
2289 $toprint[] = '<li class="select2-search-choice-dolibarr noborderoncategories"'.($c->color ? ' style="background: #'.$c->color.';"' : ' style="background: #bbb"').'>'.img_object('', 'category').' '.$way.'</li>';
2290 }
2291 }
2292 }
2293 }
2294 if (!empty($toprint)) {
2295 $value = '<div class="select2-container-multi-dolibarr" style="width: 90%;"><ul class="select2-choices-dolibarr">'.implode(' ', $toprint).'</ul></div>';
2296 }
2297 } else {
2298 dol_syslog(get_class($this).'::showOutputField error '.$this->db->lasterror(), LOG_WARNING);
2299 }
2300 } elseif ($type == 'link') {
2301 $out = '';
2302
2303 // Only if something to display (perf)
2304 if ($value) { // If we have -1 here, pb is into insert, not into output (fix insert instead of changing code here to compensate)
2305 $param_list = array_keys($param['options']); // $param_list='ObjectName:classPath'
2306
2307 $InfoFieldList = explode(":", $param_list[0]);
2308 $classname = $InfoFieldList[0];
2309 $classpath = $InfoFieldList[1];
2310 if (!empty($classpath)) {
2311 dol_include_once($InfoFieldList[1]);
2312 if ($classname && class_exists($classname)) {
2313 $tmpobject = new $classname($this->db);
2314 '@phan-var-force CommonObject $tmpobject';
2315 $tmpobject->fetch($value);
2316 $value = $tmpobject->getNomUrl(3);
2317 }
2318 } else {
2319 dol_syslog('Error bad setup of extrafield', LOG_WARNING);
2320 return 'Error bad setup of extrafield';
2321 }
2322 }
2323 } elseif ($type == 'point') {
2324 if (!empty($value)) {
2325 require_once DOL_DOCUMENT_ROOT.'/core/class/dolgeophp.class.php';
2326 $dolgeophp = new DolGeoPHP($this->db);
2327 $value = $dolgeophp->getXYString($value);
2328 } else {
2329 $value = '';
2330 }
2331 } elseif (in_array($type, ['multipts', 'linestrg', 'polygon'])) {
2332 if (!empty($value)) {
2333 require_once DOL_DOCUMENT_ROOT.'/core/class/dolgeophp.class.php';
2334 $dolgeophp = new DolGeoPHP($this->db);
2335 $value = $dolgeophp->getPointString($value);
2336 } else {
2337 $value = '';
2338 }
2339 } elseif ($type == 'text') {
2340 $value = '<div class="'.($cssview ? $cssview : 'shortmessagecut').'">'.dol_htmlentitiesbr($value).'</div>';
2341 } elseif ($type == 'html') {
2342 $value = dol_htmlentitiesbr($value);
2343 } elseif ($type == 'password') {
2344 $value = dol_trunc(preg_replace('/./i', '*', $value), 8, 'right', 'UTF-8', 1);
2345 } elseif ($type == 'stars') {
2346 $objectid = (int) $object->id;
2347 if ($showValueInsteadOfInputField == 1) {
2348 $value = '<span style="display:none;" id="'.$key.$object->id.'">'.dol_escape_htmltag($value).'</span>';
2349 } else {
2350 $value = '<input type="hidden" class="flat" name="'.$key.'" id="'.$key.$objectid.'" value="'.dol_escape_htmltag($value).'"'.($moreparam ? $moreparam : '').'>';
2351 }
2352
2353 $value .= '<div class="star-selection" id="'.$key.$objectid.'_selection">';
2354 $i = 1;
2355 while ($i <= $size) {
2356 $value .= '<span class="star" data-value="'.$i.'">'.img_picto('', 'fontawesome_star_fas').'</span>';
2357 $i++;
2358 }
2359 $value .= '</div>';
2360 $value .= '<script>
2361 $(document).ready(function() {
2362 let container = $("#'.$key.$objectid.'_selection");
2363 let selectedStars = parseInt($("#'.$key.$objectid.'").val() || $("#'.$key.$objectid.'").text()) || 0;
2364 container.find(".star").each(function() {
2365 $(this).toggleClass("active", $(this).data("value") <= selectedStars);
2366 });';
2367 if ($showValueInsteadOfInputField == 0) {
2368 $value .= '
2369 container.find(".star").on("mouseover", function() {
2370 let selectedStar = $(this).data("value");
2371 container.find(".star").each(function() {
2372 $(this).toggleClass("active", $(this).data("value") <= selectedStar);
2373 });
2374 });
2375 container.on("mouseout", function() {
2376 container.find(".star").each(function() {
2377 $(this).toggleClass("active", $(this).data("value") <= selectedStars);
2378 });
2379 });
2380 container.find(".star").off("click").on("click", function() {
2381 selectedStars = $(this).data("value");
2382 if (selectedStars == 1 && $("#'.$key.$objectid.'").val() == 1) {
2383 selectedStars = 0;
2384 }
2385 container.find("#'.$key.$objectid.'").val(selectedStars);
2386 container.find(".star").each(function() {
2387 $(this).toggleClass("active", $(this).data("value") <= selectedStars);
2388 });
2389 $.ajax({
2390 url: "'.DOL_URL_ROOT.'/core/ajax/editextrafield.php",
2391 method: "POST",
2392 data: {
2393 objectType: \''.dol_escape_js($extrafieldsobjectkey).'\',
2394 objectId: '.((int) $objectid).',
2395 field: \''.dol_escape_js($key).'\',
2396 value: selectedStars,
2397 token: "'.newToken().'"
2398 },
2399 success: function(response) {
2400 var res = JSON.parse(response);
2401 console[res.status === "success" ? "log" : "error"](res.message);
2402 },
2403 error: function(xhr, status, error) {
2404 console.log("Ajax request failed while updating '.$key.':", error);
2405 }
2406 });
2407 });';
2408 }
2409 $value .= '
2410 });
2411 </script>';
2412 } else {
2413 $showsize = round((float) $size);
2414 if ($showsize > 48) {
2415 $showsize = 48;
2416 }
2417 }
2418
2419 //print $type.'-'.$size;
2420 $out = $value;
2421
2422 return $out;
2423 }
2424
2432 public function getAlignFlag($key, $extrafieldsobjectkey = '')
2433 {
2434 $type = 'varchar';
2435 if (!empty($extrafieldsobjectkey)) {
2436 $type = $this->attributes[$extrafieldsobjectkey]['type'][$key];
2437 }
2438
2439 $cssstring = '';
2440
2441 if (in_array($type, array('date', 'datetime', 'datetimegmt',))) {
2442 $cssstring = "center";
2443 } elseif (in_array($type, array('int', 'price', 'double', 'duration'))) {
2444 $cssstring = "right";
2445 } elseif (in_array($type, array('boolean', 'radio', 'checkbox', 'ip', 'icon'))) {
2446 $cssstring = "center";
2447 }
2448
2449 if (!empty($this->attributes[$extrafieldsobjectkey]['csslist'][$key])) {
2450 $cssstring .= ($cssstring ? ' ' : '').$this->attributes[$extrafieldsobjectkey]['csslist'][$key];
2451 } else {
2452 if (in_array($type, array('ip'))) {
2453 $cssstring .= ($cssstring ? ' ' : '').'tdoverflowmax150';
2454 }
2455 }
2456
2457 return $cssstring;
2458 }
2459
2470 public function showSeparator($key, $object, $colspan = 2, $display_type = 'card', $mode = '')
2471 {
2472 global $conf, $langs;
2473
2474 $tagtype = 'tr';
2475 $tagtype_dyn = 'td';
2476
2477 if ($display_type == 'line') {
2478 $tagtype = 'div';
2479 $tagtype_dyn = 'span';
2480 $colspan = 0;
2481 }
2482
2483 $extrafield_param = $this->attributes[$object->table_element]['param'][$key];
2484 $extrafield_param_list = array();
2485 if (!empty($extrafield_param) && is_array($extrafield_param)) {
2486 $extrafield_param_list = array_keys($extrafield_param['options']);
2487 }
2488
2489 // Set $extrafield_collapse_display_value (do we have to collapse/expand the group after the separator)
2490 $extrafield_collapse_display_value = -1;
2491 $expand_display = false;
2492 if (is_array($extrafield_param_list) && count($extrafield_param_list) > 0) {
2493 $extrafield_collapse_display_value = intval($extrafield_param_list[0]);
2494 $expand_display = ((isset($_COOKIE['DOLUSER_COLLAPSE_'.$object->table_element.'_extrafields_'.$key]) || GETPOSTINT('ignorecollapsesetup')) ? (!empty($_COOKIE['DOLUSER_COLLAPSE_'.$object->table_element.'_extrafields_'.$key])) : !($extrafield_collapse_display_value == 2));
2495 }
2496 $disabledcookiewrite = 0;
2497 if ($mode == 'create') {
2498 // On create mode, force separator group to not be collapsible
2499 $extrafield_collapse_display_value = 1;
2500 $expand_display = true; // We force group to be shown expanded
2501 $disabledcookiewrite = 1; // We keep status of group unchanged into the cookie
2502 }
2503
2504 $out = '<'.$tagtype.' id="trextrafieldseparator'.$key.(!empty($object->id) ? '_'.$object->id : '').'" class="trextrafieldseparator trextrafieldseparator'.$key.(!empty($object->id) ? '_'.$object->id : '').'">';
2505 $out .= '<'.$tagtype_dyn.' '.(!empty($colspan) ? 'colspan="' . $colspan . '"' : '').'>';
2506 // Some js code will be injected here to manage the collapsing of extrafields
2507 // Output the picto
2508 $out .= '<span class="'.($extrafield_collapse_display_value ? 'cursorpointer ' : '').($extrafield_collapse_display_value == 0 ? 'fas fa-square opacitymedium' : 'far fa-'.(($expand_display ? 'minus' : 'plus').'-square')).'"></span>';
2509 $out .= '&nbsp;';
2510 $out .= '<strong>';
2511 $out .= $langs->trans($this->attributes[$object->table_element]['label'][$key]);
2512 $out .= '</strong>';
2513 $out .= '</'.$tagtype_dyn.'>';
2514 $out .= '</'.$tagtype.'>';
2515
2516 $collapse_group = $key.(!empty($object->id) ? '_'.$object->id : '');
2517 //$extrafields_collapse_num = $this->attributes[$object->table_element]['pos'][$key].(!empty($object->id)?'_'.$object->id:'');
2518
2519 if ($extrafield_collapse_display_value == 1 || $extrafield_collapse_display_value == 2) {
2520 // Set the collapse_display status to cookie in priority or if ignorecollapsesetup is 1, if cookie and ignorecollapsesetup not defined, use the setup.
2521 $this->expand_display[$collapse_group] = $expand_display;
2522
2523 if (!empty($conf->use_javascript_ajax)) {
2524 $out .= '<!-- Add js script to manage the collapse/uncollapse of extrafields separators '.$key.' -->'."\n";
2525 $out .= '<script nonce="'.getNonce().'" type="text/javascript">'."\n";
2526 $out .= 'jQuery(document).ready(function(){'."\n";
2527 if (empty($disabledcookiewrite)) {
2528 if (!$expand_display) {
2529 $out .= ' console.log("Inject js for the collapsing of extrafield '.$key.' - hide");'."\n";
2530 $out .= ' jQuery(".trextrafields_collapse'.$collapse_group.'").hide();'."\n";
2531 } else {
2532 $out .= ' console.log("Inject js for collapsing of extrafield '.$key.' - keep visible and set cookie");'."\n";
2533 $out .= ' document.cookie = "DOLUSER_COLLAPSE_'.$object->table_element.'_extrafields_'.$key.'=1; path='.$_SERVER["PHP_SELF"].'"'."\n";
2534 }
2535 }
2536 $out .= ' jQuery("#trextrafieldseparator'.$key.(!empty($object->id) ? '_'.$object->id : '').'").click(function(){'."\n";
2537 $out .= ' console.log("We click on collapse/uncollapse to hide/show .trextrafields_collapse'.$collapse_group.'");'."\n";
2538 $out .= ' jQuery(".trextrafields_collapse'.$collapse_group.'").toggle(100, function(){'."\n";
2539 $out .= ' if (jQuery(".trextrafields_collapse'.$collapse_group.'").is(":hidden")) {'."\n";
2540 $out .= ' jQuery("#trextrafieldseparator'.$key.(!empty($object->id) ? '_'.$object->id : '').' '.$tagtype_dyn.' span").addClass("fa-plus-square").removeClass("fa-minus-square");'."\n";
2541 $out .= ' document.cookie = "DOLUSER_COLLAPSE_'.$object->table_element.'_extrafields_'.$key.'=0; path='.$_SERVER["PHP_SELF"].'"'."\n";
2542 $out .= ' } else {'."\n";
2543 $out .= ' jQuery("#trextrafieldseparator'.$key.(!empty($object->id) ? '_'.$object->id : '').' '.$tagtype_dyn.' span").addClass("fa-minus-square").removeClass("fa-plus-square");'."\n";
2544 $out .= ' document.cookie = "DOLUSER_COLLAPSE_'.$object->table_element.'_extrafields_'.$key.'=1; path='.$_SERVER["PHP_SELF"].'"'."\n";
2545 $out .= ' }'."\n";
2546 $out .= ' });'."\n";
2547 $out .= ' });'."\n";
2548 $out .= '});'."\n";
2549 $out .= '</script>'."\n";
2550 }
2551 } else {
2552 $this->expand_display[$collapse_group] = 1;
2553 }
2554
2555 return $out;
2556 }
2557
2569 public function setOptionalsFromPost($extralabels, &$object, $onlykey = '', $todefaultifmissing = 0)
2570 {
2571 global $langs;
2572
2573 $nofillrequired = 0; // For error when required field left blank
2574 $error_field_required = array();
2575
2576 if (isset($this->attributes[$object->table_element]['label']) && is_array($this->attributes[$object->table_element]['label'])) {
2577 $extralabels = $this->attributes[$object->table_element]['label'];
2578 }
2579
2580 if (is_array($extralabels)) {
2581 // Get extra fields
2582 foreach ($extralabels as $key => $value) {
2583 if (!empty($onlykey) && $onlykey != '@GETPOSTISSET' && $key != $onlykey) {
2584 continue;
2585 }
2586
2587 if (!empty($onlykey) && $onlykey == '@GETPOSTISSET' && !GETPOSTISSET('options_'.$key) && (! in_array($this->attributes[$object->table_element]['type'][$key], array('boolean', 'checkbox', 'chkbxlst', 'point', 'multipts', 'linestrg', 'polygon', 'duration')))) {
2588 //when unticking boolean field, it's not set in POST
2589 continue;
2590 }
2591
2592 $key_type = $this->attributes[$object->table_element]['type'][$key];
2593 if ($key_type == 'separate') {
2594 continue;
2595 }
2596
2597 $enabled = 1;
2598 if (isset($this->attributes[$object->table_element]['enabled'][$key])) { // 'enabled' is often a condition on module enabled or not
2599 $enabled = (int) dol_eval((string) $this->attributes[$object->table_element]['enabled'][$key], 1, 1, '2');
2600 }
2601
2602 $visibility = 1;
2603 if (isset($this->attributes[$object->table_element]['list'][$key])) { // 'list' is option for visibility
2604 $visibility = (int) dol_eval($this->attributes[$object->table_element]['list'][$key], 1, 1, '2');
2605 }
2606
2607 $perms = 1;
2608 if (isset($this->attributes[$object->table_element]['perms'][$key])) {
2609 $perms = (int) dol_eval($this->attributes[$object->table_element]['perms'][$key], 1, 1, '2');
2610 }
2611 if (empty($enabled)
2612 || (
2613 $onlykey === '@GETPOSTISSET'
2614 && in_array($this->attributes[$object->table_element]['type'][$key], array('boolean', 'checkbox', 'chkbxlst'))
2615 && in_array(abs($enabled), array(2, 5))
2616 && ! GETPOSTISSET('options_' . $key) // Update hidden checkboxes and multiselect only if they are provided
2617 )
2618 ) {
2619 continue;
2620 }
2621
2622 $visibility_abs = abs($visibility);
2623 // not modify if extra field is not in update form (0 : never, 2 or -2 : list only, 5 or - 5 : list and view only)
2624 if (empty($visibility_abs) || $visibility_abs == 2 || $visibility_abs == 5) {
2625 continue;
2626 }
2627 if (empty($perms)) {
2628 continue;
2629 }
2630
2631 if ($this->attributes[$object->table_element]['required'][$key]) { // Value is required
2632 // Check if functionally empty without using GETPOST (depending on the type of extrafield, a
2633 // technically non-empty value may be treated as empty functionally).
2634 // value can be alpha, int, array, etc...
2635 $v = $_POST["options_".$key] ?? null;
2636 $type = $this->attributes[$object->table_element]['type'][$key];
2637 if (self::isEmptyValue($v, $type)) {
2638 //print 'ccc'.$value.'-'.$this->attributes[$object->table_element]['required'][$key];
2639
2640 // Field is not defined. We mark this as an error. We may fix it later if there is a default value and $todefaultifmissing is set.
2641
2642 $nofillrequired++;
2643 if (!empty($this->attributes[$object->table_element]['langfile'][$key])) {
2644 $langs->load($this->attributes[$object->table_element]['langfile'][$key]);
2645 }
2646 $error_field_required[$key] = $langs->transnoentitiesnoconv($value);
2647 }
2648 }
2649
2650 if (in_array($key_type, array('date'))) {
2651 // Clean parameters
2652 $value_key = dol_mktime(12, 0, 0, GETPOSTINT("options_".$key."month"), GETPOSTINT("options_".$key."day"), GETPOSTINT("options_".$key."year"));
2653 } elseif (in_array($key_type, array('datetime'))) {
2654 // Clean parameters
2655 $value_key = dol_mktime(GETPOSTINT("options_".$key."hour"), GETPOSTINT("options_".$key."min"), GETPOSTINT("options_".$key."sec"), GETPOSTINT("options_".$key."month"), GETPOSTINT("options_".$key."day"), GETPOSTINT("options_".$key."year"), 'tzuserrel');
2656 } elseif (in_array($key_type, array('datetimegmt'))) {
2657 // Clean parameters
2658 $value_key = dol_mktime(GETPOSTINT("options_".$key."hour"), GETPOSTINT("options_".$key."min"), GETPOSTINT("options_".$key."sec"), GETPOSTINT("options_".$key."month"), GETPOSTINT("options_".$key."day"), GETPOSTINT("options_".$key."year"), 'gmt');
2659 } elseif (in_array($key_type, array('duration'))) {
2660 $value_hours = GETPOSTINT("options_" . $key . "hour");
2661 $value_minutes = GETPOSTINT("options_" . $key . "minute");
2662 $value_key = $value_hours * 3600 + $value_minutes * 60;
2663 } elseif (in_array($key_type, array('checkbox', 'chkbxlst'))) {
2664 $value_arr = GETPOST("options_".$key, 'array'); // check if an array
2665 if (!empty($value_arr)) {
2666 $value_key = implode(',', $value_arr);
2667 } else {
2668 $value_key = '';
2669 }
2670 } elseif (in_array($key_type, array('price', 'double'))) {
2671 $value_arr = GETPOST("options_".$key, 'alpha');
2672 $value_key = price2num($value_arr);
2673 } elseif (in_array($key_type, array('pricecy', 'double'))) {
2674 $value_key = price2num(GETPOST("options_".$key, 'alpha')).':'.GETPOST("options_".$key."currency_id", 'alpha');
2675 } elseif (in_array($key_type, array('html'))) {
2676 $value_key = GETPOST("options_".$key, 'restricthtml');
2677 } elseif (in_array($key_type, ['point', 'multipts', 'linestrg', 'polygon'])) {
2678 // construct point
2679 require_once DOL_DOCUMENT_ROOT.'/core/class/dolgeophp.class.php';
2680 $geojson = GETPOST("options_".$key, 'restricthtml');
2681 if ($geojson != '{}') {
2682 $dolgeophp = new DolGeoPHP($this->db);
2683 $value_key = $dolgeophp->getWkt($geojson);
2684 } else {
2685 $value_key = '';
2686 }
2687 } elseif (in_array($key_type, array('text'))) {
2688 $label_security_check = 'alphanohtml';
2689 // by default 'alphanohtml' (better security); hidden conf MAIN_SECURITY_ALLOW_UNSECURED_LABELS_WITH_HTML allows basic html
2690 if (getDolGlobalString('MAIN_SECURITY_ALLOW_UNSECURED_REF_LABELS')) {
2691 $label_security_check = 'nohtml';
2692 } else {
2693 $label_security_check = !getDolGlobalString('MAIN_SECURITY_ALLOW_UNSECURED_LABELS_WITH_HTML') ? 'alphanohtml' : 'restricthtml';
2694 }
2695 $value_key = GETPOST("options_".$key, $label_security_check);
2696 } else {
2697 $value_key = GETPOST("options_".$key);
2698 if (in_array($key_type, array('link')) && $value_key == '-1') {
2699 $value_key = '';
2700 }
2701 }
2702
2703 if (!empty($error_field_required[$key]) && $todefaultifmissing) {
2704 // Value is required but we have a default value and we asked to set empty value to the default value
2705 if (!empty($this->attributes[$object->table_element]['default']) && !is_null($this->attributes[$object->table_element]['default'][$key])) {
2706 $value_key = $this->attributes[$object->table_element]['default'][$key];
2707 unset($error_field_required[$key]);
2708 $nofillrequired--;
2709 }
2710 }
2711
2712 $object->array_options["options_".$key] = $value_key;
2713 }
2714
2715 if ($nofillrequired) {
2716 $langs->load('errors');
2717 $this->error = $langs->trans('ErrorFieldsRequired').' : '.implode(', ', $error_field_required);
2718 setEventMessages($this->error, null, 'errors');
2719 return -1;
2720 } else {
2721 return 1;
2722 }
2723 } else {
2724 return 0;
2725 }
2726 }
2727
2736 public function getOptionalsFromPost($extrafieldsobjectkey, $keysuffix = '', $keyprefix = '')
2737 {
2738 global $_POST;
2739
2740 if (is_string($extrafieldsobjectkey) && !empty($this->attributes[$extrafieldsobjectkey]['label']) && is_array($this->attributes[$extrafieldsobjectkey]['label'])) {
2741 $extralabels = $this->attributes[$extrafieldsobjectkey]['label'];
2742 } else {
2743 $extralabels = $extrafieldsobjectkey;
2744 }
2745
2746 if (is_array($extralabels)) {
2747 $array_options = array();
2748
2749 // Get extra fields
2750 foreach ($extralabels as $key => $value) {
2751 $key_type = '';
2752 if (is_string($extrafieldsobjectkey)) {
2753 $key_type = $this->attributes[$extrafieldsobjectkey]['type'][$key];
2754 }
2755
2756 if (in_array($key_type, array('date'))) {
2757 $dateparamname_start = $keyprefix . 'options_' . $key . $keysuffix . '_start';
2758 $dateparamname_end = $keyprefix . 'options_' . $key . $keysuffix . '_end';
2759
2760 if (GETPOST($dateparamname_start . 'year') || GETPOST($dateparamname_end . 'year')) {
2761 $value_key = array();
2762 // values provided as a component year, month, day, etc.
2763 if (GETPOST($dateparamname_start . 'year')) {
2764 $value_key['start'] = dol_mktime(0, 0, 0, GETPOSTINT($dateparamname_start . 'month'), GETPOSTINT($dateparamname_start . 'day'), GETPOSTINT($dateparamname_start . 'year'));
2765 }
2766 if (GETPOST($dateparamname_end . 'year')) {
2767 $value_key['end'] = dol_mktime(23, 59, 59, GETPOSTINT($dateparamname_end . 'month'), GETPOSTINT($dateparamname_end . 'day'), GETPOSTINT($dateparamname_end . 'year'));
2768 }
2769 } elseif (GETPOST($keyprefix."options_".$key.$keysuffix."year")) {
2770 // Clean parameters
2771 $value_key = dol_mktime(12, 0, 0, GETPOSTINT($keyprefix."options_".$key.$keysuffix."month"), GETPOSTINT($keyprefix."options_".$key.$keysuffix."day"), GETPOSTINT($keyprefix."options_".$key.$keysuffix."year"));
2772 } else {
2773 continue; // Value was not provided, we should not set it.
2774 }
2775 } elseif (in_array($key_type, array('datetime', 'datetimegmt'))) {
2776 $dateparamname_start = $keyprefix . 'options_' . $key . $keysuffix . '_start';
2777 $dateparamname_end = $keyprefix . 'options_' . $key . $keysuffix . '_end';
2778
2779 if (GETPOST($dateparamname_start . 'year') || GETPOST($dateparamname_end . 'year')) {
2780 // values provided as a date pair (start date + end date), each date being broken down as year, month, day, etc.
2781 $dateparamname_start_hour = GETPOSTINT($dateparamname_start . 'hour') != '-1' ? GETPOSTINT($dateparamname_start . 'hour') : '00';
2782 $dateparamname_start_min = GETPOSTINT($dateparamname_start . 'min') != '-1' ? GETPOSTINT($dateparamname_start . 'min') : '00';
2783 $dateparamname_start_sec = GETPOSTINT($dateparamname_start . 'sec') != '-1' ? GETPOSTINT($dateparamname_start . 'sec') : '00';
2784 $dateparamname_end_hour = GETPOSTINT($dateparamname_end . 'hour') != '-1' ? GETPOSTINT($dateparamname_end . 'hour') : '23';
2785 $dateparamname_end_min = GETPOSTINT($dateparamname_end . 'min') != '-1' ? GETPOSTINT($dateparamname_end . 'min') : '59';
2786 $dateparamname_end_sec = GETPOSTINT($dateparamname_end . 'sec') != '-1' ? GETPOSTINT($dateparamname_end . 'sec') : '59';
2787 if ($key_type == 'datetimegmt') {
2788 $value_key = array(
2789 'start' => dol_mktime($dateparamname_start_hour, $dateparamname_start_min, $dateparamname_start_sec, GETPOSTINT($dateparamname_start . 'month'), GETPOSTINT($dateparamname_start . 'day'), GETPOSTINT($dateparamname_start . 'year'), 'gmt'),
2790 'end' => dol_mktime($dateparamname_end_hour, $dateparamname_end_min, $dateparamname_end_sec, GETPOSTINT($dateparamname_end . 'month'), GETPOSTINT($dateparamname_end . 'day'), GETPOSTINT($dateparamname_end . 'year'), 'gmt')
2791 );
2792 } else {
2793 $value_key = array(
2794 'start' => dol_mktime($dateparamname_start_hour, $dateparamname_start_min, $dateparamname_start_sec, GETPOSTINT($dateparamname_start . 'month'), GETPOSTINT($dateparamname_start . 'day'), GETPOSTINT($dateparamname_start . 'year'), 'tzuserrel'),
2795 'end' => dol_mktime($dateparamname_end_hour, $dateparamname_end_min, $dateparamname_end_sec, GETPOSTINT($dateparamname_end . 'month'), GETPOSTINT($dateparamname_end . 'day'), GETPOSTINT($dateparamname_end . 'year'), 'tzuserrel')
2796 );
2797 }
2798 } elseif (GETPOST($keyprefix."options_".$key.$keysuffix."year")) {
2799 // Clean parameters
2800 if ($key_type == 'datetimegmt') {
2801 $value_key = dol_mktime(GETPOSTINT($keyprefix."options_".$key.$keysuffix."hour"), GETPOSTINT($keyprefix."options_".$key.$keysuffix."min"), GETPOSTINT($keyprefix."options_".$key.$keysuffix."sec"), GETPOSTINT($keyprefix."options_".$key.$keysuffix."month"), GETPOSTINT($keyprefix."options_".$key.$keysuffix."day"), GETPOSTINT($keyprefix."options_".$key.$keysuffix."year"), 'gmt');
2802 } else {
2803 $value_key = dol_mktime(GETPOSTINT($keyprefix."options_".$key.$keysuffix."hour"), GETPOSTINT($keyprefix."options_".$key.$keysuffix."min"), GETPOSTINT($keyprefix."options_".$key.$keysuffix."sec"), GETPOSTINT($keyprefix."options_".$key.$keysuffix."month"), GETPOSTINT($keyprefix."options_".$key.$keysuffix."day"), GETPOSTINT($keyprefix."options_".$key.$keysuffix."year"), 'tzuserrel');
2804 }
2805 } else {
2806 continue; // Value was not provided, we should not set it.
2807 }
2808 } elseif ($key_type == 'select') {
2809 // to detect if we are in search context
2810 if (GETPOSTISARRAY($keyprefix."options_".$key.$keysuffix)) {
2811 $value_arr = GETPOST($keyprefix."options_".$key.$keysuffix, 'array:aZ09');
2812 // Make sure we get an array even if there's only one selected
2813 $value_arr = (array) $value_arr;
2814 $value_key = implode(',', $value_arr);
2815 } else {
2816 $value_key = GETPOST($keyprefix."options_".$key.$keysuffix);
2817 }
2818 } elseif (in_array($key_type, array('checkbox', 'chkbxlst'))) {
2819 // We test on a hidden field named "..._multiselect" that is always set to 1 if param is in form so
2820 // when nothing is provided we can make a difference between noparam in the form and param was set to nothing.
2821 if (!GETPOSTISSET($keyprefix."options_".$key.$keysuffix.'_multiselect')) {
2822 continue; // Value was not provided, we should not set it.
2823 }
2824 $value_arr = GETPOST($keyprefix."options_".$key.$keysuffix);
2825 // Make sure we get an array even if there's only one checkbox
2826 $value_arr = (array) $value_arr;
2827 $value_key = implode(',', $value_arr);
2828 } elseif (in_array($key_type, array('price', 'double', 'int'))) {
2829 if (!GETPOSTISSET($keyprefix."options_".$key.$keysuffix)) {
2830 continue; // Value was not provided, we should not set it.
2831 }
2832 $value_arr = GETPOST($keyprefix."options_".$key.$keysuffix);
2833 if ($keyprefix != 'search_') { // If value is for a search, we must keep complex string like '>100 <=150'
2834 $value_key = price2num($value_arr);
2835 } else {
2836 $value_key = $value_arr;
2837 }
2838 } elseif (in_array($key_type, array('boolean'))) {
2839 // We test on a hidden field named "..._boolean" that is always set to 1 if param is in form so
2840 // when nothing is provided we can make a difference between noparam in the form and param was set to nothing.
2841 if (!GETPOSTISSET($keyprefix."options_".$key.$keysuffix."_boolean")) {
2842 $value_key = '';
2843 } else {
2844 $value_arr = GETPOST($keyprefix."options_".$key.$keysuffix);
2845 $value_key = $value_arr;
2846 }
2847 } elseif (in_array($key_type, array('html'))) {
2848 if (!GETPOSTISSET($keyprefix."options_".$key.$keysuffix)) {
2849 continue; // Value was not provided, we should not set it.
2850 }
2851 $value_key = dol_htmlcleanlastbr(GETPOST($keyprefix."options_".$key.$keysuffix, 'restricthtml'));
2852 } else {
2853 if (!GETPOSTISSET($keyprefix."options_".$key.$keysuffix)) {
2854 continue; // Value was not provided, we should not set it.
2855 }
2856 $value_key = GETPOST($keyprefix."options_".$key.$keysuffix);
2857 }
2858
2859 $array_options[$keyprefix."options_".$key] = $value_key; // No keyprefix here. keyprefix is used only for read.
2860 }
2861
2862 return $array_options;
2863 }
2864
2865 return 0;
2866 }
2867
2873 public static function getListOfTypesLabels()
2874 {
2875 global $langs;
2876
2877 $arraytype2label = array('');
2878
2879 $tmptype2label = ExtraFields::$type2label;
2880 foreach ($tmptype2label as $key => $val) {
2881 $arraytype2label[$key] = $langs->transnoentitiesnoconv($val);
2882 }
2883
2884 if (!getDolGlobalString('MAIN_USE_EXTRAFIELDS_ICON')) {
2885 unset($arraytype2label['icon']);
2886 }
2887 if (!getDolGlobalString('MAIN_USE_GEOPHP')) {
2888 unset($arraytype2label['point']);
2889 unset($arraytype2label['multipts']);
2890 unset($arraytype2label['linestrg']);
2891 unset($arraytype2label['polygon']);
2892 }
2893
2894 return $arraytype2label;
2895 }
2896
2904 public static function isEmptyValue($v, string $type)
2905 {
2906 if ($v === null || $v === '') {
2907 return true;
2908 }
2909 if (is_array($v) || $type == 'select') {
2910 return empty($v);
2911 }
2912 if ($type == 'link') {
2913 return ($v == '-1');
2914 }
2915 if ($type == 'sellist') {
2916 return ($v == '0');
2917 }
2918 return empty($v); // Note empty('0') is also true, tested 7.0 up to 8.3.12
2919 }
2920}
if( $user->socid > 0) if(! $user->hasRight('accounting', 'chartofaccount')) $object
Definition card.php:66
ajax_combobox($htmlname, $events=array(), $minLengthToAutocomplete=0, $forcefocus=0, $widthTypeOfAutocomplete='resolve', $idforemptyvalue='-1', $morecss='')
Convert a html select field into an ajax combobox.
Definition ajax.lib.php:459
Class to manage categories.
Class to manage a WYSIWYG editor.
Class to manage Geo processing Usage: $dolgeophp=new DolGeoPHP($db);.
Class to manage standard extra fields.
update_label($attrname, $label, $type, $size, $elementtype, $unique=0, $required=0, $pos=0, $param=array(), $alwayseditable=0, $perms='', $list='0', $help='', $default='', $computed='', $entity='', $langfile='', $enabled='1', $totalizable=0, $printable=0, $moreparams=array())
Modify description of personalized attribute This is a private method.
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, $moreparams=array())
Add a new extra field parameter.
getOptionalsFromPost($extrafieldsobjectkey, $keysuffix='', $keyprefix='')
return array_options array of data of extrafields value of object sent by a search form
create_label($attrname, $label='', $type='', $pos=0, $size='', $elementtype='', $unique=0, $required=0, $param='', $alwayseditable=0, $perms='', $list='-1', $help='', $default='', $computed='', $entity='', $langfile='', $enabled='1', $totalizable=0, $printable=0, $moreparams=array())
Add description of a new optional attribute.
fetch_name_optionals_label($elementtype, $forceload=false, $attrname='')
Load the array of extrafields definition $this->attributes.
create($attrname, $type='varchar', $length='255', $elementtype='', $unique=0, $required=0, $default_value='', $param=array(), $perms='', $list='0', $computed='', $help='', $moreparams=array())
Add a new optional attribute.
update($attrname, $label, $type, $length, $elementtype, $unique=0, $required=0, $pos=0, $param=array(), $alwayseditable=0, $perms='', $list='', $help='', $default='', $computed='', $entity='', $langfile='', $enabled='1', $totalizable=0, $printable=0, $moreparams=array())
Modify type of a personalized attribute.
static getListOfTypesLabels()
Return array with all possible types and labels of extrafields.
updateExtraField($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, $moreparams=array())
Update an existing extra field parameter.
showInputField($key, $value, $moreparam='', $keysuffix='', $keyprefix='', $morecss='', $object=0, $extrafieldsobjectkey='', $mode=0)
Return HTML string to put an input field into a page Code very similar with showInputField of common ...
__construct($db)
Constructor.
delete_label($attrname, $elementtype='')
Delete description of an optional attribute.
static isEmptyValue($v, string $type)
Return if a value is "empty" for a mandatory vision.
showOutputField($key, $value, $moreparam='', $extrafieldsobjectkey='', $outputlangs=null, $object=null)
Return HTML string to put an output field into a page.
Class to manage generation of HTML components Only common components must be here.
Class to manage a Leaflet map width geometrics objects.
print $langs trans("Ref").' m titre as m m statut as status
Or an array listing all the potential status of the object: array: int of the status => translated la...
Definition index.php:171
convertSecondToTime($iSecond, $format='all', $lengthOfDay=86400, $lengthOfWeek=7)
Return, in clear text, value of a number of seconds in days, hours and minutes.
Definition date.lib.php:244
dol_mktime($hour, $minute, $second, $month, $day, $year, $gm='auto', $check=1)
Return a timestamp date built from detailed information (by default a local PHP server timestamp) Rep...
img_object($titlealt, $picto, $moreatt='', $pictoisfullpath=0, $srconly=0, $notitle=0)
Show a picto called object_picto (generic function)
setEventMessages($mesg, $mesgs, $style='mesgs', $messagekey='', $noduplicate=0, $attop=0)
Set event messages in dol_events session object.
dol_print_ip($ip, $mode=0)
Return an IP formatted to be shown on screen.
img_picto($titlealt, $picto, $moreatt='', $pictoisfullpath=0, $srconly=0, $notitle=0, $alt='', $morecss='', $marginleftonlyshort=2)
Show picto whatever it's its name (generic function)
GETPOSTINT($paramname, $method=0)
Return the value of a $_GET or $_POST supervariable, converted into integer.
dol_print_phone($phone, $countrycode='', $cid=0, $socid=0, $addlink='', $separ="&nbsp;", $withpicto='', $titlealt='', $adddivfloat=0, $morecss='paddingright')
Format phone numbers according to country.
price2num($amount, $rounding='', $option=0)
Function that return a number with universal decimal format (decimal separator is '.
dol_eval($s, $returnvalue=1, $hideerrors=1, $onlysimplestring='1')
Replace eval function to add more security.
dol_print_url($url, $target='_blank', $max=32, $withpicto=0, $morecss='')
Show Url link.
price($amount, $form=0, $outlangs='', $trunc=1, $rounding=-1, $forcerounding=-1, $currency_code='')
Function to format a value into an amount for visual output Function used into PDF and HTML pages.
forgeSQLFromUniversalSearchCriteria($filter, &$errorstr='', $noand=0, $nopar=0, $noerror=0)
forgeSQLFromUniversalSearchCriteria
GETPOSTISARRAY($paramname, $method=0)
Return true if the parameter $paramname is submit from a POST OR GET as an array.
dol_now($mode='auto')
Return date for now.
getDolGlobalInt($key, $default=0)
Return a Dolibarr global constant int value.
dol_escape_js($stringtoescape, $mode=0, $noescapebackslashn=0)
Returns text escaped for inclusion into javascript code.
dol_print_date($time, $format='', $tzoutput='auto', $outputlangs=null, $encodetooutput=false)
Output date in a string format according to outputlangs (or langs if not defined).
if(!function_exists( 'dol_getprefix')) dol_include_once($relpath, $classname='')
Make an include_once using default root and alternate root if it fails.
dol_htmlcleanlastbr($stringtodecode)
This function remove all ending and br at end.
dol_print_email($email, $cid=0, $socid=0, $addlink=0, $max=64, $showinvalid=1, $withpicto=0, $morecss='paddingrightonly')
Show EMail link formatted for HTML output.
yn($yesno, $format=1, $color=0)
Return yes or no in current language.
GETPOST($paramname, $check='alphanohtml', $method=0, $filter=null, $options=null, $noreplace=0)
Return value of a param into GET or POST supervariable.
dol_print_error($db=null, $error='', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
dol_trunc($string, $size=40, $trunc='right', $stringencoding='UTF-8', $nodot=0, $display=0)
Truncate a string to a particular length adding '…' if string larger than length.
dol_htmlentitiesbr($stringtoencode, $nl2brmode=0, $pagecodefrom='UTF-8', $removelasteolbr=1)
This function is called to encode a string into a HTML string but differs from htmlentities because a...
jsonOrUnserialize($stringtodecode)
Decode an encode string.
getDolGlobalString($key, $default='')
Return a Dolibarr global constant string value.
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='', $logcontext=null)
Write log message into outputs.
dol_escape_htmltag($stringtoescape, $keepb=0, $keepn=0, $noescapetags='', $escapeonlyhtmltags=0, $cleanalsojavascript=0)
Returns text escaped for inclusion in HTML alt or title or value tags, or into values of HTML input f...
global $conf
The following vars must be defined: $type2label $form $conf, $lang, The following vars may also be de...
Definition member.php:79
if(preg_match('/crypted:/i', $dolibarr_main_db_pass)||!empty($dolibarr_main_db_encrypted_pass)) $conf db type
Definition repair.php:149