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