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: '".$objectid."',
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 // Re-add parent field that was removed by keyList reset above
1503 if (!empty($parentField)) {
1504 $keyList .= ', '.$parentField;
1505 }
1506 }
1507
1508 $filter_categorie = false;
1509 if (count($InfoFieldList) > 5) {
1510 if ($InfoFieldList[0] == 'categorie') {
1511 $filter_categorie = true;
1512 }
1513 }
1514
1515 if (!$filter_categorie) {
1516 $fields_label = explode('|', $InfoFieldList[1]);
1517 if (is_array($fields_label)) {
1518 $keyList .= ', ';
1519 $keyList .= implode(', ', $fields_label);
1520 }
1521
1522 // WARNING!! This code is duplicated into core/ajax/ajaxextrafield.php
1523
1524 $sqlwhere = '';
1525 $sql = "SELECT ".$keyList;
1526 $sql .= ' FROM '.$this->db->prefix().$InfoFieldList[0];
1527
1528 // Add filter from 4th field
1529 if (!empty($InfoFieldList[4])) {
1530 // can use current entity filter
1531 if (strpos($InfoFieldList[4], '$ENTITY$') !== false) {
1532 $InfoFieldList[4] = str_replace('$ENTITY$', (string) $conf->entity, $InfoFieldList[4]);
1533 }
1534 // can use SELECT request
1535 if (!getDolGlobalString("MAIN_DISALLOW_UNSECURED_SELECT_INTO_EXTRAFIELDS_FILTER")) {
1536 if (strpos($InfoFieldList[4], '$SEL$') !== false) {
1537 $InfoFieldList[4] = str_replace('$SEL$', 'SELECT', $InfoFieldList[4]);
1538 }
1539 }
1540 // can use MODE parameter (list or view)
1541 if (strpos($InfoFieldList[4], '$MODE$') !== false) {
1542 $InfoFieldList[4] = str_replace('$MODE$', preg_replace('/[^a-z0-9_]/i', '', (string) $mode), $InfoFieldList[4]);
1543 }
1544
1545 // current object id can be use into filter
1546 if (strpos($InfoFieldList[4], '$ID$') !== false && !empty($objectid)) {
1547 $InfoFieldList[4] = str_replace('$ID$', (string) $objectid, $InfoFieldList[4]);
1548 } elseif (substr($_SERVER["PHP_SELF"], -8) == 'list.php') {
1549 // In filters of list views, we do not want $ID$ replaced by 0. So we remove the '=' condition.
1550 // Do nothing if condition is using 'IN' keyword
1551 // Replace 'column = $ID$' by an always true test, the parent object is unknown in a list
1552 $word = '#\b([a-zA-Z0-9-\.-_]+)\b *= *\$ID\$#';
1553 $InfoFieldList[4] = preg_replace($word, '1 = 1', $InfoFieldList[4]);
1554 // Replace '$ID$ = column' by an always true test
1555 $word = '#\$ID\$ *= *\b([a-zA-Z0-9-\.-_]+)\b#';
1556 $InfoFieldList[4] = preg_replace($word, '1 = 1', $InfoFieldList[4]);
1557 // Same with the Universal Search Filter syntax, '(column:=:$ID$)'
1558 $word = '#\b([a-zA-Z0-9-\.-_]+)\b *: *[<>!=]?= *: *\$ID\$#';
1559 $InfoFieldList[4] = preg_replace($word, '1 = 1', $InfoFieldList[4]);
1560 } else {
1561 $InfoFieldList[4] = str_replace('$ID$', '0', $InfoFieldList[4]);
1562 }
1563
1564 // can use filter on any field of object
1565 if (is_object($object)) {
1566 $tags = [];
1567 preg_match_all('/\$(.*?)\$/', $InfoFieldList[4], $tags); // Example: $InfoFieldList[4] is ($dateadh$:<=:CURRENT_DATE)
1568 foreach ($tags[0] as $keytag => $valuetag) {
1569 $property = preg_replace('/[^a-z0-9_]/', '', strtolower($tags[1][$keytag]));
1570 if (strpos($InfoFieldList[4], $valuetag) !== false && property_exists($object, $property) && !empty($object->$property)) {
1571 $InfoFieldList[4] = str_replace($valuetag, (string) $object->$property, $InfoFieldList[4]);
1572 } else {
1573 $InfoFieldList[4] = str_replace($valuetag, '0', $InfoFieldList[4]);
1574 }
1575 }
1576 }
1577
1578 // We have to join on extrafield table
1579 $errstr = '';
1580 if (strpos($InfoFieldList[4], 'extra.') !== false) {
1581 $sql .= ' as main, '.$this->db->sanitize($this->db->prefix().$InfoFieldList[0]).'_extrafields as extra';
1582 $sqlwhere .= " WHERE extra.fk_object = main.".$this->db->sanitize($InfoFieldList[2]);
1583 $sqlwhere .= " AND " . forgeSQLFromUniversalSearchCriteria($InfoFieldList[4], $errstr, 1);
1584 } else {
1585 $sqlwhere .= " WHERE " . forgeSQLFromUniversalSearchCriteria($InfoFieldList[4], $errstr, 1);
1586 }
1587 } else {
1588 $sqlwhere .= ' WHERE 1=1';
1589 }
1590
1591 // Add Usf filter on second line
1592 /*
1593 if ($Usf) {
1594 $errorstr = '';
1595 $sqlusf .= forgeSQLFromUniversalSearchCriteria($Usf, $errorstr);
1596 if (!$errorstr) {
1597 $sqlwhere .= $sqlusf;
1598 } else {
1599 $sqlwhere .= " AND invalid_usf_filter_of_extrafield";
1600 }
1601 }
1602 */
1603
1604 // Some tables may have field, some other not. For the moment we disable it.
1605 if (in_array($InfoFieldList[0], array('tablewithentity'))) {
1606 $sqlwhere .= ' AND entity = '.((int) $conf->entity);
1607 }
1608 $sql .= $sqlwhere;
1609
1610 $sql .= $this->db->order(implode(', ', $fields_label));
1611 $sql .= ' LIMIT ' . getDolGlobalInt('MAIN_EXTRAFIELDS_LIMIT_SELLIST_SQL', 1000);
1612 //print $sql;
1613
1614 dol_syslog(get_class($this).'::showInputField type=sellist', LOG_DEBUG);
1615 $resql = $this->db->query($sql);
1616 if ($resql) {
1617 $out .= '<option value="0">&nbsp;</option>';
1618 $num = $this->db->num_rows($resql);
1619 $i = 0;
1620 while ($i < $num) {
1621 $labeltoshow = '';
1622 $obj = $this->db->fetch_object($resql);
1623
1624 $nameFields = $InfoFieldList[1];
1625 // If text is "field1|f(a,b,c) as xxx|field2", we must convert string into 'field1|xxx|field2'
1626 $nameFields = preg_replace('/[a-z_]+\‍([^\‍)]*\‍) as ([\w]+)/i', '\1', $nameFields);
1627 // Sanitize field names to avoid error when doing $obj->field
1628 $nameFields = preg_replace('/[^0-9a-z_\.\|]/i', '', $nameFields);
1629
1630 // Several fields into label (eq table:code|label:rowid)
1631 $notrans = false;
1632 $fields_label = explode('|', $nameFields);
1633 if (is_array($fields_label) && count($fields_label) > 1) {
1634 $notrans = true;
1635 foreach ($fields_label as $field_toshow) {
1636 $field_toshow = preg_replace('/^.*\./', '', $field_toshow);
1637 $labeltoshow .= $obj->$field_toshow.' ';
1638 }
1639 } else {
1640 $labeltoshow = $obj->$nameFields;
1641 }
1642
1643 if ($value == $obj->rowid) {
1644 if (!$notrans) {
1645 foreach ($fields_label as $field_toshow) {
1646 $translabel = $langs->trans($obj->$field_toshow);
1647 $labeltoshow = $translabel.' ';
1648 }
1649 }
1650 $out .= '<option value="'.$obj->rowid.'" selected>'.$labeltoshow.'</option>';
1651 } else {
1652 if (!$notrans) {
1653 $translabel = $langs->trans($obj->$nameFields);
1654 $labeltoshow = $translabel;
1655 }
1656 if (empty($labeltoshow)) {
1657 $labeltoshow = '(not defined)';
1658 }
1659
1660 if (!empty($InfoFieldList[3]) && $parentField) {
1661 // Sanitize parent field name to avoid when doing $obj->field
1662 $parentField = preg_replace('/[^a-zA-Z0-9_\-]/', '', $parentField);
1663 $parent = $parentName.':'.$obj->{$parentField};
1664 }
1665
1666 $out .= '<option value="'.$obj->rowid.'"';
1667 $out .= ($value == $obj->rowid ? ' selected' : '');
1668 $out .= (!empty($parent) ? ' parent="'.$parent.'"' : '');
1669 $out .= '>'.$labeltoshow.'</option>';
1670 }
1671
1672 $i++;
1673 }
1674 $this->db->free($resql);
1675 } else {
1676 print 'Error in request '.$sql.' '.$this->db->lasterror().'. Check setup of extra parameters.<br>';
1677 }
1678 } else {
1679 require_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php';
1680 $categcode = $InfoFieldList[5];
1681 if (is_numeric($categcode)) {
1682 $categcode = Categorie::$MAP_ID_TO_CODE[$InfoFieldList[5]];
1683 }
1684 $data = $form->select_all_categories($categcode, '', 'parent', 64, $InfoFieldList[6], 1, 1);
1685 $out .= '<option value="0">&nbsp;</option>';
1686 if (is_array($data)) {
1687 foreach ($data as $data_key => $data_value) {
1688 $out .= '<option value="'.$data_key.'"';
1689 $out .= ($value == $data_key ? ' selected' : '');
1690 $out .= '>'.$data_value.'</option>';
1691 }
1692 }
1693 }
1694 }
1695 $out .= '</select>';
1696 }
1697 } elseif ($type == 'checkbox') {
1698 $value_arr = $value;
1699 if (!is_array($value)) {
1700 $value_arr = explode(',', $value);
1701 }
1702 $out = $form->multiselectarray($keyprefix.$key.$keysuffix, (empty($param['options']) ? null : $param['options']), $value_arr, 0, 0, '', 0, '100%');
1703 } elseif ($type == 'radio') {
1704 $out = '';
1705 foreach ($param['options'] as $keyopt => $val) {
1706 $out .= '<input class="flat '.$morecss.'" type="radio" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" '.($moreparam ? $moreparam : '');
1707 $out .= ' value="'.$keyopt.'"';
1708 $out .= ' id="'.$keyprefix.$key.$keysuffix.'_'.$keyopt.'"';
1709 $out .= ($value == $keyopt ? 'checked' : '');
1710 $out .= '/><label for="'.$keyprefix.$key.$keysuffix.'_'.$keyopt.'">'.$langs->trans($val).'</label><br>';
1711 }
1712 } elseif ($type == 'chkbxlst') { // List of values selected from a table (n choices)
1713 if (is_array($value)) {
1714 $value_arr = $value;
1715 } else {
1716 $value_arr = explode(',', $value);
1717 }
1718
1719 if (is_array($param['options'])) {
1720 $tmpparamoptions = array_keys($param['options']);
1721 $paramoptions = preg_split('/[\r\n]+/', $tmpparamoptions[0]);
1722
1723 $InfoFieldList = explode(":", $paramoptions[0], 5);
1724 // 0 : tableName
1725 // 1 : label field name
1726 // 2 : key fields name (if different of rowid)
1727 // optional parameters...
1728 // 3 : key field parent (for dependent lists). How this is used ?
1729 // 4 : where clause filter on column or table extrafield, syntax field='value' or extra.field=value. Or use USF on the second line.
1730 // 5 : string category type. This replace the filter.
1731 // 6 : ids categories list separated by comma for category root. This replace the filter.
1732 // 7 : sort field (not used here but used into format for commobject)
1733
1734 // If there is a filter, we extract it by taking all content inside parenthesis.
1735 if (! empty($InfoFieldList[4])) {
1736 $pos = 0;
1737 $parenthesisopen = 0;
1738 while (substr($InfoFieldList[4], $pos, 1) !== '' && ($parenthesisopen || $pos == 0 || substr($InfoFieldList[4], $pos, 1) != ':')) {
1739 if (substr($InfoFieldList[4], $pos, 1) == '(') {
1740 $parenthesisopen++;
1741 }
1742 if (substr($InfoFieldList[4], $pos, 1) == ')') {
1743 $parenthesisopen--;
1744 }
1745 $pos++;
1746 }
1747 $tmpbefore = substr($InfoFieldList[4], 0, $pos);
1748 $tmpafter = substr($InfoFieldList[4], $pos + 1);
1749 //var_dump($InfoFieldList[4].' -> '.$pos); var_dump($tmpafter);
1750 $InfoFieldList[4] = $tmpbefore;
1751 if ($tmpafter !== '') {
1752 $InfoFieldList = array_merge($InfoFieldList, explode(':', $tmpafter));
1753 }
1754
1755 // Fix better compatibility with some old extrafield syntax filter "(field_name=123)"
1756 $reg = array();
1757 if (preg_match('/^\‍(?([a-z0-9_]+)([=<>]+)(\d+)\‍)?$/i', $InfoFieldList[4], $reg)) {
1758 $InfoFieldList[4] = '('.$reg[1].':'.$reg[2].':'.$reg[3].')';
1759 }
1760
1761 //var_dump($InfoFieldList);
1762 }
1763
1764 //$Usf = empty($paramoptions[1]) ? '' :$paramoptions[1];
1765
1766 $parentName = '';
1767 $parentField = '';
1768 $keyList = (empty($InfoFieldList[2]) ? 'rowid' : $InfoFieldList[2].' as rowid');
1769
1770 if (count($InfoFieldList) > 4 && !empty($InfoFieldList[4])) {
1771 if (strpos($InfoFieldList[4], 'extra.') !== false) {
1772 $keyList = 'main.'.$InfoFieldList[2].' as rowid';
1773 } else {
1774 $keyList = $InfoFieldList[2].' as rowid';
1775 }
1776 }
1777 if (count($InfoFieldList) > 3 && !empty($InfoFieldList[3])) {
1778 list($parentName, $parentField) = explode('|', $InfoFieldList[3]);
1779 if (!empty($InfoFieldList[4]) && strpos($InfoFieldList[4], 'extra.') !== false) {
1780 $keyList .= ', main.'.$parentField;
1781 } else {
1782 $keyList .= ', '.$parentField;
1783 }
1784 // Re-add parent field that was removed by keyList reset above
1785 if (!empty($parentField)) {
1786 $keyList .= ', '.$parentField;
1787 }
1788 }
1789
1790 $filter_categorie = false;
1791 if (count($InfoFieldList) > 5) {
1792 if ($InfoFieldList[0] == 'categorie') {
1793 $filter_categorie = true;
1794 }
1795 }
1796
1797 if (!$filter_categorie) {
1798 $fields_label = explode('|', $InfoFieldList[1]);
1799 if (is_array($fields_label)) {
1800 $keyList .= ', ';
1801 $keyList .= implode(', ', $fields_label);
1802 }
1803
1804 $sqlwhere = '';
1805 $sql = "SELECT ".$keyList;
1806 $sql .= ' FROM '.$this->db->prefix().$InfoFieldList[0];
1807
1808 // Add filter from 4th field
1809 if (!empty($InfoFieldList[4])) {
1810 // can use current entity filter
1811 if (strpos($InfoFieldList[4], '$ENTITY$') !== false) {
1812 $InfoFieldList[4] = str_replace('$ENTITY$', (string) $conf->entity, $InfoFieldList[4]);
1813 }
1814 // can use SELECT request
1815 if (strpos($InfoFieldList[4], '$SEL$') !== false) {
1816 $InfoFieldList[4] = str_replace('$SEL$', 'SELECT', $InfoFieldList[4]);
1817 }
1818
1819 // current object id can be use into filter
1820 if (strpos($InfoFieldList[4], '$ID$') !== false && !empty($objectid)) {
1821 $InfoFieldList[4] = str_replace('$ID$', (string) $objectid, $InfoFieldList[4]);
1822 } elseif (substr($_SERVER["PHP_SELF"], -8) == 'list.php') {
1823 // In filters of list views, we do not want $ID$ replaced by 0. So we remove the '=' condition.
1824 // Do nothing if condition is using 'IN' keyword
1825 // Replace 'column = $ID$' by an always true test, the parent object is unknown in a list
1826 $word = '#\b([a-zA-Z0-9-\.-_]+)\b *= *\$ID\$#';
1827 $InfoFieldList[4] = preg_replace($word, '1 = 1', $InfoFieldList[4]);
1828 // Replace '$ID$ = column' by an always true test
1829 $word = '#\$ID\$ *= *\b([a-zA-Z0-9-\.-_]+)\b#';
1830 $InfoFieldList[4] = preg_replace($word, '1 = 1', $InfoFieldList[4]);
1831 // Same with the Universal Search Filter syntax, '(column:=:$ID$)'
1832 $word = '#\b([a-zA-Z0-9-\.-_]+)\b *: *[<>!=]?= *: *\$ID\$#';
1833 $InfoFieldList[4] = preg_replace($word, '1 = 1', $InfoFieldList[4]);
1834 } else {
1835 $InfoFieldList[4] = str_replace('$ID$', '0', $InfoFieldList[4]);
1836 }
1837
1838 // We have to join on extrafield table
1839 $errstr = '';
1840 if (strpos($InfoFieldList[4], 'extra.') !== false) {
1841 $sql .= ' as main, '.$this->db->sanitize($this->db->prefix().$InfoFieldList[0]).'_extrafields as extra';
1842 $sqlwhere .= " WHERE extra.fk_object = main.".$this->db->sanitize($InfoFieldList[2]);
1843 $sqlwhere .= " AND " . forgeSQLFromUniversalSearchCriteria($InfoFieldList[4], $errstr, 1);
1844 } else {
1845 $sqlwhere .= " WHERE " . forgeSQLFromUniversalSearchCriteria($InfoFieldList[4], $errstr, 1);
1846 }
1847 } else {
1848 $sqlwhere .= ' WHERE 1=1';
1849 }
1850
1851 // Add Usf filter on second line
1852 /*
1853 if ($Usf) {
1854 $errorstr = '';
1855 $sqlusf .= forgeSQLFromUniversalSearchCriteria($Usf, $errorstr);
1856 if (!$errorstr) {
1857 $sqlwhere .= $sqlusf;
1858 } else {
1859 $sqlwhere .= " AND invalid_usf_filter_of_extrafield";
1860 }
1861 }
1862 */
1863
1864 // Some tables may have field, some other not. For the moment we disable it.
1865 if (in_array($InfoFieldList[0], array('tablewithentity'))) {
1866 $sqlwhere .= " AND entity = ".((int) $conf->entity);
1867 }
1868 // $sql.=preg_replace('/^ AND /','',$sqlwhere);
1869 // print $sql;
1870
1871 $sql .= $sqlwhere;
1872 $sql .= ' ORDER BY '.implode(', ', $fields_label);
1873
1874 dol_syslog(get_class($this).'::showInputField type=chkbxlst', LOG_DEBUG);
1875 $resql = $this->db->query($sql);
1876 if ($resql) {
1877 $num = $this->db->num_rows($resql);
1878 $i = 0;
1879
1880 $data = array();
1881
1882 while ($i < $num) {
1883 $labeltoshow = '';
1884 $obj = $this->db->fetch_object($resql);
1885
1886 $notrans = false;
1887 // Several field into label (eq table:code|label:rowid)
1888 $fields_label = explode('|', $InfoFieldList[1]);
1889 if (is_array($fields_label)) {
1890 $notrans = true;
1891 foreach ($fields_label as $field_toshow) {
1892 $labeltoshow .= $obj->$field_toshow.' ';
1893 }
1894 } else {
1895 $labeltoshow = $obj->{$InfoFieldList[1]};
1896 }
1897 $labeltoshow = dol_trunc($labeltoshow, 45);
1898
1899 if (is_array($value_arr) && in_array($obj->rowid, $value_arr)) {
1900 $labeltoshow = '';
1901 foreach ($fields_label as $field_toshow) {
1902 $translabel = $langs->trans($obj->$field_toshow);
1903 if ($translabel != $obj->$field_toshow) {
1904 $labeltoshow .= ' '.dol_trunc($translabel, 18).' ';
1905 } else {
1906 $labeltoshow .= ' '.dol_trunc($obj->$field_toshow, 18).' ';
1907 }
1908 }
1909 $data[$obj->rowid] = $labeltoshow;
1910 } else {
1911 if (!$notrans) {
1912 $translabel = $langs->trans($obj->{$InfoFieldList[1]});
1913 if ($translabel != $obj->{$InfoFieldList[1]}) {
1914 $labeltoshow = dol_trunc($translabel, 18);
1915 } else {
1916 $labeltoshow = dol_trunc($obj->{$InfoFieldList[1]}, 18);
1917 }
1918 }
1919 if (empty($labeltoshow)) {
1920 $labeltoshow = '(not defined)';
1921 }
1922
1923 if (is_array($value_arr) && in_array($obj->rowid, $value_arr)) {
1924 $data[$obj->rowid] = $labeltoshow;
1925 }
1926
1927 if (!empty($InfoFieldList[3]) && $parentField) {
1928 $parent = $parentName.':'.$obj->{$parentField};
1929 }
1930
1931 $data[$obj->rowid] = $labeltoshow;
1932 }
1933
1934 $i++;
1935 }
1936 $this->db->free($resql);
1937
1938 $out = $form->multiselectarray($keyprefix.$key.$keysuffix, $data, $value_arr, 0, 0, '', 0, '100%');
1939 } else {
1940 print 'Error in request '.$sql.' '.$this->db->lasterror().'. Check setup of extra parameters.<br>';
1941 }
1942 } else {
1943 require_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php';
1944 $categcode = $InfoFieldList[5];
1945 if (is_numeric($categcode)) {
1946 $categcode = Categorie::$MAP_ID_TO_CODE[$InfoFieldList[5]];
1947 }
1948 $data = $form->select_all_categories($categcode, '', 'parent', 64, $InfoFieldList[6], 1, 1);
1949 $out = $form->multiselectarray($keyprefix.$key.$keysuffix, $data, $value_arr, 0, 0, '', 0, '100%');
1950 }
1951 }
1952 } elseif ($type == 'link') {
1953 $param_list = array_keys($param['options']); // $param_list[0] = 'ObjectName:classPath' but can also be 'ObjectName:classPath:1:(status:=:1)'
1954 /* Removed.
1955 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
1956 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.
1957 if (strpos($param_list[0], '$ID$') !== false && !empty($objectid)) {
1958 $param_list[0] = str_replace('$ID$', $objectid, $param_list[0]);
1959 }*/
1960 $showempty = (($required && $default != '') ? 0 : 1);
1961
1962 $tmparray = explode(':', $param_list[0]);
1963
1964 $element = $extrafieldsobjectkey; // $extrafieldsobjectkey comes from $object->table_element but we need $object->element
1965 if ($element == 'socpeople') {
1966 $element = 'contact';
1967 } elseif ($element == 'projet') {
1968 $element = 'project';
1969 }
1970
1971 //$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
1972 $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.
1973 $objectfield = $element.':options_'.$key; // Example: 'actioncomm:options_fff' To be used in priority to know object linked with all its definition (including filters)
1974
1975 $out = $form->selectForForms($objectdesc, $keyprefix.$key.$keysuffix, $value, $showempty, '', '', $morecss, '', 0, 0, '', $objectfield);
1976 } elseif (in_array($type, ['point', 'multipts', 'linestrg', 'polygon'])) {
1977 require_once DOL_DOCUMENT_ROOT.'/core/class/dolgeophp.class.php';
1978 $dolgeophp = new DolGeoPHP($this->db);
1979 $geojson = '{}';
1980 $centroidjson = getDolGlobalString('MAIN_INFO_SOCIETE_GEO_COORDINATES', '{}');
1981 if (!empty($value)) {
1982 $tmparray = $dolgeophp->parseGeoString($value);
1983 $geojson = $tmparray['geojson'];
1984 $centroidjson = $tmparray['centroidjson'];
1985 }
1986 if (!preg_match('/search_/', $keyprefix)) {
1987 require_once DOL_DOCUMENT_ROOT.'/core/class/geomapeditor.class.php';
1988 $geomapeditor = new GeoMapEditor();
1989 $out .= $geomapeditor->getHtml($keyprefix.$key.$keysuffix, $geojson, $centroidjson, $type);
1990 } else {
1991 // If keyprefix is search_ or search_options_, we must just use a simple text field
1992 $out = '';
1993 }
1994 } elseif ($type == 'password') {
1995 // If prefix is 'search_', field is used as a filter, we use a common text field.
1996 $out = '<input style="display:none" type="text" name="fakeusernameremembered">'; // Hidden field to reduce impact of evil Google Chrome autopopulate bug.
1997 $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 : '').'>';
1998 } elseif ($type == 'stars') {
1999 $out = '<input type="hidden" class="flat '.$morecss.'" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" value="'.dol_escape_htmltag($value).'"'.($moreparam ? $moreparam : '').'>';
2000 $out .= '<div class="star-selection" id="'.$keyprefix.$key.$keysuffix.'_selection">';
2001 $i = 1;
2002 while ($i <= $size) {
2003 $out .= '<span class="star" data-value="'.$i.'">'.img_picto('', 'fontawesome_star_fas').'</span>';
2004 $i++;
2005 }
2006 $out .= '</div>';
2007 $out .= '<script>
2008 jQuery(function($) { /* extrafields.class.php 1 */
2009 let container = $("#'.$keyprefix.$key.$keysuffix.'_selection");
2010 let selectedStars = parseInt($("#'.$keyprefix.$key.$keysuffix.'").val()) || 0;
2011 container.find(".star").each(function() {
2012 $(this).toggleClass("active", $(this).data("value") <= selectedStars);
2013 });
2014 container.find(".star").on("mouseover", function() {
2015 let selectedStar = $(this).data("value");
2016 container.find(".star").each(function() {
2017 $(this).toggleClass("active", $(this).data("value") <= selectedStar);
2018 });
2019 });
2020 container.on("mouseout", function() {
2021 container.find(".star").each(function() {
2022 $(this).toggleClass("active", $(this).data("value") <= selectedStars);
2023 });
2024 });
2025 container.find(".star").off("click").on("click", function() {
2026 selectedStars = $(this).data("value");
2027 if (selectedStars === 1 && $("#'.$keyprefix.$key.$keysuffix.'").val() == 1) {
2028 selectedStars = 0;
2029 }
2030 $("#'.$keyprefix.$key.$keysuffix.'").val(selectedStars);
2031 container.find(".star").each(function() {
2032 $(this).toggleClass("active", $(this).data("value") <= selectedStars);
2033 });
2034 });
2035 });
2036 </script>';
2037 }
2038 if (!empty($hidden)) {
2039 $out = '<input type="hidden" value="'.$value.'" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'"/>';
2040 }
2041
2042 // If alwayseditable is false, and object is not in draft, then showOutputField
2043 // @phan-suppress-next-line PhanUndeclaredConstantOfClass
2044 if ($alwayseditable == 0 && is_object($object) && isset($object->status) && defined(get_class($object)."::STATUS_DRAFT") && $object->status != $object::STATUS_DRAFT) {
2045 $out = $this->showOutputField($key, $value, $moreparam, $extrafieldsobjectkey, null, $object);
2046 }
2047 /* Add comments
2048 if ($type == 'date') $out.=' (YYYY-MM-DD)';
2049 elseif ($type == 'datetime') $out.=' (YYYY-MM-DD HH:MM:SS)';
2050 */
2051 /*if (!empty($help) && $keyprefix != 'search_options_') {
2052 $out .= $form->textwithpicto('', $help, 1, 'help', '', 0, 3);
2053 }*/
2054 return $out;
2055 }
2056
2057
2069 public function showOutputField($key, $value, $moreparam = '', $extrafieldsobjectkey = '', $outputlangs = null, $object = null)
2070 {
2071 global $conf, $langs;
2072
2073 if (is_null($outputlangs) || !is_object($outputlangs)) {
2074 $outputlangs = $langs;
2075 }
2076
2077 if (empty($extrafieldsobjectkey)) {
2078 dol_syslog(get_class($this).'::showOutputField extrafieldsobjectkey required', LOG_ERR);
2079 return 'BadValueForParamExtraFieldsObjectKey';
2080 }
2081
2082 $label = $this->attributes[$extrafieldsobjectkey]['label'][$key];
2083 $type = $this->attributes[$extrafieldsobjectkey]['type'][$key];
2084 $size = $this->attributes[$extrafieldsobjectkey]['size'][$key]; // Can be '255', '24,8'...
2085 $default = $this->attributes[$extrafieldsobjectkey]['default'][$key];
2086 $computed = $this->attributes[$extrafieldsobjectkey]['computed'][$key];
2087 $unique = $this->attributes[$extrafieldsobjectkey]['unique'][$key];
2088 $required = $this->attributes[$extrafieldsobjectkey]['required'][$key];
2089 $param = $this->attributes[$extrafieldsobjectkey]['param'][$key];
2090 $perms = (int) dol_eval((string) $this->attributes[$extrafieldsobjectkey]['perms'][$key], 1, 1, '2');
2091 $langfile = $this->attributes[$extrafieldsobjectkey]['langfile'][$key];
2092 $list = (string) dol_eval((string) $this->attributes[$extrafieldsobjectkey]['list'][$key], 1, 1, '2');
2093 $help = $this->attributes[$extrafieldsobjectkey]['help'][$key];
2094 $cssview = $this->attributes[$extrafieldsobjectkey]['cssview'][$key];
2095 $alwayseditable = $this->attributes[$extrafieldsobjectkey]['alwayseditable'][$key];
2096
2097 // If alwayseditable is false, and object is not in draft, then we show value instead of input field
2098 $showValueInsteadOfInputField = 0; // Variable used to disable update of fields via ajax
2099 // @phan-suppress-next-line PhanUndeclaredConstantOfClass
2100 if ($alwayseditable == 0 && is_object($object) && isset($object->status) && defined(get_class($object)."::STATUS_DRAFT") && $object->status != $object::STATUS_DRAFT) {
2101 $showValueInsteadOfInputField = 1;
2102 }
2103
2104 $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)
2105
2106 if ($hidden) {
2107 return ''; // This is a protection. If field is hidden, we should just not call this method.
2108 }
2109
2110 //if ($computed) $value = // $value is already calculated into $value before calling this method
2111 $showsize = 0;
2112 if ($type == 'date') {
2113 $showsize = 10;
2114 if ($value !== '') {
2115 $value = dol_print_date($value, 'day'); // For date without hour, date is always GMT for storage and output
2116 }
2117 } elseif ($type == 'datetime') {
2118 $showsize = 19;
2119 if ($value !== '') {
2120 $value = dol_print_date($value, 'dayhour', 'tzuserrel');
2121 }
2122 } elseif ($type == 'duration') {
2123 $showsize = 10;
2124 if ($value !== '') {
2125 $value = intval($value);
2126 $value = convertSecondToTime($value);
2127 }
2128 } elseif ($type == 'datetimegmt') {
2129 $showsize = 19;
2130 if ($value !== '') {
2131 $value = dol_print_date($value, 'dayhour', 'gmt');
2132 }
2133 } elseif ($type == 'int') {
2134 $showsize = 10;
2135 } elseif ($type == 'double') {
2136 if (!empty($value)) {
2137 //$value=price($value);
2138 //$sizeparts = explode(",", $size);
2139 //$number_decimals = array_key_exists(1, $sizeparts) ? $sizeparts[1] : 0;
2140 $value = price($value, 0, $outputlangs, 0, 0, -2, '');
2141 }
2142 } elseif ($type == 'boolean') {
2143 $checked = '';
2144 if (!empty($value)) {
2145 $checked = ' checked ';
2146 }
2147 if (getDolGlobalInt('MAIN_OPTIMIZEFORTEXTBROWSER') < 2) {
2148 $value = '<input type="checkbox" '.$checked.' '.($moreparam ? $moreparam : '').' readonly disabled>';
2149 } else {
2150 $value = yn($value ? 1 : 0);
2151 }
2152 } elseif ($type == 'mail' || $type == 'email') {
2153 $value = dol_print_email($value, 0, 0, 0, 64, 1, 1);
2154 } elseif ($type == 'ip') {
2155 $value = dol_print_ip($value, 0);
2156 } elseif ($type == 'icon') {
2157 $value = '<span class="'.$value.'"></span>';
2158 } elseif ($type == 'url') {
2159 $value = dol_print_url($value, '_blank', 32, 1);
2160 } elseif ($type == 'phone') {
2161 $value = dol_print_phone($value, '', 0, 0, '', '&nbsp;', 'phone');
2162 } elseif ($type == 'price') {
2163 //$value = price($value, 0, $langs, 0, 0, -1, $conf->currency);
2164 if ($value || $value == '0') {
2165 $value = price($value, 0, $outputlangs, 0, getDolGlobalInt('MAIN_MAX_DECIMALS_TOT'), -1).' '.$outputlangs->getCurrencySymbol($conf->currency);
2166 }
2167 } elseif ($type == 'pricecy') {
2168 $currency = $conf->currency;
2169 if (!empty($value)) {
2170 // $value in memory is a php string like '0.01:EUR'
2171 $pricetmp = explode(':', $value);
2172 $currency = !empty($pricetmp[1]) ? $pricetmp[1] : $conf->currency;
2173 $value = $pricetmp[0];
2174 }
2175 if ($value || $value == '0') {
2176 $value = price($value, 0, $outputlangs, 0, getDolGlobalInt('MAIN_MAX_DECIMALS_TOT'), -1, $currency);
2177 }
2178 } elseif ($type == 'select') {
2179 $valstr = (!empty($param['options'][$value]) ? $param['options'][$value] : '');
2180 if (($pos = strpos($valstr, "|")) !== false) {
2181 $valstr = substr($valstr, 0, $pos);
2182 }
2183 if ($langfile && $valstr) {
2184 $value = $outputlangs->trans($valstr);
2185 } else {
2186 $value = $valstr;
2187 }
2188 } elseif ($type == 'sellist') {
2189 $param_list = array_keys($param['options']);
2190 $InfoFieldList = explode(":", $param_list[0]);
2191
2192 $selectkey = "rowid";
2193 $keyList = 'rowid';
2194
2195 if (count($InfoFieldList) >= 3) {
2196 $selectkey = $InfoFieldList[2];
2197 $keyList = $InfoFieldList[2].' as rowid';
2198 }
2199
2200 $fields_label = explode('|', $InfoFieldList[1]);
2201 if (is_array($fields_label)) {
2202 $keyList .= ', ';
2203 $keyList .= implode(', ', $fields_label);
2204 }
2205
2206 $filter_categorie = false;
2207 if (count($InfoFieldList) > 5) {
2208 if ($InfoFieldList[0] == 'categorie') {
2209 $filter_categorie = true;
2210 }
2211 }
2212
2213 $sql = "SELECT ".$keyList;
2214 $sql .= ' FROM '.$this->db->prefix().$InfoFieldList[0];
2215 if (!empty($InfoFieldList[4]) && strpos($InfoFieldList[4], 'extra.') !== false) {
2216 $sql .= ' as main';
2217 }
2218 if ($selectkey == 'rowid' && empty($value)) {
2219 $sql .= " WHERE ".$selectkey." = 0";
2220 } elseif ($selectkey == 'rowid') {
2221 $sql .= " WHERE ".$selectkey." = ".((int) $value);
2222 } else {
2223 $sql .= " WHERE ".$selectkey." = '".$this->db->escape($value)."'";
2224 }
2225
2226 //$sql.= ' AND entity = '.$conf->entity;
2227
2228 dol_syslog(get_class($this).':showOutputField:$type=sellist', LOG_DEBUG);
2229 $resql = $this->db->query($sql);
2230 if ($resql) {
2231 if (!$filter_categorie) {
2232 $value = ''; // value was used, so now we reset it to use it to build final output
2233
2234 $obj = $this->db->fetch_object($resql);
2235
2236 // Several field into label (eq table:code|label:rowid)
2237 $fields_label = explode('|', $InfoFieldList[1]);
2238
2239 if (is_array($fields_label) && count($fields_label) > 1) {
2240 foreach ($fields_label as $field_toshow) {
2241 $translabel = '';
2242 $field_toshow = preg_replace('/^.*\./', '', $field_toshow);
2243 if (!empty($obj->$field_toshow)) {
2244 $translabel = $outputlangs->trans($obj->$field_toshow);
2245
2246 if ($translabel != $obj->$field_toshow) {
2247 $value .= dol_trunc($translabel, 24) . ' ';
2248 } else {
2249 $value .= $obj->$field_toshow . ' ';
2250 }
2251 }
2252 }
2253 } else {
2254 $translabel = '';
2255 $tmppropname = $InfoFieldList[1];
2256 //$obj->$tmppropname = '';
2257 if (!empty(isset($obj->$tmppropname) ? $obj->$tmppropname : '')) {
2258 $translabel = $outputlangs->trans($obj->$tmppropname);
2259 }
2260 if ($translabel != (isset($obj->$tmppropname) ? $obj->$tmppropname : '')) {
2261 $value = dol_trunc($translabel, 18);
2262 } else {
2263 $value = isset($obj->$tmppropname) ? $obj->$tmppropname : '';
2264 }
2265 }
2266 } else {
2267 $toprint = array();
2268 $obj = $this->db->fetch_object($resql);
2269 if ($obj->rowid) {
2270 require_once DOL_DOCUMENT_ROOT . '/categories/class/categorie.class.php';
2271 $c = new Categorie($this->db);
2272 $result = $c->fetch($obj->rowid);
2273 if ($result > 0) {
2274 $ways = $c->print_all_ways(); // $ways[0] = "ccc2 >> ccc2a >> ccc2a1" with html formatted text
2275 foreach ($ways as $way) {
2276 $toprint[] = '<li class="select2-search-choice-dolibarr noborderoncategories"' . ($c->color ? ' style="background: #' . $c->color . ';"' : ' style="background: #bbb"') . '>' . img_object('', 'category') . ' ' . $way . '</li>';
2277 }
2278 }
2279 }
2280 $value = '<div class="select2-container-multi-dolibarr" style="width: 90%;"><ul class="select2-choices-dolibarr">'.implode(' ', $toprint).'</ul></div>';
2281 }
2282 } else {
2283 dol_syslog(get_class($this).'::showOutputField error '.$this->db->lasterror(), LOG_WARNING);
2284 }
2285 } elseif ($type == 'radio') {
2286 if ($required && !isset($param['options'][$value])) {
2287 $outputlangs->load('errors');
2288 $value = '<span class="opacitymedium">'.$outputlangs->trans('ErrorNoValueForRadioType').'</span>';
2289 } else {
2290 if (isset($param['options'][$value])) {
2291 $value = $outputlangs->trans($param['options'][$value]);
2292 } else {
2293 $value = '';
2294 }
2295 }
2296 } elseif ($type == 'checkbox') {
2297 $value_arr = explode(',', $value);
2298 $value = '';
2299 $toprint = array();
2300 if (is_array($value_arr)) {
2301 foreach ($value_arr as $keyval => $valueval) {
2302 if (!empty($valueval)) {
2303 $toprint[] = '<li class="select2-search-choice-dolibarr noborderoncategories" style="background: #bbb">'.$param['options'][$valueval].'</li>';
2304 }
2305 }
2306 }
2307 $value = '<div class="select2-container-multi-dolibarr" style="width: 90%;"><ul class="select2-choices-dolibarr">'.implode(' ', $toprint).'</ul></div>';
2308 } elseif ($type == 'chkbxlst') {
2309 $value_arr = explode(',', $value);
2310
2311 $param_list = array_keys($param['options']);
2312 $InfoFieldList = explode(":", $param_list[0]);
2313
2314 $selectkey = "rowid";
2315 $keyList = 'rowid';
2316
2317 if (count($InfoFieldList) >= 3) {
2318 $selectkey = $InfoFieldList[2];
2319 $keyList = $InfoFieldList[2].' as rowid';
2320 }
2321
2322 $fields_label = explode('|', $InfoFieldList[1]);
2323 if (is_array($fields_label)) {
2324 $keyList .= ', ';
2325 $keyList .= implode(', ', $fields_label);
2326 }
2327
2328 $filter_categorie = false;
2329 if (count($InfoFieldList) > 5) {
2330 if ($InfoFieldList[0] == 'categorie') {
2331 $filter_categorie = true;
2332 }
2333 }
2334
2335 $sql = "SELECT ".$keyList;
2336 $sql .= " FROM ".$this->db->prefix().$InfoFieldList[0];
2337 if (strpos($InfoFieldList[4], 'extra.') !== false) {
2338 $sql .= ' as main';
2339 }
2340 // $sql.= " WHERE ".$selectkey."='".$this->db->escape($value)."'";
2341 // $sql.= ' AND entity = '.$conf->entity;
2342
2343 dol_syslog(get_class($this).':showOutputField:$type=chkbxlst', LOG_DEBUG);
2344 $resql = $this->db->query($sql);
2345 if ($resql) {
2346 if (!$filter_categorie) {
2347 $value = ''; // value was used, so now we reset it to use it to build final output
2348 $toprint = array();
2349 while ($obj = $this->db->fetch_object($resql)) {
2350 // Several field into label (eq table:code|label:rowid)
2351 $fields_label = explode('|', $InfoFieldList[1]);
2352 if (is_array($value_arr) && in_array($obj->rowid, $value_arr)) {
2353 if (is_array($fields_label) && count($fields_label) > 1) {
2354 $label = '<li class="select2-search-choice-dolibarr noborderoncategories" style="background: #bbb">';
2355 foreach ($fields_label as $field_toshow) {
2356 $translabel = '';
2357 if (!empty($obj->$field_toshow)) {
2358 $translabel = $outputlangs->trans($obj->$field_toshow);
2359 }
2360 if ($translabel != $field_toshow) {
2361 $label .= ' '.dol_trunc($translabel, 18);
2362 } else {
2363 $label .= ' '.$obj->$field_toshow;
2364 }
2365 }
2366 $label .= '</li>';
2367 $toprint[] = $label;
2368 } else {
2369 $translabel = '';
2370 if (!empty($obj->{$InfoFieldList[1]})) {
2371 $translabel = $outputlangs->trans($obj->{$InfoFieldList[1]});
2372 }
2373 if ($translabel != $obj->{$InfoFieldList[1]}) {
2374 $toprint[] = '<li class="select2-search-choice-dolibarr noborderoncategories" style="background: #bbb">'.dol_trunc($translabel, 18).'</li>';
2375 } else {
2376 $toprint[] = '<li class="select2-search-choice-dolibarr noborderoncategories" style="background: #bbb">'.$obj->{$InfoFieldList[1]}.'</li>';
2377 }
2378 }
2379 }
2380 }
2381 } else {
2382 require_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php';
2383
2384 $toprint = array();
2385 while ($obj = $this->db->fetch_object($resql)) {
2386 if (is_array($value_arr) && in_array($obj->rowid, $value_arr)) {
2387 $c = new Categorie($this->db);
2388 $c->fetch($obj->rowid);
2389 $ways = $c->print_all_ways(); // $ways[0] = "ccc2 >> ccc2a >> ccc2a1" with html formatted text
2390 foreach ($ways as $way) {
2391 $toprint[] = '<li class="select2-search-choice-dolibarr noborderoncategories"'.($c->color ? ' style="background: #'.$c->color.';"' : ' style="background: #bbb"').'>'.img_object('', 'category').' '.$way.'</li>';
2392 }
2393 }
2394 }
2395 }
2396 if (!empty($toprint)) {
2397 $value = '<div class="select2-container-multi-dolibarr" style="width: 90%;"><ul class="select2-choices-dolibarr">'.implode(' ', $toprint).'</ul></div>';
2398 }
2399 } else {
2400 dol_syslog(get_class($this).'::showOutputField error '.$this->db->lasterror(), LOG_WARNING);
2401 }
2402 } elseif ($type == 'link') {
2403 $out = '';
2404
2405 // Only if something to display (perf)
2406 if ($value) { // If we have -1 here, pb is into insert, not into output (fix insert instead of changing code here to compensate)
2407 $param_list = array_keys($param['options']); // $param_list='ObjectName:classPath'
2408
2409 $InfoFieldList = explode(":", $param_list[0]);
2410 $classname = $InfoFieldList[0];
2411 $classpath = $InfoFieldList[1];
2412 if (!empty($classpath)) {
2413 dol_include_once($InfoFieldList[1]);
2414 if (!$classname || !class_exists($classname)) {
2415 // Without this, the raw id is printed with nothing telling why, which is very
2416 // hard to diagnose. Most often the class path stored in the definition is wrong.
2417 dol_syslog('Extrafields::showOutputField the class '.$classname.' of the link field '.$key.' could not be loaded from '.$classpath.', check the extrafield definition', LOG_WARNING);
2418 }
2419 if ($classname && class_exists($classname)) {
2420 $tmpobject = new $classname($this->db);
2421 '@phan-var-force CommonObject $tmpobject';
2422 $tmpobject->fetch($value);
2423
2424 if (get_class($tmpobject) == 'Categorie') {
2425 // For category object, rendering must use the same method than the one deinfed into showCategories()
2426 $color = $tmpobject->color;
2427 $sfortag = '<span class="noborderoncategories"' . ($color ? ' style="background: #' . $color . ';"' : ' style="background: #bbb"') . '>';
2428 $sfortag .= $tmpobject->getNomUrl(3);
2429 $sfortag .= '</span>';
2430 $value = $sfortag;
2431 } else {
2432 $value = $tmpobject->getNomUrl(3);
2433 }
2434 }
2435 } else {
2436 dol_syslog('Error bad setup of extrafield', LOG_WARNING);
2437 return 'Error bad setup of extrafield';
2438 }
2439 }
2440 } elseif ($type == 'point') {
2441 if (!empty($value)) {
2442 require_once DOL_DOCUMENT_ROOT.'/core/class/dolgeophp.class.php';
2443 $dolgeophp = new DolGeoPHP($this->db);
2444 $value = $dolgeophp->getXYString($value);
2445 } else {
2446 $value = '';
2447 }
2448 } elseif (in_array($type, ['multipts', 'linestrg', 'polygon'])) {
2449 if (!empty($value)) {
2450 require_once DOL_DOCUMENT_ROOT.'/core/class/dolgeophp.class.php';
2451 $dolgeophp = new DolGeoPHP($this->db);
2452 $value = $dolgeophp->getPointString($value);
2453 } else {
2454 $value = '';
2455 }
2456 } elseif ($type == 'text') {
2457 $value = '<div class="'.($cssview ? $cssview : 'shortmessagecut').'">'.dol_htmlentitiesbr($value).'</div>';
2458 } elseif ($type == 'html') {
2459 $value = dol_htmlentitiesbr($value);
2460 } elseif ($type == 'password') {
2461 $value = dol_trunc(preg_replace('/./i', '*', $value), 8, 'right', 'UTF-8', 1);
2462 } elseif ($type == 'stars') {
2463 $objectid = (int) $object->id;
2464 $nbstars = (int) $value;
2465 if ($showValueInsteadOfInputField == 1) {
2466 $value = '<span style="display:none;" id="'.$key.$object->id.'">'.dol_escape_htmltag($value).'</span>';
2467 } else {
2468 $value = '<input type="hidden" class="flat" name="'.$key.'" id="'.$key.$objectid.'" value="'.dol_escape_htmltag($value).'"'.($moreparam ? $moreparam : '').'>';
2469 }
2470
2471 $value .= '<div class="star-selection" id="'.$key.$objectid.'_selection">';
2472 $i = 1;
2473 while ($i <= $size) {
2474 $value .= '<span class="star'.($i <= $nbstars ? ' active' : '').'" data-value="'.$i.'">'.img_picto('', 'fontawesome_star_fas').'</span>';
2475 $i++;
2476 }
2477 $value .= '</div>';
2478 $value .= '<script>
2479 $(document).ready(function() { /* extrafields.class.php 2 */
2480 let container = $("#'.$key.$objectid.'_selection");
2481 let selectedStars = parseInt($("#'.$key.$objectid.'").val() || $("#'.$key.$objectid.'").text()) || 0;
2482 ';
2483 if ($showValueInsteadOfInputField == 0) {
2484 $value .= '
2485 container.find(".star").on("mouseover", function() {
2486 console.log("Mouse over a star");
2487 let selectedStar = $(this).data("value");
2488 container.find(".star").each(function() {
2489 $(this).toggleClass("active", $(this).data("value") <= selectedStar);
2490 });
2491 });
2492 container.on("mouseout", function() {
2493 console.log("Mouse out of star");
2494 container.find(".star").each(function() {
2495 $(this).toggleClass("active", $(this).data("value") <= selectedStars);
2496 });
2497 });
2498 container.find(".star").off("click").on("click", function() {
2499 console.log("We click on star, we call the ajax core/ajax/updateextrafield.php");
2500 selectedStars = $(this).data("value");
2501 if (selectedStars == 1 && $("#'.$key.$objectid.'").val() == 1) {
2502 selectedStars = 0;
2503 }
2504 container.find("#'.$key.$objectid.'").val(selectedStars);
2505 container.find(".star").each(function() {
2506 $(this).toggleClass("active", $(this).data("value") <= selectedStars);
2507 });
2508 $.ajax({
2509 url: "'.DOL_URL_ROOT.'/core/ajax/updateextrafield.php",
2510 method: "POST",
2511 data: {
2512 objectType: \''.dol_escape_js($extrafieldsobjectkey).'\',
2513 objectId: '.((int) $objectid).',
2514 field: \''.dol_escape_js($key).'\',
2515 value: selectedStars,
2516 token: \''.newToken().'\'
2517 },
2518 success: function(response) {
2519 var res = JSON.parse(response);
2520 console[res.status === "success" ? "log" : "error"](res.message);
2521 },
2522 error: function(xhr, status, error) {
2523 console.log("Ajax request failed while updating '.$key.':", error);
2524 }
2525 });
2526 });';
2527 }
2528 $value .= '
2529 });
2530 </script>';
2531 } else {
2532 $showsize = round((float) $size);
2533 if ($showsize > 48) {
2534 $showsize = 48;
2535 }
2536 }
2537
2538 //print $type.'-'.$size;
2539 $out = $value;
2540
2541 return $out;
2542 }
2543
2552 public function getAlignFlag($key, $extrafieldsobjectkey = '')
2553 {
2554 return $this->getCSSClass($key, $extrafieldsobjectkey);
2555 }
2556
2565 public function getCSSClass($key, $extrafieldsobjectkey = '', $mode = 'csslist')
2566 {
2567 $type = 'varchar';
2568 if (!empty($extrafieldsobjectkey)) {
2569 $type = $this->attributes[$extrafieldsobjectkey]['type'][$key];
2570 }
2571
2572 $cssstring = '';
2573
2574 if ($mode == 'csslist') {
2575 if (in_array($type, array('date', 'datetime', 'datetimegmt',))) {
2576 $cssstring = "center";
2577 } elseif (in_array($type, array('int', 'price', 'double', 'duration'))) {
2578 $cssstring = "right";
2579 } elseif (in_array($type, array('boolean', 'radio', 'checkbox', 'ip', 'icon'))) {
2580 $cssstring = "center";
2581 }
2582
2583 if (!empty($this->attributes[$extrafieldsobjectkey][$mode][$key])) {
2584 $cssstring .= ($cssstring ? ' ' : '').$this->attributes[$extrafieldsobjectkey][$mode][$key];
2585 } else {
2586 if (in_array($type, array('ip'))) {
2587 $cssstring .= ($cssstring ? ' ' : '').'tdoverflowmax150';
2588 }
2589 }
2590 }
2591
2592 if ($mode == 'css' || $mode == 'cssview') {
2593 if (!empty($this->attributes[$extrafieldsobjectkey][$mode][$key])) {
2594 $cssstring = ($cssstring ? ' ' : '').$this->attributes[$extrafieldsobjectkey][$mode][$key];
2595 }
2596 }
2597
2598 return $cssstring;
2599 }
2600
2611 public function showSeparator($key, $object, $colspan = 2, $display_type = 'card', $mode = '')
2612 {
2613 global $conf, $langs;
2614
2615 $tagtype = 'tr';
2616 $tagtype_dyn = 'td';
2617
2618 if ($display_type == 'line') {
2619 $tagtype = 'div';
2620 $tagtype_dyn = 'span';
2621 $colspan = 0;
2622 }
2623
2624 $extrafield_param = $this->attributes[$object->table_element]['param'][$key];
2625 $extrafield_param_list = array();
2626 if (!empty($extrafield_param) && is_array($extrafield_param)) {
2627 $extrafield_param_list = array_keys($extrafield_param['options']);
2628 }
2629
2630 // Set $extrafield_collapse_display_value (do we have to collapse/expand the group after the separator)
2631 $extrafield_collapse_display_value = -1;
2632 $expand_display = false;
2633 if (is_array($extrafield_param_list) && count($extrafield_param_list) > 0) {
2634 $extrafield_collapse_display_value = intval($extrafield_param_list[0]);
2635 $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));
2636 }
2637 $disabledcookiewrite = 0;
2638 if ($mode == 'create') {
2639 // On create mode, force separator group to not be collapsible
2640 $extrafield_collapse_display_value = 1;
2641 $expand_display = true; // We force group to be shown expanded
2642 $disabledcookiewrite = 1; // We keep status of group unchanged into the cookie
2643 }
2644
2645 $out = '<'.$tagtype.' id="trextrafieldseparator'.$key.(!empty($object->id) ? '_'.$object->id : '').'" class="trextrafieldseparator trextrafieldseparator'.$key.(!empty($object->id) ? '_'.$object->id : '').'">';
2646 $out .= '<'.$tagtype_dyn.' '.(!empty($colspan) ? 'colspan="' . $colspan . '"' : '').'>';
2647 // Some js code will be injected here to manage the collapsing of extrafields
2648 // Output the picto
2649 $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>';
2650 $out .= '&nbsp;';
2651 $out .= '<strong>';
2652 $out .= $langs->trans($this->attributes[$object->table_element]['label'][$key]);
2653 $out .= '</strong>';
2654 $out .= '</'.$tagtype_dyn.'>';
2655 $out .= '</'.$tagtype.'>';
2656
2657 $collapse_group = $key.(!empty($object->id) ? '_'.$object->id : '');
2658 //$extrafields_collapse_num = $this->attributes[$object->table_element]['pos'][$key].(!empty($object->id)?'_'.$object->id:'');
2659
2660 if ($extrafield_collapse_display_value == 1 || $extrafield_collapse_display_value == 2) {
2661 // Set the collapse_display status to cookie in priority or if ignorecollapsesetup is 1, if cookie and ignorecollapsesetup not defined, use the setup.
2662 $this->expand_display[$collapse_group] = $expand_display;
2663
2664 if (!empty($conf->use_javascript_ajax)) {
2665 $out .= '<!-- Add js script to manage the collapse/uncollapse of extrafields separators '.$key.' -->'."\n";
2666 $out .= '<script nonce="'.getNonce().'" type="text/javascript">'."\n";
2667 $out .= 'jQuery(document).ready(function(){'."\n";
2668 if (empty($disabledcookiewrite)) {
2669 if (!$expand_display) {
2670 $out .= ' console.log("Inject js for the collapsing of extrafield '.$key.' - hide");'."\n";
2671 $out .= ' jQuery(".trextrafields_collapse'.$collapse_group.'").hide();'."\n";
2672 } else {
2673 $out .= ' console.log("Inject js for collapsing of extrafield '.$key.' - keep visible and set cookie");'."\n";
2674 $out .= ' document.cookie = "DOLUSER_COLLAPSE_'.$object->table_element.'_extrafields_'.$key.'=1; path='.$_SERVER["PHP_SELF"].'"'."\n";
2675 }
2676 }
2677 $out .= ' jQuery("#trextrafieldseparator'.$key.(!empty($object->id) ? '_'.$object->id : '').'").click(function(){'."\n";
2678 $out .= ' console.log("We click on collapse/uncollapse to hide/show .trextrafields_collapse'.$collapse_group.'");'."\n";
2679 $out .= ' jQuery(".trextrafields_collapse'.$collapse_group.'").toggle(100, function(){'."\n";
2680 $out .= ' if (jQuery(".trextrafields_collapse'.$collapse_group.'").is(":hidden")) {'."\n";
2681 $out .= ' jQuery("#trextrafieldseparator'.$key.(!empty($object->id) ? '_'.$object->id : '').' '.$tagtype_dyn.' span").addClass("fa-plus-square").removeClass("fa-minus-square");'."\n";
2682 $out .= ' document.cookie = "DOLUSER_COLLAPSE_'.$object->table_element.'_extrafields_'.$key.'=0; path='.$_SERVER["PHP_SELF"].'"'."\n";
2683 $out .= ' } else {'."\n";
2684 $out .= ' jQuery("#trextrafieldseparator'.$key.(!empty($object->id) ? '_'.$object->id : '').' '.$tagtype_dyn.' span").addClass("fa-minus-square").removeClass("fa-plus-square");'."\n";
2685 $out .= ' document.cookie = "DOLUSER_COLLAPSE_'.$object->table_element.'_extrafields_'.$key.'=1; path='.$_SERVER["PHP_SELF"].'"'."\n";
2686 $out .= ' }'."\n";
2687 $out .= ' });'."\n";
2688 $out .= ' });'."\n";
2689 $out .= '});'."\n";
2690 $out .= '</script>'."\n";
2691 }
2692 } else {
2693 $this->expand_display[$collapse_group] = 1;
2694 }
2695
2696 return $out;
2697 }
2698
2710 public function setOptionalsFromPost($extralabels, &$object, $onlykey = '', $todefaultifmissing = 0)
2711 {
2712 global $langs;
2713
2714 $nofillrequired = 0; // For error when required field left blank
2715 $error_field_required = array();
2716
2717 if (isset($this->attributes[$object->table_element]['label']) && is_array($this->attributes[$object->table_element]['label'])) {
2718 $extralabels = $this->attributes[$object->table_element]['label'];
2719 }
2720
2721 if (is_array($extralabels)) {
2722 // Get extra fields
2723 foreach ($extralabels as $key => $value) {
2724 if (!empty($onlykey) && $onlykey != '@GETPOSTISSET' && $key != $onlykey) {
2725 continue;
2726 }
2727
2728 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')))) {
2729 //when unticking boolean field, it's not set in POST
2730 continue;
2731 }
2732
2733 $key_type = $this->attributes[$object->table_element]['type'][$key];
2734 if ($key_type == 'separate') {
2735 continue;
2736 }
2737
2738 $enabled = 1;
2739 if (isset($this->attributes[$object->table_element]['enabled'][$key])) { // 'enabled' is often a condition on module enabled or not
2740 $enabled = (int) dol_eval((string) $this->attributes[$object->table_element]['enabled'][$key], 1, 1, '2');
2741 }
2742
2743 $visibility = 1;
2744 if (isset($this->attributes[$object->table_element]['list'][$key])) { // 'list' is option for visibility
2745 $visibility = (int) dol_eval((string) $this->attributes[$object->table_element]['list'][$key], 1, 1, '2');
2746 }
2747
2748 $perms = 1;
2749 if (isset($this->attributes[$object->table_element]['perms'][$key])) {
2750 $perms = (int) dol_eval((string) $this->attributes[$object->table_element]['perms'][$key], 1, 1, '2');
2751 }
2752 if (empty($enabled)
2753 || (
2754 $onlykey === '@GETPOSTISSET'
2755 && in_array($this->attributes[$object->table_element]['type'][$key], array('boolean', 'checkbox', 'chkbxlst'))
2756 && in_array(abs($enabled), array(2, 5))
2757 && ! GETPOSTISSET('options_' . $key) // Update hidden checkboxes and multiselect only if they are provided
2758 )
2759 ) {
2760 continue;
2761 }
2762
2763 $visibility_abs = abs($visibility);
2764 // not modify if extra field is not in update form (0 : never, 2 or -2 : list only, 5 or - 5 : list and view only)
2765 if (empty($visibility_abs) || $visibility_abs == 2 || $visibility_abs == 5) {
2766 continue;
2767 }
2768 if (empty($perms)) {
2769 continue;
2770 }
2771
2772 if ($this->attributes[$object->table_element]['required'][$key]) { // Value is required
2773 // Check if functionally empty without using GETPOST (depending on the type of extrafield, a
2774 // technically non-empty value may be treated as empty functionally).
2775 // value can be alpha, int, array, etc...
2776 $v = $_POST["options_".$key] ?? null;
2777 $type = $this->attributes[$object->table_element]['type'][$key];
2778 if (self::isEmptyValue($v, $type)) {
2779 //print 'ccc'.$value.'-'.$this->attributes[$object->table_element]['required'][$key];
2780
2781 // 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.
2782
2783 $nofillrequired++;
2784 if (!empty($this->attributes[$object->table_element]['langfile'][$key])) {
2785 $langs->load($this->attributes[$object->table_element]['langfile'][$key]);
2786 }
2787 $error_field_required[$key] = $langs->transnoentitiesnoconv($value);
2788 }
2789 }
2790
2791 if (in_array($key_type, array('date'))) {
2792 // Clean parameters
2793 $value_key = dol_mktime(12, 0, 0, GETPOSTINT("options_".$key."month"), GETPOSTINT("options_".$key."day"), GETPOSTINT("options_".$key."year"));
2794 } elseif (in_array($key_type, array('datetime'))) {
2795 // Clean parameters
2796 $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');
2797 } elseif (in_array($key_type, array('datetimegmt'))) {
2798 // Clean parameters
2799 $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');
2800 } elseif (in_array($key_type, array('duration'))) {
2801 $value_hours = GETPOSTINT("options_" . $key . "hour");
2802 $value_minutes = GETPOSTINT("options_" . $key . "min");
2803 $value_key = $value_hours * 3600 + $value_minutes * 60;
2804 } elseif (in_array($key_type, array('checkbox', 'chkbxlst'))) {
2805 $value_arr = GETPOST("options_".$key, 'array'); // check if an array
2806 if (!empty($value_arr)) {
2807 $value_key = implode(',', $value_arr);
2808 } else {
2809 $value_key = '';
2810 }
2811 } elseif (in_array($key_type, array('price', 'double'))) {
2812 $value_arr = GETPOST("options_".$key, 'alpha');
2813 $value_key = price2num($value_arr);
2814 } elseif (in_array($key_type, array('pricecy', 'double'))) {
2815 $value_key = price2num(GETPOST("options_".$key, 'alpha')).':'.GETPOST("options_".$key."currency_id", 'alpha');
2816 } elseif (in_array($key_type, array('html'))) {
2817 $value_key = GETPOST("options_".$key, 'restricthtml');
2818 } elseif (in_array($key_type, ['point', 'multipts', 'linestrg', 'polygon'])) {
2819 // construct point
2820 require_once DOL_DOCUMENT_ROOT.'/core/class/dolgeophp.class.php';
2821 $geojson = GETPOST("options_".$key, 'restricthtml');
2822 if ($geojson != '{}') {
2823 $dolgeophp = new DolGeoPHP($this->db);
2824 $value_key = $dolgeophp->getWkt($geojson);
2825 } else {
2826 $value_key = '';
2827 }
2828 } elseif (in_array($key_type, array('text'))) {
2829 $label_security_check = 'alphanohtml';
2830 // by default 'alphanohtml' (better security); hidden conf MAIN_SECURITY_ALLOW_UNSECURED_LABELS_WITH_HTML allows basic html
2831 if (getDolGlobalString('MAIN_SECURITY_ALLOW_UNSECURED_REF_LABELS')) {
2832 $label_security_check = 'nohtml';
2833 } else {
2834 $label_security_check = !getDolGlobalString('MAIN_SECURITY_ALLOW_UNSECURED_LABELS_WITH_HTML') ? 'alphanohtml' : 'restricthtml';
2835 }
2836 $value_key = GETPOST("options_".$key, $label_security_check);
2837 } else {
2838 $value_key = GETPOST("options_".$key);
2839 if (in_array($key_type, array('link')) && $value_key == '-1') {
2840 $value_key = '';
2841 }
2842 }
2843
2844 if (!empty($error_field_required[$key]) && $todefaultifmissing) {
2845 // Value is required but we have a default value and we asked to set empty value to the default value
2846 if (!empty($this->attributes[$object->table_element]['default']) && !is_null($this->attributes[$object->table_element]['default'][$key])) {
2847 $value_key = $this->attributes[$object->table_element]['default'][$key];
2848 unset($error_field_required[$key]);
2849 $nofillrequired--;
2850 }
2851 }
2852
2853 $object->array_options["options_".$key] = $value_key;
2854 }
2855
2856 if ($nofillrequired) {
2857 $langs->load('errors');
2858 $this->error = $langs->trans('ErrorFieldsRequired').' : '.implode(', ', $error_field_required);
2859 setEventMessages($this->error, null, 'errors');
2860 return -1;
2861 } else {
2862 return 1;
2863 }
2864 } else {
2865 return 0;
2866 }
2867 }
2868
2877 public function getOptionalsFromPost($extrafieldsobjectkey, $keysuffix = '', $keyprefix = '')
2878 {
2879 global $_POST;
2880
2881 if (is_string($extrafieldsobjectkey) && !empty($this->attributes[$extrafieldsobjectkey]['label']) && is_array($this->attributes[$extrafieldsobjectkey]['label'])) {
2882 $extralabels = $this->attributes[$extrafieldsobjectkey]['label'];
2883 } else {
2884 $extralabels = $extrafieldsobjectkey;
2885 }
2886
2887 if (is_array($extralabels)) {
2888 $array_options = array();
2889
2890 // Get extra fields
2891 foreach ($extralabels as $key => $value) {
2892 $key_type = '';
2893 if (is_string($extrafieldsobjectkey)) {
2894 $key_type = $this->attributes[$extrafieldsobjectkey]['type'][$key];
2895 }
2896
2897 if (in_array($key_type, array('date'))) {
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 $value_key = array();
2903 // values provided as a component year, month, day, etc.
2904 if (GETPOST($dateparamname_start . 'year')) {
2905 $value_key['start'] = dol_mktime(0, 0, 0, GETPOSTINT($dateparamname_start . 'month'), GETPOSTINT($dateparamname_start . 'day'), GETPOSTINT($dateparamname_start . 'year'));
2906 }
2907 if (GETPOST($dateparamname_end . 'year')) {
2908 $value_key['end'] = dol_mktime(23, 59, 59, GETPOSTINT($dateparamname_end . 'month'), GETPOSTINT($dateparamname_end . 'day'), GETPOSTINT($dateparamname_end . 'year'));
2909 }
2910 } elseif (GETPOST($keyprefix."options_".$key.$keysuffix."year")) {
2911 // Clean parameters
2912 $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"));
2913 } else {
2914 continue; // Value was not provided, we should not set it.
2915 }
2916 } elseif (in_array($key_type, array('datetime', 'datetimegmt'))) {
2917 $dateparamname_start = $keyprefix . 'options_' . $key . $keysuffix . '_start';
2918 $dateparamname_end = $keyprefix . 'options_' . $key . $keysuffix . '_end';
2919
2920 if (GETPOST($dateparamname_start . 'year') || GETPOST($dateparamname_end . 'year')) {
2921 // values provided as a date pair (start date + end date), each date being broken down as year, month, day, etc.
2922 $dateparamname_start_hour = GETPOSTINT($dateparamname_start . 'hour') != '-1' ? GETPOSTINT($dateparamname_start . 'hour') : '00';
2923 $dateparamname_start_min = GETPOSTINT($dateparamname_start . 'min') != '-1' ? GETPOSTINT($dateparamname_start . 'min') : '00';
2924 $dateparamname_start_sec = GETPOSTINT($dateparamname_start . 'sec') != '-1' ? GETPOSTINT($dateparamname_start . 'sec') : '00';
2925 $dateparamname_end_hour = GETPOSTINT($dateparamname_end . 'hour') != '-1' ? GETPOSTINT($dateparamname_end . 'hour') : '23';
2926 $dateparamname_end_min = GETPOSTINT($dateparamname_end . 'min') != '-1' ? GETPOSTINT($dateparamname_end . 'min') : '59';
2927 $dateparamname_end_sec = GETPOSTINT($dateparamname_end . 'sec') != '-1' ? GETPOSTINT($dateparamname_end . 'sec') : '59';
2928 if ($key_type == 'datetimegmt') {
2929 $value_key = array(
2930 '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'),
2931 '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')
2932 );
2933 } else {
2934 $value_key = array(
2935 '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'),
2936 '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')
2937 );
2938 }
2939 } elseif (GETPOST($keyprefix."options_".$key.$keysuffix."year")) {
2940 // Clean parameters
2941 if ($key_type == 'datetimegmt') {
2942 $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');
2943 } else {
2944 $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');
2945 }
2946 } else {
2947 continue; // Value was not provided, we should not set it.
2948 }
2949 } elseif ($key_type == 'select') {
2950 // to detect if we are in search context
2951 if (GETPOSTISARRAY($keyprefix."options_".$key.$keysuffix)) {
2952 $value_arr = GETPOST($keyprefix."options_".$key.$keysuffix, 'array:aZ09');
2953 // Make sure we get an array even if there's only one selected
2954 $value_arr = (array) $value_arr;
2955 $value_key = implode(',', $value_arr);
2956 } else {
2957 $value_key = GETPOST($keyprefix."options_".$key.$keysuffix);
2958 }
2959 } elseif (in_array($key_type, array('checkbox', 'chkbxlst'))) {
2960 // We test on a hidden field named "..._multiselect" that is always set to 1 if param is in form so
2961 // when nothing is provided we can make a difference between noparam in the form and param was set to nothing.
2962 if (!GETPOSTISSET($keyprefix."options_".$key.$keysuffix.'_multiselect')) {
2963 continue; // Value was not provided, we should not set it.
2964 }
2965 $value_arr = GETPOST($keyprefix."options_".$key.$keysuffix);
2966 // Make sure we get an array even if there's only one checkbox
2967 $value_arr = (array) $value_arr;
2968 $value_key = implode(',', $value_arr);
2969 } elseif (in_array($key_type, array('price', 'double', 'int'))) {
2970 if (!GETPOSTISSET($keyprefix."options_".$key.$keysuffix)) {
2971 continue; // Value was not provided, we should not set it.
2972 }
2973 $value_arr = GETPOST($keyprefix."options_".$key.$keysuffix);
2974 if ($keyprefix != 'search_') { // If value is for a search, we must keep complex string like '>100 <=150'
2975 $value_key = price2num($value_arr);
2976 } else {
2977 $value_key = $value_arr;
2978 }
2979 } elseif (in_array($key_type, array('boolean'))) {
2980 // We test on a hidden field named "..._boolean" that is always set to 1 if param is in form so
2981 // when nothing is provided we can make a difference between noparam in the form and param was set to nothing.
2982 if (!GETPOSTISSET($keyprefix."options_".$key.$keysuffix."_boolean")) {
2983 $value_key = '';
2984 } else {
2985 $value_arr = GETPOST($keyprefix."options_".$key.$keysuffix);
2986 $value_key = $value_arr;
2987 }
2988 } elseif (in_array($key_type, array('html'))) {
2989 if (!GETPOSTISSET($keyprefix."options_".$key.$keysuffix)) {
2990 continue; // Value was not provided, we should not set it.
2991 }
2992 $value_key = dol_htmlcleanlastbr(GETPOST($keyprefix."options_".$key.$keysuffix, 'restricthtml'));
2993 } else {
2994 if (!GETPOSTISSET($keyprefix."options_".$key.$keysuffix)) {
2995 continue; // Value was not provided, we should not set it.
2996 }
2997
2998 $value_key = GETPOST($keyprefix."options_".$key.$keysuffix);
2999 if ($value_key === '') {
3000 $value_key = null;
3001 }
3002 }
3003
3004 $array_options[$keyprefix."options_".$key] = $value_key; // No keyprefix here. keyprefix is used only for read.
3005 }
3006
3007 return $array_options;
3008 }
3009
3010 return 0;
3011 }
3012
3018 public static function getListOfTypesLabels()
3019 {
3020 global $langs;
3021
3022 $arraytype2label = array('');
3023
3024 $tmptype2label = ExtraFields::$type2label;
3025 foreach ($tmptype2label as $key => $val) {
3026 $arraytype2label[$key] = $langs->transnoentitiesnoconv($val);
3027 }
3028
3029 if (!getDolGlobalString('MAIN_USE_EXTRAFIELDS_ICON')) {
3030 unset($arraytype2label['icon']);
3031 }
3032 if (!getDolGlobalString('MAIN_USE_GEOPHP')) {
3033 unset($arraytype2label['point']);
3034 unset($arraytype2label['multipts']);
3035 unset($arraytype2label['linestrg']);
3036 unset($arraytype2label['polygon']);
3037 }
3038
3039 return $arraytype2label;
3040 }
3041
3049 public static function isEmptyValue($v, string $type)
3050 {
3051 if ($v === null || $v === '') {
3052 return true;
3053 }
3054 if (is_array($v) || $type == 'select') {
3055 return empty($v);
3056 }
3057 if ($type == 'link') {
3058 return ($v == '-1');
3059 }
3060 if ($type == 'sellist') {
3061 return ($v == '0');
3062 }
3063 return empty($v); // Note empty('0') is also true, tested 7.0 up to 8.3.12
3064 }
3065}
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