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