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