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