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