dolibarr  18.0.0
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 Charles-Fr BENKE <charles.fr@benke.fr>
10  * Copyright (C) 2016 Raphaël Doursenaud <rdoursenaud@gpcsolutions.fr>
11  * Copyright (C) 2017 Nicolas ZABOURI <info@inovea-conseil.com>
12  * Copyright (C) 2018-2022 Frédéric France <frederic.france@netlogic.fr>
13  * Copyright (C) 2022 Antonin MARCHAL <antonin@letempledujeu.fr>
14  *
15  * This program is free software; you can redistribute it and/or modify
16  * it under the terms of the GNU General Public License as published by
17  * the Free Software Foundation; either version 3 of the License, or
18  * (at your option) any later version.
19  *
20  * This program is distributed in the hope that it will be useful,
21  * but WITHOUT ANY WARRANTY; without even the implied warranty of
22  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23  * GNU General Public License for more details.
24  *
25  * You should have received a copy of the GNU General Public License
26  * along with this program. If not, see <https://www.gnu.org/licenses/>.
27  */
28 
40 {
44  public $db;
45 
49  public $attributes;
50 
54  public $expand_display;
55 
59  public $error = '';
60 
64  public $errors = array();
65 
69  public $errno;
70 
74  public static $type2label = array(
75  'varchar'=>'String1Line',
76  'text'=>'TextLongNLines',
77  'html'=>'HtmlText',
78  'int'=>'Int',
79  'double'=>'Float',
80  'date'=>'Date',
81  'datetime'=>'DateAndTime',
82  //'datetimegmt'=>'DateAndTimeUTC',
83  'boolean'=>'Boolean',
84  'price'=>'ExtrafieldPrice',
85  'pricecy'=>'ExtrafieldPriceWithCurrency',
86  'phone'=>'ExtrafieldPhone',
87  'mail'=>'ExtrafieldMail',
88  'url'=>'ExtrafieldUrl',
89  'ip'=>'ExtrafieldIP',
90  'password' => 'ExtrafieldPassword',
91  'select' => 'ExtrafieldSelect',
92  'sellist' => 'ExtrafieldSelectList',
93  'radio' => 'ExtrafieldRadio',
94  'checkbox' => 'ExtrafieldCheckBox',
95  'chkbxlst' => 'ExtrafieldCheckBoxFromList',
96  'link' => 'ExtrafieldLink',
97  'separate' => 'ExtrafieldSeparator',
98  );
99 
100 
106  public function __construct($db)
107  {
108  $this->db = $db;
109  $this->error = '';
110  $this->errors = array();
111  $this->attributes = array();
112  }
113 
140  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())
141  {
142  if (empty($attrname)) {
143  return -1;
144  }
145  if (empty($label)) {
146  return -1;
147  }
148 
149  $result = 0;
150 
151  if ($type == 'separate') {
152  $unique = 0;
153  $required = 0;
154  } // Force unique and not required if this is a separator field to avoid troubles.
155  if ($elementtype == 'thirdparty') {
156  $elementtype = 'societe';
157  }
158  if ($elementtype == 'contact') {
159  $elementtype = 'socpeople';
160  }
161 
162  // Create field into database except for separator type which is not stored in database
163  if ($type != 'separate') {
164  $result = $this->create($attrname, $type, $size, $elementtype, $unique, $required, $default_value, $param, $perms, $list, $computed, $help, $moreparams);
165  }
166  $err1 = $this->errno;
167  if ($result > 0 || $err1 == 'DB_ERROR_COLUMN_ALREADY_EXISTS' || $type == 'separate') {
168  // Add declaration of field into table
169  $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);
170  $err2 = $this->errno;
171  if ($result2 > 0 || ($err1 == 'DB_ERROR_COLUMN_ALREADY_EXISTS' && $err2 == 'DB_ERROR_RECORD_ALREADY_EXISTS')) {
172  $this->error = '';
173  $this->errno = 0;
174  return 1;
175  } else {
176  return -2;
177  }
178  } else {
179  return -1;
180  }
181  }
182 
202  private function create($attrname, $type = 'varchar', $length = 255, $elementtype = 'member', $unique = 0, $required = 0, $default_value = '', $param = '', $perms = '', $list = '0', $computed = '', $help = '', $moreparams = array())
203  {
204  if ($elementtype == 'thirdparty') {
205  $elementtype = 'societe';
206  }
207  if ($elementtype == 'contact') {
208  $elementtype = 'socpeople';
209  }
210 
211  $table = $elementtype.'_extrafields';
212  if ($elementtype == 'categorie') {
213  $table = 'categories_extrafields';
214  }
215 
216  if (!empty($attrname) && preg_match("/^\w[a-zA-Z0-9_]*$/", $attrname) && !is_numeric($attrname)) {
217  if ($type == 'boolean') {
218  $typedb = 'int';
219  $lengthdb = '1';
220  } elseif ($type == 'price') {
221  $typedb = 'double';
222  $lengthdb = '24,8';
223  } elseif ($type == 'pricecy') {
224  $typedb = 'varchar';
225  $lengthdb = '64';
226  } elseif ($type == 'phone') {
227  $typedb = 'varchar';
228  $lengthdb = '20';
229  } elseif ($type == 'mail' || $type == 'ip') {
230  $typedb = 'varchar';
231  $lengthdb = '128';
232  } elseif ($type == 'url') {
233  $typedb = 'varchar';
234  $lengthdb = '255';
235  } elseif (($type == 'select') || ($type == 'sellist') || ($type == 'radio') || ($type == 'checkbox') || ($type == 'chkbxlst')) {
236  $typedb = 'varchar';
237  $lengthdb = '255';
238  } elseif ($type == 'link') {
239  $typedb = 'int';
240  $lengthdb = '11';
241  } elseif ($type == 'html') {
242  $typedb = 'text';
243  $lengthdb = $length;
244  } elseif ($type == 'password') {
245  $typedb = 'varchar';
246  $lengthdb = '128';
247  } else {
248  $typedb = $type;
249  $lengthdb = $length;
250  if ($type == 'varchar' && empty($lengthdb)) {
251  $lengthdb = '255';
252  }
253  }
254  $field_desc = array(
255  'type'=>$typedb,
256  'value'=>$lengthdb,
257  'null'=>($required ? 'NOT NULL' : 'NULL'),
258  'default' => $default_value
259  );
260 
261  $result = $this->db->DDLAddField($this->db->prefix().$table, $attrname, $field_desc);
262  if ($result > 0) {
263  if ($unique) {
264  $sql = "ALTER TABLE ".$this->db->prefix().$table." ADD UNIQUE INDEX uk_".$table."_".$attrname." (".$attrname.")";
265  $resql = $this->db->query($sql, 1, 'dml');
266  }
267  return 1;
268  } else {
269  $this->error = $this->db->lasterror();
270  $this->errno = $this->db->lasterrno();
271  return -1;
272  }
273  } else {
274  return 0;
275  }
276  }
277 
278  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
306  private function create_label($attrname, $label = '', $type = '', $pos = 0, $size = 0, $elementtype = 'member', $unique = 0, $required = 0, $param = '', $alwayseditable = 0, $perms = '', $list = '-1', $help = '', $default = '', $computed = '', $entity = '', $langfile = '', $enabled = '1', $totalizable = 0, $printable = 0, $moreparams = array())
307  {
308  // phpcs:enable
309  global $conf, $user;
310 
311  if ($elementtype == 'thirdparty') {
312  $elementtype = 'societe';
313  }
314  if ($elementtype == 'contact') {
315  $elementtype = 'socpeople';
316  }
317 
318  // Clean parameters
319  if (empty($pos)) {
320  $pos = 0;
321  }
322  if (empty($list)) {
323  $list = '0';
324  }
325  if (empty($required)) {
326  $required = 0;
327  }
328  if (empty($unique)) {
329  $unique = 0;
330  }
331  if (empty($printable)) {
332  $printable = 0;
333  }
334  if (empty($alwayseditable)) {
335  $alwayseditable = 0;
336  }
337  if (empty($totalizable)) {
338  $totalizable = 0;
339  }
340 
341  $css = '';
342  if (!empty($moreparams) && !empty($moreparams['css'])) {
343  $css = $moreparams['css'];
344  }
345  $csslist = '';
346  if (!empty($moreparams) && !empty($moreparams['csslist'])) {
347  $csslist = $moreparams['csslist'];
348  }
349  $cssview = '';
350  if (!empty($moreparams) && !empty($moreparams['cssview'])) {
351  $cssview = $moreparams['cssview'];
352  }
353 
354  if (!empty($attrname) && preg_match("/^\w[a-zA-Z0-9-_]*$/", $attrname) && !is_numeric($attrname)) {
355  if (is_array($param) && count($param) > 0) {
356  $params = serialize($param);
357  } elseif (strlen($param) > 0) {
358  $params = trim($param);
359  } else {
360  $params = '';
361  }
362 
363  $sql = "INSERT INTO ".$this->db->prefix()."extrafields(";
364  $sql .= " name,";
365  $sql .= " label,";
366  $sql .= " type,";
367  $sql .= " pos,";
368  $sql .= " size,";
369  $sql .= " entity,";
370  $sql .= " elementtype,";
371  $sql .= " fieldunique,";
372  $sql .= " fieldrequired,";
373  $sql .= " param,";
374  $sql .= " alwayseditable,";
375  $sql .= " perms,";
376  $sql .= " langs,";
377  $sql .= " list,";
378  $sql .= " printable,";
379  $sql .= " fielddefault,";
380  $sql .= " fieldcomputed,";
381  $sql .= " fk_user_author,";
382  $sql .= " fk_user_modif,";
383  $sql .= " datec,";
384  $sql .= " enabled,";
385  $sql .= " help,";
386  $sql .= " totalizable,";
387  $sql .= " css,";
388  $sql .= " csslist,";
389  $sql .= " cssview";
390  $sql .= " )";
391  $sql .= " VALUES('".$this->db->escape($attrname)."',";
392  $sql .= " '".$this->db->escape($label)."',";
393  $sql .= " '".$this->db->escape($type)."',";
394  $sql .= " ".((int) $pos).",";
395  $sql .= " '".$this->db->escape($size)."',";
396  $sql .= " ".($entity === '' ? $conf->entity : $entity).",";
397  $sql .= " '".$this->db->escape($elementtype)."',";
398  $sql .= " ".((int) $unique).",";
399  $sql .= " ".((int) $required).",";
400  $sql .= " '".$this->db->escape($params)."',";
401  $sql .= " ".((int) $alwayseditable).",";
402  $sql .= " ".($perms ? "'".$this->db->escape($perms)."'" : "null").",";
403  $sql .= " ".($langfile ? "'".$this->db->escape($langfile)."'" : "null").",";
404  $sql .= " '".$this->db->escape($list)."',";
405  $sql .= " '".$this->db->escape($printable)."',";
406  $sql .= " ".($default ? "'".$this->db->escape($default)."'" : "null").",";
407  $sql .= " ".($computed ? "'".$this->db->escape($computed)."'" : "null").",";
408  $sql .= " ".(is_object($user) ? $user->id : 0).",";
409  $sql .= " ".(is_object($user) ? $user->id : 0).",";
410  $sql .= "'".$this->db->idate(dol_now())."',";
411  $sql .= " ".($enabled ? "'".$this->db->escape($enabled)."'" : "1").",";
412  $sql .= " ".($help ? "'".$this->db->escape($help)."'" : "null").",";
413  $sql .= " ".($totalizable ? 'TRUE' : 'FALSE').",";
414  $sql .= " ".($css ? "'".$this->db->escape($css)."'" : "null").",";
415  $sql .= " ".($csslist ? "'".$this->db->escape($csslist)."'" : "null").",";
416  $sql .= " ".($cssview ? "'".$this->db->escape($cssview)."'" : "null");
417  $sql .= ')';
418 
419  dol_syslog(get_class($this)."::create_label", LOG_DEBUG);
420  if ($this->db->query($sql)) {
421  return 1;
422  } else {
423  $this->error = $this->db->lasterror();
424  $this->errno = $this->db->lasterrno();
425  return -1;
426  }
427  }
428  return -1;
429  }
430 
438  public function delete($attrname, $elementtype = 'member')
439  {
440  if ($elementtype == 'thirdparty') {
441  $elementtype = 'societe';
442  }
443  if ($elementtype == 'contact') {
444  $elementtype = 'socpeople';
445  }
446 
447  $table = $elementtype.'_extrafields';
448  if ($elementtype == 'categorie') {
449  $table = 'categories_extrafields';
450  }
451 
452  $error = 0;
453 
454  if (!empty($attrname) && preg_match("/^\w[a-zA-Z0-9-_]*$/", $attrname)) {
455  $result = $this->delete_label($attrname, $elementtype);
456  if ($result < 0) {
457  $this->error = $this->db->lasterror();
458  $this->errors[] = $this->db->lasterror();
459  $error++;
460  }
461 
462  if (!$error) {
463  $sql = "SELECT COUNT(rowid) as nb";
464  $sql .= " FROM ".$this->db->prefix()."extrafields";
465  $sql .= " WHERE elementtype = '".$this->db->escape($elementtype)."'";
466  $sql .= " AND name = '".$this->db->escape($attrname)."'";
467  //$sql.= " AND entity IN (0,".$conf->entity.")"; Do not test on entity here. We want to see if there is still on field remaning in other entities before deleting field in table
468  $resql = $this->db->query($sql);
469  if ($resql) {
470  $obj = $this->db->fetch_object($resql);
471  if ($obj->nb <= 0) {
472  $result = $this->db->DDLDropField($this->db->prefix().$table, $attrname); // This also drop the unique key
473  if ($result < 0) {
474  $this->error = $this->db->lasterror();
475  $this->errors[] = $this->db->lasterror();
476  $error++;
477  }
478  }
479  }
480  }
481 
482  return $result;
483  } else {
484  return 0;
485  }
486  }
487 
488  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
496  private function delete_label($attrname, $elementtype = 'member')
497  {
498  // phpcs:enable
499  global $conf;
500 
501  if ($elementtype == 'thirdparty') {
502  $elementtype = 'societe';
503  }
504  if ($elementtype == 'contact') {
505  $elementtype = 'socpeople';
506  }
507 
508  if (isset($attrname) && $attrname != '' && preg_match("/^\w[a-zA-Z0-9-_]*$/", $attrname)) {
509  $sql = "DELETE FROM ".$this->db->prefix()."extrafields";
510  $sql .= " WHERE name = '".$this->db->escape($attrname)."'";
511  $sql .= " AND entity IN (0,".$conf->entity.')';
512  $sql .= " AND elementtype = '".$this->db->escape($elementtype)."'";
513 
514  dol_syslog(get_class($this)."::delete_label", LOG_DEBUG);
515  $resql = $this->db->query($sql);
516  if ($resql) {
517  return 1;
518  } else {
519  dol_print_error($this->db);
520  return -1;
521  }
522  } else {
523  return 0;
524  }
525  }
526 
554  public function update($attrname, $label, $type, $length, $elementtype, $unique = 0, $required = 0, $pos = 0, $param = '', $alwayseditable = 0, $perms = '', $list = '', $help = '', $default = '', $computed = '', $entity = '', $langfile = '', $enabled = '1', $totalizable = 0, $printable = 0, $moreparams = array())
555  {
556  global $hookmanager;
557 
558  if ($elementtype == 'thirdparty') {
559  $elementtype = 'societe';
560  }
561  if ($elementtype == 'contact') {
562  $elementtype = 'socpeople';
563  }
564 
565  $table = $elementtype.'_extrafields';
566  if ($elementtype == 'categorie') {
567  $table = 'categories_extrafields';
568  }
569 
570  if (isset($attrname) && $attrname != '' && preg_match("/^\w[a-zA-Z0-9-_]*$/", $attrname)) {
571  if ($type == 'boolean') {
572  $typedb = 'int';
573  $lengthdb = '1';
574  } elseif ($type == 'price') {
575  $typedb = 'double';
576  $lengthdb = '24,8';
577  } elseif ($type == 'pricecy') {
578  $typedb = 'varchar';
579  $lengthdb = '64';
580  } elseif ($type == 'phone') {
581  $typedb = 'varchar';
582  $lengthdb = '20';
583  } elseif ($type == 'mail' || $type == 'ip') {
584  $typedb = 'varchar';
585  $lengthdb = '128';
586  } elseif ($type == 'url') {
587  $typedb = 'varchar';
588  $lengthdb = '255';
589  } elseif (($type == 'select') || ($type == 'sellist') || ($type == 'radio') || ($type == 'checkbox') || ($type == 'chkbxlst')) {
590  $typedb = 'varchar';
591  $lengthdb = '255';
592  } elseif ($type == 'html') {
593  $typedb = 'text';
594  } elseif ($type == 'link') {
595  $typedb = 'int';
596  $lengthdb = '11';
597  } elseif ($type == 'password') {
598  $typedb = 'varchar';
599  $lengthdb = '50';
600  } else {
601  $typedb = $type;
602  $lengthdb = $length;
603  }
604  $field_desc = array('type'=>$typedb, 'value'=>$lengthdb, 'null'=>($required ? 'NOT NULL' : 'NULL'), 'default'=>$default);
605 
606  if (is_object($hookmanager)) {
607  $hookmanager->initHooks(array('extrafieldsdao'));
608  $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);
609  $reshook = $hookmanager->executeHooks('updateExtrafields', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
610 
611  if ($reshook < 0) {
612  $this->error = $this->db->lasterror();
613  return -1;
614  }
615  }
616 
617  if ($type != 'separate') { // No table update when separate type
618  $result = $this->db->DDLUpdateField($this->db->prefix().$table, $attrname, $field_desc);
619  }
620  if ($result > 0 || $type == 'separate') {
621  if ($label) {
622  $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);
623  }
624  if ($result > 0) {
625  $sql = '';
626  if ($unique) {
627  $sql = "ALTER TABLE ".$this->db->prefix().$table." ADD UNIQUE INDEX uk_".$table."_".$attrname." (".$attrname.")";
628  } else {
629  $sql = "ALTER TABLE ".$this->db->prefix().$table." DROP INDEX IF EXISTS uk_".$table."_".$attrname;
630  }
631  dol_syslog(get_class($this).'::update', LOG_DEBUG);
632  $resql = $this->db->query($sql, 1, 'dml');
633  /*if ($resql < 0) {
634  $this->error = $this->db->lasterror();
635  return -1;
636  }*/
637  return 1;
638  } else {
639  $this->error = $this->db->lasterror();
640  return -1;
641  }
642  } else {
643  $this->error = $this->db->lasterror();
644  return -1;
645  }
646  } else {
647  return 0;
648  }
649  }
650 
651  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
679  private function update_label($attrname, $label, $type, $size, $elementtype, $unique = 0, $required = 0, $pos = 0, $param = '', $alwayseditable = 0, $perms = '', $list = '0', $help = '', $default = '', $computed = '', $entity = '', $langfile = '', $enabled = '1', $totalizable = 0, $printable = 0, $moreparams = array())
680  {
681  // phpcs:enable
682  global $conf, $user;
683  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);
684 
685  // Clean parameters
686  if ($elementtype == 'thirdparty') {
687  $elementtype = 'societe';
688  }
689  if ($elementtype == 'contact') {
690  $elementtype = 'socpeople';
691  }
692 
693  if (empty($pos)) {
694  $pos = 0;
695  }
696  if (empty($list)) {
697  $list = '0';
698  }
699  if (empty($totalizable)) {
700  $totalizable = 0;
701  }
702  if (empty($required)) {
703  $required = 0;
704  }
705  if (empty($unique)) {
706  $unique = 0;
707  }
708  if (empty($alwayseditable)) {
709  $alwayseditable = 0;
710  }
711 
712  $css = '';
713  if (!empty($moreparams) && !empty($moreparams['css'])) {
714  $css = $moreparams['css'];
715  }
716  $csslist = '';
717  if (!empty($moreparams) && !empty($moreparams['csslist'])) {
718  $csslist = $moreparams['csslist'];
719  }
720  $cssview = '';
721  if (!empty($moreparams) && !empty($moreparams['cssview'])) {
722  $cssview = $moreparams['cssview'];
723  }
724 
725  if (isset($attrname) && $attrname != '' && preg_match("/^\w[a-zA-Z0-9-_]*$/", $attrname)) {
726  $this->db->begin();
727 
728  if (is_array($param) && count($param) > 0) {
729  $params = serialize($param);
730  } elseif (is_array($param)) {
731  $params = '';
732  } elseif (strlen($param) > 0) {
733  $params = trim($param);
734  } else {
735  $params = '';
736  }
737 
738  if ($entity === '' || $entity != '0') {
739  // We dont want on all entities, we delete all and current
740  $sql_del = "DELETE FROM ".$this->db->prefix()."extrafields";
741  $sql_del .= " WHERE name = '".$this->db->escape($attrname)."'";
742  $sql_del .= " AND entity IN (0, ".($entity === '' ? $conf->entity : $entity).")";
743  $sql_del .= " AND elementtype = '".$this->db->escape($elementtype)."'";
744  } else {
745  // We want on all entities ($entities = '0'), we delete on all only (we keep setup specific to each entity)
746  $sql_del = "DELETE FROM ".$this->db->prefix()."extrafields";
747  $sql_del .= " WHERE name = '".$this->db->escape($attrname)."'";
748  $sql_del .= " AND entity = 0";
749  $sql_del .= " AND elementtype = '".$this->db->escape($elementtype)."'";
750  }
751  $resql1 = $this->db->query($sql_del);
752 
753  $sql = "INSERT INTO ".$this->db->prefix()."extrafields(";
754  $sql .= " name,"; // This is code
755  $sql .= " entity,";
756  $sql .= " label,";
757  $sql .= " type,";
758  $sql .= " size,";
759  $sql .= " elementtype,";
760  $sql .= " fieldunique,";
761  $sql .= " fieldrequired,";
762  $sql .= " perms,";
763  $sql .= " langs,";
764  $sql .= " pos,";
765  $sql .= " alwayseditable,";
766  $sql .= " param,";
767  $sql .= " list,";
768  $sql .= " printable,";
769  $sql .= " totalizable,";
770  $sql .= " fielddefault,";
771  $sql .= " fieldcomputed,";
772  $sql .= " fk_user_author,";
773  $sql .= " fk_user_modif,";
774  $sql .= " datec,";
775  $sql .= " enabled,";
776  $sql .= " help,";
777  $sql .= " css,";
778  $sql .= " csslist,";
779  $sql .= " cssview";
780  $sql .= ") VALUES (";
781  $sql .= "'".$this->db->escape($attrname)."',";
782  $sql .= " ".($entity === '' ? $conf->entity : $entity).",";
783  $sql .= " '".$this->db->escape($label)."',";
784  $sql .= " '".$this->db->escape($type)."',";
785  $sql .= " '".$this->db->escape($size)."',";
786  $sql .= " '".$this->db->escape($elementtype)."',";
787  $sql .= " ".$unique.",";
788  $sql .= " ".$required.",";
789  $sql .= " ".($perms ? "'".$this->db->escape($perms)."'" : "null").",";
790  $sql .= " ".($langfile ? "'".$this->db->escape($langfile)."'" : "null").",";
791  $sql .= " ".$pos.",";
792  $sql .= " '".$this->db->escape($alwayseditable)."',";
793  $sql .= " '".$this->db->escape($params)."',";
794  $sql .= " '".$this->db->escape($list)."', ";
795  $sql .= " '".$this->db->escape($printable)."', ";
796  $sql .= " ".($totalizable ? 'TRUE' : 'FALSE').",";
797  $sql .= " ".(($default != '') ? "'".$this->db->escape($default)."'" : "null").",";
798  $sql .= " ".($computed ? "'".$this->db->escape($computed)."'" : "null").",";
799  $sql .= " ".$user->id.",";
800  $sql .= " ".$user->id.",";
801  $sql .= "'".$this->db->idate(dol_now())."',";
802  $sql .= "'".$this->db->escape($enabled)."',";
803  $sql .= " ".($help ? "'".$this->db->escape($help)."'" : "null").",";
804  $sql .= " ".($css ? "'".$this->db->escape($css)."'" : "null").",";
805  $sql .= " ".($csslist ? "'".$this->db->escape($csslist)."'" : "null").",";
806  $sql .= " ".($cssview ? "'".$this->db->escape($cssview)."'" : "null");
807  $sql .= ")";
808 
809  $resql2 = $this->db->query($sql);
810 
811  if ($resql1 && $resql2) {
812  $this->db->commit();
813  return 1;
814  } else {
815  $this->db->rollback();
816  dol_print_error($this->db);
817  return -1;
818  }
819  } else {
820  return 0;
821  }
822  }
823 
824 
825  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
833  public function fetch_name_optionals_label($elementtype, $forceload = false)
834  {
835  // phpcs:enable
836  global $conf;
837 
838  if (empty($elementtype)) {
839  return array();
840  }
841 
842  if ($elementtype == 'thirdparty') {
843  $elementtype = 'societe';
844  }
845  if ($elementtype == 'contact') {
846  $elementtype = 'socpeople';
847  }
848  if ($elementtype == 'order_supplier') {
849  $elementtype = 'commande_fournisseur';
850  }
851 
852  // Test cache $this->attributes[$elementtype]['loaded'] to see if we must do something
853  // TODO
854 
855  $array_name_label = array();
856 
857  // 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
858  $sql = "SELECT rowid, name, label, type, size, elementtype, fieldunique, fieldrequired, param, pos, alwayseditable, perms, langs, list, printable, totalizable, fielddefault, fieldcomputed, entity, enabled, help,";
859  $sql .= " css, cssview, csslist";
860  $sql .= " FROM ".$this->db->prefix()."extrafields";
861  //$sql.= " WHERE entity IN (0,".$conf->entity.")"; // Filter is done later
862  if ($elementtype && $elementtype != 'all') {
863  $sql .= " WHERE elementtype = '".$this->db->escape($elementtype)."'"; // Filed with object->table_element
864  }
865  $sql .= " ORDER BY pos";
866 
867  $resql = $this->db->query($sql);
868  if ($resql) {
869  $count = 0;
870  if ($this->db->num_rows($resql)) {
871  while ($tab = $this->db->fetch_object($resql)) {
872  if ($tab->entity != 0 && $tab->entity != $conf->entity) {
873  // 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
874  if ($tab->fieldrequired && is_null($tab->fielddefault)) {
875  $this->attributes[$tab->elementtype]['mandatoryfieldsofotherentities'][$tab->name] = $tab->type;
876  }
877  continue;
878  }
879 
880  // We can add this attribute to object. TODO Remove this and return $this->attributes[$elementtype]['label']
881  if ($tab->type != 'separate') {
882  $array_name_label[$tab->name] = $tab->label;
883  }
884 
885  $this->attributes[$tab->elementtype]['type'][$tab->name] = $tab->type;
886  $this->attributes[$tab->elementtype]['label'][$tab->name] = $tab->label;
887  $this->attributes[$tab->elementtype]['size'][$tab->name] = $tab->size;
888  $this->attributes[$tab->elementtype]['elementtype'][$tab->name] = $tab->elementtype;
889  $this->attributes[$tab->elementtype]['default'][$tab->name] = $tab->fielddefault;
890  $this->attributes[$tab->elementtype]['computed'][$tab->name] = $tab->fieldcomputed;
891  $this->attributes[$tab->elementtype]['unique'][$tab->name] = $tab->fieldunique;
892  $this->attributes[$tab->elementtype]['required'][$tab->name] = $tab->fieldrequired;
893  $this->attributes[$tab->elementtype]['param'][$tab->name] = ($tab->param ? jsonOrUnserialize($tab->param) : '');
894  $this->attributes[$tab->elementtype]['pos'][$tab->name] = $tab->pos;
895  $this->attributes[$tab->elementtype]['alwayseditable'][$tab->name] = $tab->alwayseditable;
896  $this->attributes[$tab->elementtype]['perms'][$tab->name] = ((is_null($tab->perms) || strlen($tab->perms) == 0) ? 1 : $tab->perms);
897  $this->attributes[$tab->elementtype]['langfile'][$tab->name] = $tab->langs;
898  $this->attributes[$tab->elementtype]['list'][$tab->name] = $tab->list;
899  $this->attributes[$tab->elementtype]['printable'][$tab->name] = $tab->printable;
900  $this->attributes[$tab->elementtype]['totalizable'][$tab->name] = ($tab->totalizable ? 1 : 0);
901  $this->attributes[$tab->elementtype]['entityid'][$tab->name] = $tab->entity;
902  $this->attributes[$tab->elementtype]['enabled'][$tab->name] = $tab->enabled;
903  $this->attributes[$tab->elementtype]['help'][$tab->name] = $tab->help;
904  $this->attributes[$tab->elementtype]['css'][$tab->name] = $tab->css;
905  $this->attributes[$tab->elementtype]['cssview'][$tab->name] = $tab->cssview;
906  $this->attributes[$tab->elementtype]['csslist'][$tab->name] = $tab->csslist;
907 
908  $this->attributes[$tab->elementtype]['loaded'] = 1;
909  $count++;
910  }
911  }
912  if ($elementtype) {
913  $this->attributes[$elementtype]['loaded'] = 1; // Note: If nothing is found, we also set the key 'loaded' to 1.
914  $this->attributes[$elementtype]['count'] = $count;
915  }
916  } else {
917  $this->error = $this->db->lasterror();
918  dol_syslog(get_class($this)."::fetch_name_optionals_label ".$this->error, LOG_ERR);
919  }
920 
921  return $array_name_label;
922  }
923 
924 
940  public function showInputField($key, $value, $moreparam = '', $keysuffix = '', $keyprefix = '', $morecss = '', $objectid = 0, $extrafieldsobjectkey = '', $mode = 0)
941  {
942  global $conf, $langs, $form;
943 
944  if (!is_object($form)) {
945  require_once DOL_DOCUMENT_ROOT.'/core/class/html.form.class.php';
946  $form = new Form($this->db);
947  }
948 
949  $out = '';
950 
951  if (!preg_match('/options_$/', $keyprefix)) { // Because we work on extrafields, we add 'options_' to prefix if not already added
952  $keyprefix = $keyprefix.'options_';
953  }
954 
955  if (empty($extrafieldsobjectkey)) {
956  dol_syslog(get_class($this).'::showInputField extrafieldsobjectkey required', LOG_ERR);
957  return 'BadValueForParamExtraFieldsObjectKey';
958  }
959 
960  $label = $this->attributes[$extrafieldsobjectkey]['label'][$key];
961  $type = $this->attributes[$extrafieldsobjectkey]['type'][$key];
962  $size = $this->attributes[$extrafieldsobjectkey]['size'][$key];
963  $default = $this->attributes[$extrafieldsobjectkey]['default'][$key];
964  $computed = $this->attributes[$extrafieldsobjectkey]['computed'][$key];
965  $unique = $this->attributes[$extrafieldsobjectkey]['unique'][$key];
966  $required = $this->attributes[$extrafieldsobjectkey]['required'][$key];
967  $param = $this->attributes[$extrafieldsobjectkey]['param'][$key];
968  $perms = dol_eval($this->attributes[$extrafieldsobjectkey]['perms'][$key], 1, 1, '2');
969  $langfile = $this->attributes[$extrafieldsobjectkey]['langfile'][$key];
970  $list = dol_eval($this->attributes[$extrafieldsobjectkey]['list'][$key], 1, 1, '2');
971  $totalizable = $this->attributes[$extrafieldsobjectkey]['totalizable'][$key];
972  $help = $this->attributes[$extrafieldsobjectkey]['help'][$key];
973  $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)
974 
975  if ($computed) {
976  if (!preg_match('/^search_/', $keyprefix)) {
977  return '<span class="opacitymedium">'.$langs->trans("AutomaticallyCalculated").'</span>';
978  } else {
979  return '';
980  }
981  }
982 
983  //
984  // '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'
985  if (empty($morecss)) {
986  // Add automatic css
987  if ($type == 'date') {
988  $morecss = 'minwidth100imp';
989  } elseif ($type == 'datetime' || $type == 'datetimegmt' || $type == 'link') {
990  $morecss = 'minwidth200imp';
991  } elseif (in_array($type, array('int', 'integer', 'double', 'price'))) {
992  $morecss = 'maxwidth75';
993  } elseif ($type == 'password') {
994  $morecss = 'maxwidth100';
995  } elseif ($type == 'url') {
996  $morecss = 'minwidth400';
997  } elseif ($type == 'boolean') {
998  $morecss = '';
999  } elseif ($type == 'radio') {
1000  $morecss = 'width25';
1001  } else {
1002  if (empty($size) || round($size) < 12) {
1003  $morecss = 'minwidth100';
1004  } elseif (round($size) <= 48) {
1005  $morecss = 'minwidth200';
1006  } else {
1007  $morecss = 'minwidth400';
1008  }
1009  }
1010  // If css forced in attribute, we use this one
1011  if (!empty($this->attributes[$extrafieldsobjectkey]['css'][$key])) {
1012  $morecss = $this->attributes[$extrafieldsobjectkey]['css'][$key];
1013  }
1014  }
1015 
1016  if (in_array($type, array('date'))) {
1017  $tmp = explode(',', $size);
1018  $newsize = $tmp[0];
1019  $showtime = 0;
1020 
1021  // Do not show current date when field not required (see selectDate() method)
1022  if (!$required && $value == '') {
1023  $value = '-1';
1024  }
1025 
1026  if ($mode == 1) {
1027  // search filter on a date extrafield shows two inputs to select a date range
1028  $prefill = array(
1029  'start' => isset($value['start']) ? $value['start'] : '',
1030  'end' => isset($value['end']) ? $value['end'] : ''
1031  );
1032  $out = '<div ' . ($moreparam ? $moreparam : '') . '><div class="nowrap">';
1033  $out .= $form->selectDate($prefill['start'], $keyprefix.$key.$keysuffix.'_start', 0, 0, 1, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans("From"));
1034  $out .= '</div><div class="nowrap">';
1035  $out .= $form->selectDate($prefill['end'], $keyprefix.$key.$keysuffix.'_end', 0, 0, 1, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans("to"));
1036  $out .= '</div></div>';
1037  } else {
1038  // TODO Must also support $moreparam
1039  $out = $form->selectDate($value, $keyprefix.$key.$keysuffix, $showtime, $showtime, $required, '', 1, (($keyprefix != 'search_' && $keyprefix != 'search_options_') ? 1 : 0), 0, 1);
1040  }
1041  } elseif (in_array($type, array('datetime', 'datetimegmt'))) {
1042  $tmp = explode(',', $size);
1043  $newsize = $tmp[0];
1044  $showtime = 1;
1045 
1046  // Do not show current date when field not required (see selectDate() method)
1047  if (!$required && $value == '') {
1048  $value = '-1';
1049  }
1050 
1051  if ($mode == 1) {
1052  // search filter on a date extrafield shows two inputs to select a date range
1053  $prefill = array(
1054  'start' => isset($value['start']) ? $value['start'] : '',
1055  'end' => isset($value['end']) ? $value['end'] : ''
1056  );
1057  $out = '<div ' . ($moreparam ? $moreparam : '') . '><div class="nowrap">';
1058  $out .= $form->selectDate($prefill['start'], $keyprefix.$key.$keysuffix.'_start', 1, 1, 1, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans("From"), 'tzuserrel');
1059  $out .= '</div><div class="nowrap">';
1060  $out .= $form->selectDate($prefill['end'], $keyprefix.$key.$keysuffix.'_end', 1, 1, 1, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans("to"), 'tzuserrel');
1061  $out .= '</div></div>';
1062  } else {
1063  // TODO Must also support $moreparam
1064  $out = $form->selectDate($value, $keyprefix.$key.$keysuffix, $showtime, $showtime, $required, '', 1, (($keyprefix != 'search_' && $keyprefix != 'search_options_') ? 1 : 0), 0, 1, '', '', '', 1, '', '', 'tzuserrel');
1065  }
1066  } elseif (in_array($type, array('int', 'integer'))) {
1067  $tmp = explode(',', $size);
1068  $newsize = $tmp[0];
1069  $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 : '').'>';
1070  } elseif (preg_match('/varchar/', $type)) {
1071  $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 : '').'>';
1072  } elseif (in_array($type, array('mail', 'ip', 'phone', 'url'))) {
1073  $out = '<input type="text" class="flat '.$morecss.' maxwidthonsmartphone" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" value="'.dol_escape_htmltag($value).'" '.($moreparam ? $moreparam : '').'>';
1074  } elseif ($type == 'text') {
1075  if (!preg_match('/search_/', $keyprefix)) { // If keyprefix is search_ or search_options_, we must just use a simple text field
1076  require_once DOL_DOCUMENT_ROOT.'/core/class/doleditor.class.php';
1077  $doleditor = new DolEditor($keyprefix.$key.$keysuffix, $value, '', 200, 'dolibarr_notes', 'In', false, false, false, ROWS_5, '90%');
1078  $out = $doleditor->Create(1);
1079  } else {
1080  $out = '<input type="text" class="flat '.$morecss.' maxwidthonsmartphone" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" value="'.dol_escape_htmltag($value).'" '.($moreparam ? $moreparam : '').'>';
1081  }
1082  } elseif ($type == 'html') {
1083  if (!preg_match('/search_/', $keyprefix)) { // If keyprefix is search_ or search_options_, we must just use a simple text field
1084  require_once DOL_DOCUMENT_ROOT.'/core/class/doleditor.class.php';
1085  $doleditor = new DolEditor($keyprefix.$key.$keysuffix, $value, '', 200, 'dolibarr_notes', 'In', false, false, isModEnabled('fckeditor') && $conf->global->FCKEDITOR_ENABLE_SOCIETE, ROWS_5, '90%');
1086  $out = $doleditor->Create(1);
1087  } else {
1088  $out = '<input type="text" class="flat '.$morecss.' maxwidthonsmartphone" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" value="'.dol_escape_htmltag($value).'" '.($moreparam ? $moreparam : '').'>';
1089  }
1090  } elseif ($type == 'boolean') {
1091  if (empty($mode)) {
1092  $checked = '';
1093  if (!empty($value)) {
1094  $checked = ' checked value="1" ';
1095  } else {
1096  $checked = ' value="1" ';
1097  }
1098  $out = '<input type="checkbox" class="flat valignmiddle'.($morecss ? ' '.$morecss : '').' maxwidthonsmartphone" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" '.$checked.' '.($moreparam ? $moreparam : '').'>';
1099  } else {
1100  $out .= $form->selectyesno($keyprefix.$key.$keysuffix, $value, 1, false, 1);
1101  }
1102  } elseif ($type == 'price') {
1103  if (!empty($value)) { // $value in memory is a php numeric, we format it into user number format.
1104  $value = price($value);
1105  }
1106  $out = '<input type="text" class="flat '.$morecss.' maxwidthonsmartphone" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" value="'.$value.'" '.($moreparam ? $moreparam : '').'> '.$langs->getCurrencySymbol($conf->currency);
1107  } elseif ($type == 'pricecy') {
1108  $currency = $conf->currency;
1109  if (!empty($value)) {
1110  // $value in memory is a php string like '10.01:USD'
1111  $pricetmp = explode(':', $value);
1112  $currency = !empty($pricetmp[1]) ? $pricetmp[1] : $conf->currency;
1113  $value = price($pricetmp[0]);
1114  }
1115  $out = '<input type="text" class="flat '.$morecss.' maxwidthonsmartphone" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" value="'.$value.'" '.($moreparam ? $moreparam : '').'> ';
1116  $out .= $form->selectCurrency($currency, $keyprefix.$key.$keysuffix.'currency_id');
1117  } elseif ($type == 'double') {
1118  if (!empty($value)) { // $value in memory is a php numeric, we format it into user number format.
1119  $value = price($value);
1120  }
1121  $out = '<input type="text" class="flat '.$morecss.' maxwidthonsmartphone" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" value="'.$value.'" '.($moreparam ? $moreparam : '').'> ';
1122  } elseif ($type == 'select') {
1123  $out = '';
1124  if ($mode) {
1125  $options = array();
1126  foreach ($param['options'] as $okey => $val) {
1127  if ((string) $okey == '') {
1128  continue;
1129  }
1130 
1131  $valarray = explode('|', $val);
1132  $val = $valarray[0];
1133 
1134  if ($langfile && $val) {
1135  $options[$okey] = $langs->trans($val);
1136  } else {
1137  $options[$okey] = $val;
1138  }
1139  }
1140  $selected = array();
1141  if (!is_array($value)) {
1142  $selected = explode(',', $value);
1143  }
1144 
1145  $out .= $form->multiselectarray($keyprefix.$key.$keysuffix, $options, $selected, 0, 0, $morecss, 0, 0, '', '', '', !empty($conf->use_javascript_ajax) && empty($conf->global->MAIN_EXTRAFIELDS_DISABLE_SELECT2));
1146  } else {
1147  if (!empty($conf->use_javascript_ajax) && empty($conf->global->MAIN_EXTRAFIELDS_DISABLE_SELECT2)) {
1148  include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php';
1149  $out .= ajax_combobox($keyprefix.$key.$keysuffix, array(), 0);
1150  }
1151 
1152  $out .= '<select class="flat '.$morecss.' maxwidthonsmartphone" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" '.($moreparam ? $moreparam : '').'>';
1153  $out .= '<option value="0">&nbsp;</option>';
1154  foreach ($param['options'] as $key2 => $val2) {
1155  if ((string) $key2 == '') {
1156  continue;
1157  }
1158  $valarray = explode('|', $val2);
1159  $val2 = $valarray[0];
1160  $parent = '';
1161  if (!empty($valarray[1])) {
1162  $parent = $valarray[1];
1163  }
1164  $out .= '<option value="'.$key2.'"';
1165  $out .= (((string) $value == (string) $key2) ? ' selected' : '');
1166  $out .= (!empty($parent) ? ' parent="'.$parent.'"' : '');
1167  $out .= '>';
1168  if ($langfile && $val2) {
1169  $out .= $langs->trans($val2);
1170  } else {
1171  $out .= $val2;
1172  }
1173  $out .= '</option>';
1174  }
1175  $out .= '</select>';
1176  }
1177  } elseif ($type == 'sellist') {
1178  $out = '';
1179  if (!empty($conf->use_javascript_ajax) && empty($conf->global->MAIN_EXTRAFIELDS_DISABLE_SELECT2)) {
1180  include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php';
1181  $out .= ajax_combobox($keyprefix.$key.$keysuffix, array(), 0);
1182  }
1183 
1184  $out .= '<select class="flat '.$morecss.' maxwidthonsmartphone" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" '.($moreparam ? $moreparam : '').'>';
1185  if (is_array($param['options'])) {
1186  $param_list = array_keys($param['options']);
1187  $InfoFieldList = explode(":", $param_list[0]);
1188  $parentName = '';
1189  $parentField = '';
1190  // 0 : tableName
1191  // 1 : label field name
1192  // 2 : key fields name (if differ of rowid)
1193  // 3 : key field parent (for dependent lists)
1194  // 4 : where clause filter on column or table extrafield, syntax field='value' or extra.field=value
1195  // 5 : id category type
1196  // 6 : ids categories list separated by comma for category root
1197  $keyList = (empty($InfoFieldList[2]) ? 'rowid' : $InfoFieldList[2].' as rowid');
1198 
1199 
1200  if (count($InfoFieldList) > 4 && !empty($InfoFieldList[4])) {
1201  if (strpos($InfoFieldList[4], 'extra.') !== false) {
1202  $keyList = 'main.'.$InfoFieldList[2].' as rowid';
1203  } else {
1204  $keyList = $InfoFieldList[2].' as rowid';
1205  }
1206  }
1207  if (count($InfoFieldList) > 3 && !empty($InfoFieldList[3])) {
1208  list($parentName, $parentField) = explode('|', $InfoFieldList[3]);
1209  $keyList .= ', '.$parentField;
1210  }
1211 
1212  $filter_categorie = false;
1213  if (count($InfoFieldList) > 5) {
1214  if ($InfoFieldList[0] == 'categorie') {
1215  $filter_categorie = true;
1216  }
1217  }
1218 
1219  if ($filter_categorie === false) {
1220  $fields_label = explode('|', $InfoFieldList[1]);
1221  if (is_array($fields_label)) {
1222  $keyList .= ', ';
1223  $keyList .= implode(', ', $fields_label);
1224  }
1225 
1226  $sqlwhere = '';
1227  $sql = "SELECT ".$keyList;
1228  $sql .= ' FROM '.$this->db->prefix().$InfoFieldList[0];
1229  if (!empty($InfoFieldList[4])) {
1230  // can use current entity filter
1231  if (strpos($InfoFieldList[4], '$ENTITY$') !== false) {
1232  $InfoFieldList[4] = str_replace('$ENTITY$', $conf->entity, $InfoFieldList[4]);
1233  }
1234  // can use SELECT request
1235  if (strpos($InfoFieldList[4], '$SEL$') !== false) {
1236  $InfoFieldList[4] = str_replace('$SEL$', 'SELECT', $InfoFieldList[4]);
1237  }
1238 
1239  // current object id can be use into filter
1240  if (strpos($InfoFieldList[4], '$ID$') !== false && !empty($objectid)) {
1241  $InfoFieldList[4] = str_replace('$ID$', $objectid, $InfoFieldList[4]);
1242  } else {
1243  $InfoFieldList[4] = str_replace('$ID$', '0', $InfoFieldList[4]);
1244  }
1245  //We have to join on extrafield table
1246  if (strpos($InfoFieldList[4], 'extra.') !== false) {
1247  $sql .= ' as main, '.$this->db->prefix().$InfoFieldList[0].'_extrafields as extra';
1248  $sqlwhere .= " WHERE extra.fk_object=main.".$InfoFieldList[2]." AND ".$InfoFieldList[4];
1249  } else {
1250  $sqlwhere .= " WHERE ".$InfoFieldList[4];
1251  }
1252  } else {
1253  $sqlwhere .= ' WHERE 1=1';
1254  }
1255  // Some tables may have field, some other not. For the moment we disable it.
1256  if (in_array($InfoFieldList[0], array('tablewithentity'))) {
1257  $sqlwhere .= ' AND entity = '.((int) $conf->entity);
1258  }
1259  $sql .= $sqlwhere;
1260  //print $sql;
1261 
1262  $sql .= ' ORDER BY '.implode(', ', $fields_label);
1263 
1264  dol_syslog(get_class($this).'::showInputField type=sellist', LOG_DEBUG);
1265  $resql = $this->db->query($sql);
1266  if ($resql) {
1267  $out .= '<option value="0">&nbsp;</option>';
1268  $num = $this->db->num_rows($resql);
1269  $i = 0;
1270  while ($i < $num) {
1271  $labeltoshow = '';
1272  $obj = $this->db->fetch_object($resql);
1273 
1274  // Several field into label (eq table:code|label:rowid)
1275  $notrans = false;
1276  $fields_label = explode('|', $InfoFieldList[1]);
1277  if (is_array($fields_label) && count($fields_label) > 1) {
1278  $notrans = true;
1279  foreach ($fields_label as $field_toshow) {
1280  $labeltoshow .= $obj->$field_toshow.' ';
1281  }
1282  } else {
1283  $labeltoshow = $obj->{$InfoFieldList[1]};
1284  }
1285  $labeltoshow = $labeltoshow;
1286 
1287  if ($value == $obj->rowid) {
1288  if (!$notrans) {
1289  foreach ($fields_label as $field_toshow) {
1290  $translabel = $langs->trans($obj->$field_toshow);
1291  $labeltoshow = $translabel.' ';
1292  }
1293  }
1294  $out .= '<option value="'.$obj->rowid.'" selected>'.$labeltoshow.'</option>';
1295  } else {
1296  if (!$notrans) {
1297  $translabel = $langs->trans($obj->{$InfoFieldList[1]});
1298  $labeltoshow = $translabel;
1299  }
1300  if (empty($labeltoshow)) {
1301  $labeltoshow = '(not defined)';
1302  }
1303 
1304  if (!empty($InfoFieldList[3]) && $parentField) {
1305  $parent = $parentName.':'.$obj->{$parentField};
1306  }
1307 
1308  $out .= '<option value="'.$obj->rowid.'"';
1309  $out .= ($value == $obj->rowid ? ' selected' : '');
1310  $out .= (!empty($parent) ? ' parent="'.$parent.'"' : '');
1311  $out .= '>'.$labeltoshow.'</option>';
1312  }
1313 
1314  $i++;
1315  }
1316  $this->db->free($resql);
1317  } else {
1318  print 'Error in request '.$sql.' '.$this->db->lasterror().'. Check setup of extra parameters.<br>';
1319  }
1320  } else {
1321  require_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php';
1322  $data = $form->select_all_categories(Categorie::$MAP_ID_TO_CODE[$InfoFieldList[5]], '', 'parent', 64, $InfoFieldList[6], 1, 1);
1323  $out .= '<option value="0">&nbsp;</option>';
1324  if (is_array($data)) {
1325  foreach ($data as $data_key => $data_value) {
1326  $out .= '<option value="'.$data_key.'"';
1327  $out .= ($value == $data_key ? ' selected' : '');
1328  $out .= '>'.$data_value.'</option>';
1329  }
1330  }
1331  }
1332  }
1333  $out .= '</select>';
1334  } elseif ($type == 'checkbox') {
1335  $value_arr = $value;
1336  if (!is_array($value)) {
1337  $value_arr = explode(',', $value);
1338  }
1339  $out = $form->multiselectarray($keyprefix.$key.$keysuffix, (empty($param['options']) ?null:$param['options']), $value_arr, '', 0, '', 0, '100%');
1340  } elseif ($type == 'radio') {
1341  $out = '';
1342  foreach ($param['options'] as $keyopt => $val) {
1343  $out .= '<input class="flat '.$morecss.'" type="radio" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" '.($moreparam ? $moreparam : '');
1344  $out .= ' value="'.$keyopt.'"';
1345  $out .= ' id="'.$keyprefix.$key.$keysuffix.'_'.$keyopt.'"';
1346  $out .= ($value == $keyopt ? 'checked' : '');
1347  $out .= '/><label for="'.$keyprefix.$key.$keysuffix.'_'.$keyopt.'">'.$langs->trans($val).'</label><br>';
1348  }
1349  } elseif ($type == 'chkbxlst') {
1350  if (is_array($value)) {
1351  $value_arr = $value;
1352  } else {
1353  $value_arr = explode(',', $value);
1354  }
1355 
1356  if (is_array($param['options'])) {
1357  $param_list = array_keys($param['options']);
1358  $InfoFieldList = explode(":", $param_list[0]);
1359  $parentName = '';
1360  $parentField = '';
1361  // 0 : tableName
1362  // 1 : label field name
1363  // 2 : key fields name (if differ of rowid)
1364  // 3 : key field parent (for dependent lists)
1365  // 4 : where clause filter on column or table extrafield, syntax field='value' or extra.field=value
1366  // 5 : id category type
1367  // 6 : ids categories list separated by comma for category root
1368  $keyList = (empty($InfoFieldList[2]) ? 'rowid' : $InfoFieldList[2].' as rowid');
1369 
1370  if (count($InfoFieldList) > 3 && !empty($InfoFieldList[3])) {
1371  list ($parentName, $parentField) = explode('|', $InfoFieldList[3]);
1372  $keyList .= ', '.$parentField;
1373  }
1374  if (count($InfoFieldList) > 4 && !empty($InfoFieldList[4])) {
1375  if (strpos($InfoFieldList[4], 'extra.') !== false) {
1376  $keyList = 'main.'.$InfoFieldList[2].' as rowid';
1377  } else {
1378  $keyList = $InfoFieldList[2].' as rowid';
1379  }
1380  }
1381 
1382  $filter_categorie = false;
1383  if (count($InfoFieldList) > 5) {
1384  if ($InfoFieldList[0] == 'categorie') {
1385  $filter_categorie = true;
1386  }
1387  }
1388 
1389  if ($filter_categorie === false) {
1390  $fields_label = explode('|', $InfoFieldList[1]);
1391  if (is_array($fields_label)) {
1392  $keyList .= ', ';
1393  $keyList .= implode(', ', $fields_label);
1394  }
1395 
1396  $sqlwhere = '';
1397  $sql = "SELECT ".$keyList;
1398  $sql .= ' FROM '.$this->db->prefix().$InfoFieldList[0];
1399  if (!empty($InfoFieldList[4])) {
1400  // can use current entity filter
1401  if (strpos($InfoFieldList[4], '$ENTITY$') !== false) {
1402  $InfoFieldList[4] = str_replace('$ENTITY$', $conf->entity, $InfoFieldList[4]);
1403  }
1404  // can use SELECT request
1405  if (strpos($InfoFieldList[4], '$SEL$') !== false) {
1406  $InfoFieldList[4] = str_replace('$SEL$', 'SELECT', $InfoFieldList[4]);
1407  }
1408 
1409  // current object id can be use into filter
1410  if (strpos($InfoFieldList[4], '$ID$') !== false && !empty($objectid)) {
1411  $InfoFieldList[4] = str_replace('$ID$', $objectid, $InfoFieldList[4]);
1412  } elseif (preg_match("#^.*list.php$#", $_SERVER["PHP_SELF"])) {
1413  // Pattern for word=$ID$
1414  $word = '\b[a-zA-Z0-9-\.-_]+\b=\$ID\$';
1415 
1416  // Removing space arount =, ( and )
1417  $InfoFieldList[4] = preg_replace('# *(=|\‍(|\‍)) *#', '$1', $InfoFieldList[4]);
1418 
1419  $nbPreg = 1;
1420  // While we have parenthesis
1421  while ($nbPreg != 0) {
1422  // Init des compteurs
1423  $nbPregRepl = $nbPregSel = 0;
1424  // On retire toutes les parenthèses sans = avant
1425  $InfoFieldList[4] = preg_replace('#([^=])(\‍([^)^(]*('.$word.')[^)^(]*\‍))#', '$1 $3 ', $InfoFieldList[4], -1, $nbPregRepl);
1426  // On retire les espaces autour des = et parenthèses
1427  $InfoFieldList[4] = preg_replace('# *(=|\‍(|\‍)) *#', '$1', $InfoFieldList[4]);
1428  // On retire toutes les parenthèses avec = avant
1429  $InfoFieldList[4] = preg_replace('#\b[a-zA-Z0-9-\.-_]+\b=\‍([^)^(]*('.$word.')[^)^(]*\‍)#', '$1 ', $InfoFieldList[4], -1, $nbPregSel);
1430  // On retire les espaces autour des = et parenthèses
1431  $InfoFieldList[4] = preg_replace('# *(=|\‍(|\‍)) *#', '$1', $InfoFieldList[4]);
1432 
1433  // Calcul du compteur général pour la boucle
1434  $nbPreg = $nbPregRepl + $nbPregSel;
1435  }
1436 
1437  // Si l'on a un AND ou un OR, avant ou après
1438  preg_match('#(AND|OR|) *('.$word.') *(AND|OR|)#', $InfoFieldList[4], $matchCondition);
1439  while (!empty($matchCondition[0])) {
1440  // If the two sides differ but are not empty
1441  if (!empty($matchCondition[1]) && !empty($matchCondition[3]) && $matchCondition[1] != $matchCondition[3]) {
1442  // Nobody sain would do that without parentheses
1443  $InfoFieldList[4] = str_replace('$ID$', '0', $InfoFieldList[4]);
1444  } else {
1445  if (!empty($matchCondition[1])) {
1446  $boolCond = (($matchCondition[1] == "AND") ? ' AND TRUE ' : ' OR FALSE ');
1447  $InfoFieldList[4] = str_replace($matchCondition[0], $boolCond.$matchCondition[3], $InfoFieldList[4]);
1448  } elseif (!empty($matchCondition[3])) {
1449  $boolCond = (($matchCondition[3] == "AND") ? ' TRUE AND ' : ' FALSE OR');
1450  $InfoFieldList[4] = str_replace($matchCondition[0], $boolCond, $InfoFieldList[4]);
1451  } else {
1452  $InfoFieldList[4] = " TRUE ";
1453  }
1454  }
1455 
1456  // Si l'on a un AND ou un OR, avant ou après
1457  preg_match('#(AND|OR|) *('.$word.') *(AND|OR|)#', $InfoFieldList[4], $matchCondition);
1458  }
1459  } else {
1460  $InfoFieldList[4] = str_replace('$ID$', '0', $InfoFieldList[4]);
1461  }
1462 
1463  // We have to join on extrafield table
1464  if (strpos($InfoFieldList[4], 'extra.') !== false) {
1465  $sql .= ' as main, '.$this->db->prefix().$InfoFieldList[0].'_extrafields as extra';
1466  $sqlwhere .= " WHERE extra.fk_object=main.".$InfoFieldList[2]." AND ".$InfoFieldList[4];
1467  } else {
1468  $sqlwhere .= " WHERE ".$InfoFieldList[4];
1469  }
1470  } else {
1471  $sqlwhere .= ' WHERE 1=1';
1472  }
1473  // Some tables may have field, some other not. For the moment we disable it.
1474  if (in_array($InfoFieldList[0], array('tablewithentity'))) {
1475  $sqlwhere .= " AND entity = ".((int) $conf->entity);
1476  }
1477  // $sql.=preg_replace('/^ AND /','',$sqlwhere);
1478  // print $sql;
1479 
1480  $sql .= $sqlwhere;
1481  dol_syslog(get_class($this).'::showInputField type=chkbxlst', LOG_DEBUG);
1482  $resql = $this->db->query($sql);
1483  if ($resql) {
1484  $num = $this->db->num_rows($resql);
1485  $i = 0;
1486 
1487  $data = array();
1488 
1489  while ($i < $num) {
1490  $labeltoshow = '';
1491  $obj = $this->db->fetch_object($resql);
1492 
1493  $notrans = false;
1494  // Several field into label (eq table:code|label:rowid)
1495  $fields_label = explode('|', $InfoFieldList[1]);
1496  if (is_array($fields_label)) {
1497  $notrans = true;
1498  foreach ($fields_label as $field_toshow) {
1499  $labeltoshow .= $obj->$field_toshow.' ';
1500  }
1501  } else {
1502  $labeltoshow = $obj->{$InfoFieldList[1]};
1503  }
1504  $labeltoshow = dol_trunc($labeltoshow, 45);
1505 
1506  if (is_array($value_arr) && in_array($obj->rowid, $value_arr)) {
1507  $labeltoshow = '';
1508  foreach ($fields_label as $field_toshow) {
1509  $translabel = $langs->trans($obj->$field_toshow);
1510  if ($translabel != $obj->$field_toshow) {
1511  $labeltoshow .= ' '.dol_trunc($translabel, 18).' ';
1512  } else {
1513  $labeltoshow .= ' '.dol_trunc($obj->$field_toshow, 18).' ';
1514  }
1515  }
1516  $data[$obj->rowid] = $labeltoshow;
1517  } else {
1518  if (!$notrans) {
1519  $translabel = $langs->trans($obj->{$InfoFieldList[1]});
1520  if ($translabel != $obj->{$InfoFieldList[1]}) {
1521  $labeltoshow = dol_trunc($translabel, 18);
1522  } else {
1523  $labeltoshow = dol_trunc($obj->{$InfoFieldList[1]}, 18);
1524  }
1525  }
1526  if (empty($labeltoshow)) {
1527  $labeltoshow = '(not defined)';
1528  }
1529 
1530  if (is_array($value_arr) && in_array($obj->rowid, $value_arr)) {
1531  $data[$obj->rowid] = $labeltoshow;
1532  }
1533 
1534  if (!empty($InfoFieldList[3]) && $parentField) {
1535  $parent = $parentName.':'.$obj->{$parentField};
1536  }
1537 
1538  $data[$obj->rowid] = $labeltoshow;
1539  }
1540 
1541  $i++;
1542  }
1543  $this->db->free($resql);
1544 
1545  $out = $form->multiselectarray($keyprefix.$key.$keysuffix, $data, $value_arr, '', 0, '', 0, '100%');
1546  } else {
1547  print 'Error in request '.$sql.' '.$this->db->lasterror().'. Check setup of extra parameters.<br>';
1548  }
1549  } else {
1550  require_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php';
1551  $data = $form->select_all_categories(Categorie::$MAP_ID_TO_CODE[$InfoFieldList[5]], '', 'parent', 64, $InfoFieldList[6], 1, 1);
1552  $out = $form->multiselectarray($keyprefix.$key.$keysuffix, $data, $value_arr, '', 0, '', 0, '100%');
1553  }
1554  }
1555  } elseif ($type == 'link') {
1556  $param_list = array_keys($param['options']); // $param_list='ObjectName:classPath'
1557  $showempty = (($required && $default != '') ? 0 : 1);
1558  $out = $form->selectForForms($param_list[0], $keyprefix.$key.$keysuffix, $value, $showempty, '', '', $morecss);
1559  } elseif ($type == 'password') {
1560  // If prefix is 'search_', field is used as a filter, we use a common text field.
1561  $out = '<input style="display:none" type="text" name="fakeusernameremembered">'; // Hidden field to reduce impact of evil Google Chrome autopopulate bug.
1562  $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 : '').'>';
1563  }
1564  if (!empty($hidden)) {
1565  $out = '<input type="hidden" value="'.$value.'" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'"/>';
1566  }
1567  /* Add comments
1568  if ($type == 'date') $out.=' (YYYY-MM-DD)';
1569  elseif ($type == 'datetime') $out.=' (YYYY-MM-DD HH:MM:SS)';
1570  */
1571  /*if (!empty($help) && $keyprefix != 'search_options_') {
1572  $out .= $form->textwithpicto('', $help, 1, 'help', '', 0, 3);
1573  }*/
1574  return $out;
1575  }
1576 
1577 
1587  public function showOutputField($key, $value, $moreparam = '', $extrafieldsobjectkey = '')
1588  {
1589  global $conf, $langs;
1590 
1591  if (empty($extrafieldsobjectkey)) {
1592  dol_syslog(get_class($this).'::showOutputField extrafieldsobjectkey required', LOG_ERR);
1593  return 'BadValueForParamExtraFieldsObjectKey';
1594  }
1595 
1596  $label = $this->attributes[$extrafieldsobjectkey]['label'][$key];
1597  $type = $this->attributes[$extrafieldsobjectkey]['type'][$key];
1598  $size = $this->attributes[$extrafieldsobjectkey]['size'][$key]; // Can be '255', '24,8'...
1599  $default = $this->attributes[$extrafieldsobjectkey]['default'][$key];
1600  $computed = $this->attributes[$extrafieldsobjectkey]['computed'][$key];
1601  $unique = $this->attributes[$extrafieldsobjectkey]['unique'][$key];
1602  $required = $this->attributes[$extrafieldsobjectkey]['required'][$key];
1603  $param = $this->attributes[$extrafieldsobjectkey]['param'][$key];
1604  $perms = dol_eval($this->attributes[$extrafieldsobjectkey]['perms'][$key], 1, 1, '2');
1605  $langfile = $this->attributes[$extrafieldsobjectkey]['langfile'][$key];
1606  $list = dol_eval($this->attributes[$extrafieldsobjectkey]['list'][$key], 1, 1, '2');
1607  $help = $this->attributes[$extrafieldsobjectkey]['help'][$key];
1608  $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)
1609 
1610  if ($hidden) {
1611  return ''; // This is a protection. If field is hidden, we should just not call this method.
1612  }
1613 
1614  //if ($computed) $value = // $value is already calculated into $value before calling this method
1615 
1616  $showsize = 0;
1617  if ($type == 'date') {
1618  $showsize = 10;
1619  if ($value !== '') {
1620  $value = dol_print_date($value, 'day'); // For date without hour, date is always GMT for storage and output
1621  }
1622  } elseif ($type == 'datetime') {
1623  $showsize = 19;
1624  if ($value !== '') {
1625  $value = dol_print_date($value, 'dayhour', 'tzuserrel');
1626  }
1627  } elseif ($type == 'datetimegmt') {
1628  $showsize = 19;
1629  if ($value !== '') {
1630  $value = dol_print_date($value, 'dayhour', 'gmt');
1631  }
1632  } elseif ($type == 'int') {
1633  $showsize = 10;
1634  } elseif ($type == 'double') {
1635  if (!empty($value)) {
1636  //$value=price($value);
1637  $sizeparts = explode(",", $size);
1638  $number_decimals = array_key_exists(1, $sizeparts) ? $sizeparts[1] : 0;
1639  $value = price($value, 0, $langs, 0, 0, $number_decimals, '');
1640  }
1641  } elseif ($type == 'boolean') {
1642  $checked = '';
1643  if (!empty($value)) {
1644  $checked = ' checked ';
1645  }
1646  $value = '<input type="checkbox" '.$checked.' '.($moreparam ? $moreparam : '').' readonly disabled>';
1647  } elseif ($type == 'mail') {
1648  $value = dol_print_email($value, 0, 0, 0, 64, 1, 1);
1649  } elseif ($type == 'ip') {
1650  $value = dol_print_ip($value, 0);
1651  } elseif ($type == 'url') {
1652  $value = dol_print_url($value, '_blank', 32, 1);
1653  } elseif ($type == 'phone') {
1654  $value = dol_print_phone($value, '', 0, 0, '', '&nbsp;', 'phone');
1655  } elseif ($type == 'price') {
1656  //$value = price($value, 0, $langs, 0, 0, -1, $conf->currency);
1657  if ($value || $value == '0') {
1658  $value = price($value, 0, $langs, 0, $conf->global->MAIN_MAX_DECIMALS_TOT, -1).' '.$langs->getCurrencySymbol($conf->currency);
1659  }
1660  } elseif ($type == 'pricecy') {
1661  $currency = $conf->currency;
1662  if (!empty($value)) {
1663  // $value in memory is a php string like '0.01:EUR'
1664  $pricetmp = explode(':', $value);
1665  $currency = !empty($pricetmp[1]) ? $pricetmp[1] : $conf->currency;
1666  $value = $pricetmp[0];
1667  }
1668  if ($value || $value == '0') {
1669  $value = price($value, 0, $langs, 0, $conf->global->MAIN_MAX_DECIMALS_TOT, -1, $currency);
1670  }
1671  } elseif ($type == 'select') {
1672  $valstr = (!empty($param['options'][$value]) ? $param['options'][$value] : '');
1673  if (($pos = strpos($valstr, "|")) !== false) {
1674  $valstr = substr($valstr, 0, $pos);
1675  }
1676  if ($langfile && $valstr) {
1677  $value = $langs->trans($valstr);
1678  } else {
1679  $value = $valstr;
1680  }
1681  } elseif ($type == 'sellist') {
1682  $param_list = array_keys($param['options']);
1683  $InfoFieldList = explode(":", $param_list[0]);
1684 
1685  $selectkey = "rowid";
1686  $keyList = 'rowid';
1687 
1688  if (count($InfoFieldList) >= 3) {
1689  $selectkey = $InfoFieldList[2];
1690  $keyList = $InfoFieldList[2].' as rowid';
1691  }
1692 
1693  $fields_label = explode('|', $InfoFieldList[1]);
1694  if (is_array($fields_label)) {
1695  $keyList .= ', ';
1696  $keyList .= implode(', ', $fields_label);
1697  }
1698 
1699  $filter_categorie = false;
1700  if (count($InfoFieldList) > 5) {
1701  if ($InfoFieldList[0] == 'categorie') {
1702  $filter_categorie = true;
1703  }
1704  }
1705 
1706  $sql = "SELECT ".$keyList;
1707  $sql .= ' FROM '.$this->db->prefix().$InfoFieldList[0];
1708  if (!empty($InfoFieldList[4]) && strpos($InfoFieldList[4], 'extra.') !== false) {
1709  $sql .= ' as main';
1710  }
1711  if ($selectkey == 'rowid' && empty($value)) {
1712  $sql .= " WHERE ".$selectkey." = 0";
1713  } elseif ($selectkey == 'rowid') {
1714  $sql .= " WHERE ".$selectkey." = ".((int) $value);
1715  } else {
1716  $sql .= " WHERE ".$selectkey." = '".$this->db->escape($value)."'";
1717  }
1718 
1719  //$sql.= ' AND entity = '.$conf->entity;
1720 
1721  dol_syslog(get_class($this).':showOutputField:$type=sellist', LOG_DEBUG);
1722  $resql = $this->db->query($sql);
1723  if ($resql) {
1724  if ($filter_categorie === false) {
1725  $value = ''; // value was used, so now we reste it to use it to build final output
1726 
1727  $obj = $this->db->fetch_object($resql);
1728 
1729  // Several field into label (eq table:code|label:rowid)
1730  $fields_label = explode('|', $InfoFieldList[1]);
1731 
1732  if (is_array($fields_label) && count($fields_label) > 1) {
1733  foreach ($fields_label as $field_toshow) {
1734  $translabel = '';
1735  if (!empty($obj->$field_toshow)) {
1736  $translabel = $langs->trans($obj->$field_toshow);
1737  }
1738  if ($translabel != $obj->$field_toshow) {
1739  $value .= dol_trunc($translabel, 24).' ';
1740  } else {
1741  $value .= $obj->$field_toshow.' ';
1742  }
1743  }
1744  } else {
1745  $translabel = '';
1746  $tmppropname = $InfoFieldList[1];
1747  //$obj->$tmppropname = '';
1748  if (!empty(isset($obj->$tmppropname) ? $obj->$tmppropname : '')) {
1749  $translabel = $langs->trans($obj->$tmppropname);
1750  }
1751  if ($translabel != (isset($obj->$tmppropname) ? $obj->$tmppropname : '')) {
1752  $value = dol_trunc($translabel, 18);
1753  } else {
1754  $value = isset($obj->$tmppropname) ? $obj->$tmppropname : '';
1755  }
1756  }
1757  } else {
1758  $toprint = array();
1759  $obj = $this->db->fetch_object($resql);
1760  if ($obj->rowid) {
1761  require_once DOL_DOCUMENT_ROOT . '/categories/class/categorie.class.php';
1762  $c = new Categorie($this->db);
1763  $result = $c->fetch($obj->rowid);
1764  if ($result > 0) {
1765  $ways = $c->print_all_ways(); // $ways[0] = "ccc2 >> ccc2a >> ccc2a1" with html formatted text
1766  foreach ($ways as $way) {
1767  $toprint[] = '<li class="select2-search-choice-dolibarr noborderoncategories"' . ($c->color ? ' style="background: #' . $c->color . ';"' : ' style="background: #bbb"') . '>' . img_object('', 'category') . ' ' . $way . '</li>';
1768  }
1769  }
1770  }
1771  $value = '<div class="select2-container-multi-dolibarr" style="width: 90%;"><ul class="select2-choices-dolibarr">'.implode(' ', $toprint).'</ul></div>';
1772  }
1773  } else {
1774  dol_syslog(get_class($this).'::showOutputField error '.$this->db->lasterror(), LOG_WARNING);
1775  }
1776  } elseif ($type == 'radio') {
1777  if (!isset($param['options'][$value])) {
1778  $langs->load('errors');
1779  $value = $langs->trans('ErrorNoValueForRadioType');
1780  } else {
1781  $value = $langs->trans($param['options'][$value]);
1782  }
1783  } elseif ($type == 'checkbox') {
1784  $value_arr = explode(',', $value);
1785  $value = '';
1786  $toprint = array();
1787  if (is_array($value_arr)) {
1788  foreach ($value_arr as $keyval => $valueval) {
1789  if (!empty($valueval)) {
1790  $toprint[] = '<li class="select2-search-choice-dolibarr noborderoncategories" style="background: #bbb">'.$param['options'][$valueval].'</li>';
1791  }
1792  }
1793  }
1794  $value = '<div class="select2-container-multi-dolibarr" style="width: 90%;"><ul class="select2-choices-dolibarr">'.implode(' ', $toprint).'</ul></div>';
1795  } elseif ($type == 'chkbxlst') {
1796  $value_arr = explode(',', $value);
1797 
1798  $param_list = array_keys($param['options']);
1799  $InfoFieldList = explode(":", $param_list[0]);
1800 
1801  $selectkey = "rowid";
1802  $keyList = 'rowid';
1803 
1804  if (count($InfoFieldList) >= 3) {
1805  $selectkey = $InfoFieldList[2];
1806  $keyList = $InfoFieldList[2].' as rowid';
1807  }
1808 
1809  $fields_label = explode('|', $InfoFieldList[1]);
1810  if (is_array($fields_label)) {
1811  $keyList .= ', ';
1812  $keyList .= implode(', ', $fields_label);
1813  }
1814 
1815  $filter_categorie = false;
1816  if (count($InfoFieldList) > 5) {
1817  if ($InfoFieldList[0] == 'categorie') {
1818  $filter_categorie = true;
1819  }
1820  }
1821 
1822  $sql = "SELECT ".$keyList;
1823  $sql .= " FROM ".$this->db->prefix().$InfoFieldList[0];
1824  if (strpos($InfoFieldList[4], 'extra.') !== false) {
1825  $sql .= ' as main';
1826  }
1827  // $sql.= " WHERE ".$selectkey."='".$this->db->escape($value)."'";
1828  // $sql.= ' AND entity = '.$conf->entity;
1829 
1830  dol_syslog(get_class($this).':showOutputField:$type=chkbxlst', LOG_DEBUG);
1831  $resql = $this->db->query($sql);
1832  if ($resql) {
1833  if ($filter_categorie === false) {
1834  $value = ''; // value was used, so now we reste it to use it to build final output
1835  $toprint = array();
1836  while ($obj = $this->db->fetch_object($resql)) {
1837  // Several field into label (eq table:code|label:rowid)
1838  $fields_label = explode('|', $InfoFieldList[1]);
1839  if (is_array($value_arr) && in_array($obj->rowid, $value_arr)) {
1840  if (is_array($fields_label) && count($fields_label) > 1) {
1841  $label = '<li class="select2-search-choice-dolibarr noborderoncategories" style="background: #bbb">';
1842  foreach ($fields_label as $field_toshow) {
1843  $translabel = '';
1844  if (!empty($obj->$field_toshow)) {
1845  $translabel = $langs->trans($obj->$field_toshow);
1846  }
1847  if ($translabel != $field_toshow) {
1848  $label .= ' '.dol_trunc($translabel, 18);
1849  } else {
1850  $label .= ' '.$obj->$field_toshow;
1851  }
1852  }
1853  $label .= '</li>';
1854  $toprint[] = $label;
1855  } else {
1856  $translabel = '';
1857  if (!empty($obj->{$InfoFieldList[1]})) {
1858  $translabel = $langs->trans($obj->{$InfoFieldList[1]});
1859  }
1860  if ($translabel != $obj->{$InfoFieldList[1]}) {
1861  $toprint[] = '<li class="select2-search-choice-dolibarr noborderoncategories" style="background: #bbb">'.dol_trunc($translabel, 18).'</li>';
1862  } else {
1863  $toprint[] = '<li class="select2-search-choice-dolibarr noborderoncategories" style="background: #bbb">'.$obj->{$InfoFieldList[1]}.'</li>';
1864  }
1865  }
1866  }
1867  }
1868  } else {
1869  require_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php';
1870 
1871  $toprint = array();
1872  while ($obj = $this->db->fetch_object($resql)) {
1873  if (is_array($value_arr) && in_array($obj->rowid, $value_arr)) {
1874  $c = new Categorie($this->db);
1875  $c->fetch($obj->rowid);
1876  $ways = $c->print_all_ways(); // $ways[0] = "ccc2 >> ccc2a >> ccc2a1" with html formatted text
1877  foreach ($ways as $way) {
1878  $toprint[] = '<li class="select2-search-choice-dolibarr noborderoncategories"'.($c->color ? ' style="background: #'.$c->color.';"' : ' style="background: #bbb"').'>'.img_object('', 'category').' '.$way.'</li>';
1879  }
1880  }
1881  }
1882  }
1883  if (!empty($toprint)) $value = '<div class="select2-container-multi-dolibarr" style="width: 90%;"><ul class="select2-choices-dolibarr">'.implode(' ', $toprint).'</ul></div>';
1884  } else {
1885  dol_syslog(get_class($this).'::showOutputField error '.$this->db->lasterror(), LOG_WARNING);
1886  }
1887  } elseif ($type == 'link') {
1888  $out = '';
1889 
1890  // Only if something to display (perf)
1891  if ($value) { // If we have -1 here, pb is into insert, not into ouptut (fix insert instead of changing code here to compensate)
1892  $param_list = array_keys($param['options']); // $param_list='ObjectName:classPath'
1893 
1894  $InfoFieldList = explode(":", $param_list[0]);
1895  $classname = $InfoFieldList[0];
1896  $classpath = $InfoFieldList[1];
1897  if (!empty($classpath)) {
1898  dol_include_once($InfoFieldList[1]);
1899  if ($classname && class_exists($classname)) {
1900  $object = new $classname($this->db);
1901  $object->fetch($value);
1902  $value = $object->getNomUrl(3);
1903  }
1904  } else {
1905  dol_syslog('Error bad setup of extrafield', LOG_WARNING);
1906  return 'Error bad setup of extrafield';
1907  }
1908  }
1909  } elseif ($type == 'text') {
1910  $value = dol_htmlentitiesbr($value);
1911  } elseif ($type == 'html') {
1912  $value = dol_htmlentitiesbr($value);
1913  } elseif ($type == 'password') {
1914  $value = dol_trunc(preg_replace('/./i', '*', $value), 8, 'right', 'UTF-8', 1);
1915  } else {
1916  $showsize = round((float) $size);
1917  if ($showsize > 48) {
1918  $showsize = 48;
1919  }
1920  }
1921 
1922  //print $type.'-'.$size;
1923  $out = $value;
1924 
1925  return $out;
1926  }
1927 
1935  public function getAlignFlag($key, $extrafieldsobjectkey = '')
1936  {
1937  global $conf, $langs;
1938 
1939  $type = 'varchar';
1940  if (!empty($extrafieldsobjectkey)) {
1941  $type = $this->attributes[$extrafieldsobjectkey]['type'][$key];
1942  }
1943 
1944  $cssstring = '';
1945 
1946  if (in_array($type, array('date', 'datetime', 'datetimegmt'))) {
1947  $cssstring = "center";
1948  } elseif (in_array($type, array('int', 'price', 'double'))) {
1949  $cssstring = "right";
1950  } elseif (in_array($type, array('boolean', 'radio', 'checkbox', 'ip'))) {
1951  $cssstring = "center";
1952  }
1953 
1954  if (!empty($this->attributes[$extrafieldsobjectkey]['csslist'][$key])) {
1955  $cssstring .= ($cssstring ? ' ' : '').$this->attributes[$extrafieldsobjectkey]['csslist'][$key];
1956  } else {
1957  if (in_array($type, array('ip'))) {
1958  $cssstring .= ($cssstring ? ' ' : '').'tdoverflowmax150';
1959  }
1960  }
1961 
1962  return $cssstring;
1963  }
1964 
1975  public function showSeparator($key, $object, $colspan = 2, $display_type = 'card', $mode = '')
1976  {
1977  global $conf, $langs;
1978 
1979  $tagtype='tr';
1980  $tagtype_dyn='td';
1981 
1982  if ($display_type=='line') {
1983  $tagtype='div';
1984  $tagtype_dyn='span';
1985  $colspan=0;
1986  }
1987 
1988  $extrafield_param = $this->attributes[$object->table_element]['param'][$key];
1989  $extrafield_param_list = array();
1990  if (!empty($extrafield_param) && is_array($extrafield_param)) {
1991  $extrafield_param_list = array_keys($extrafield_param['options']);
1992  }
1993 
1994  // Set $extrafield_collapse_display_value (do we have to collapse/expand the group after the separator)
1995  $extrafield_collapse_display_value = -1;
1996  $expand_display = false;
1997  if (is_array($extrafield_param_list) && count($extrafield_param_list) > 0) {
1998  $extrafield_collapse_display_value = intval($extrafield_param_list[0]);
1999  $expand_display = ((isset($_COOKIE['DOLCOLLAPSE_'.$object->table_element.'_extrafields_'.$key]) || GETPOST('ignorecollapsesetup', 'int')) ? (empty($_COOKIE['DOLCOLLAPSE_'.$object->table_element.'_extrafields_'.$key]) ? false : true) : ($extrafield_collapse_display_value == 2 ? false : true));
2000  }
2001  $disabledcookiewrite = 0;
2002  if ($mode == 'create') {
2003  // On create mode, force separator group to not be collapsable
2004  $extrafield_collapse_display_value = 1;
2005  $expand_display = true; // We force group to be shown expanded
2006  $disabledcookiewrite = 1; // We keep status of group unchanged into the cookie
2007  }
2008 
2009  $out = '<'.$tagtype.' id="trextrafieldseparator'.$key.(!empty($object->id)?'_'.$object->id:'').'" class="trextrafieldseparator trextrafieldseparator'.$key.(!empty($object->id)?'_'.$object->id:'').'">';
2010  $out .= '<'.$tagtype_dyn.' '.(!empty($colspan)?'colspan="' . $colspan . '"':'').'>';
2011  // Some js code will be injected here to manage the collapsing of extrafields
2012  // Output the picto
2013  $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>';
2014  $out .= '&nbsp;';
2015  $out .= '<strong>';
2016  $out .= $langs->trans($this->attributes[$object->table_element]['label'][$key]);
2017  $out .= '</strong>';
2018  $out .= '</'.$tagtype_dyn.'>';
2019  $out .= '</'.$tagtype.'>';
2020 
2021  $collapse_group = $key.(!empty($object->id) ? '_'.$object->id : '');
2022  //$extrafields_collapse_num = $this->attributes[$object->table_element]['pos'][$key].(!empty($object->id)?'_'.$object->id:'');
2023 
2024  if ($extrafield_collapse_display_value == 1 || $extrafield_collapse_display_value == 2) {
2025  // Set the collapse_display status to cookie in priority or if ignorecollapsesetup is 1, if cookie and ignorecollapsesetup not defined, use the setup.
2026  $this->expand_display[$collapse_group] = $expand_display;
2027 
2028  if (!empty($conf->use_javascript_ajax)) {
2029  $out .= '<!-- Add js script to manage the collapse/uncollapse of extrafields separators '.$key.' -->'."\n";
2030  $out .= '<script nonce="'.getNonce().'" type="text/javascript">'."\n";
2031  $out .= 'jQuery(document).ready(function(){'."\n";
2032  if (empty($disabledcookiewrite)) {
2033  if ($expand_display === false) {
2034  $out .= ' console.log("Inject js for the collapsing of extrafield '.$key.' - hide");'."\n";
2035  $out .= ' jQuery(".trextrafields_collapse'.$collapse_group.'").hide();'."\n";
2036  } else {
2037  $out .= ' console.log("Inject js for collapsing of extrafield '.$key.' - keep visible and set cookie");'."\n";
2038  $out .= ' document.cookie = "DOLCOLLAPSE_'.$object->table_element.'_extrafields_'.$key.'=1; path='.$_SERVER["PHP_SELF"].'"'."\n";
2039  }
2040  }
2041  $out .= ' jQuery("#trextrafieldseparator'.$key.(!empty($object->id)?'_'.$object->id:'').'").click(function(){'."\n";
2042  $out .= ' console.log("We click on collapse/uncollapse to hide/show .trextrafields_collapse'.$collapse_group.'");'."\n";
2043  $out .= ' jQuery(".trextrafields_collapse'.$collapse_group.'").toggle(100, function(){'."\n";
2044  $out .= ' if (jQuery(".trextrafields_collapse'.$collapse_group.'").is(":hidden")) {'."\n";
2045  $out .= ' jQuery("#trextrafieldseparator'.$key.(!empty($object->id)?'_'.$object->id:'').' '.$tagtype_dyn.' span").addClass("fa-plus-square").removeClass("fa-minus-square");'."\n";
2046  $out .= ' document.cookie = "DOLCOLLAPSE_'.$object->table_element.'_extrafields_'.$key.'=0; path='.$_SERVER["PHP_SELF"].'"'."\n";
2047  $out .= ' } else {'."\n";
2048  $out .= ' jQuery("#trextrafieldseparator'.$key.(!empty($object->id)?'_'.$object->id:'').' '.$tagtype_dyn.' span").addClass("fa-minus-square").removeClass("fa-plus-square");'."\n";
2049  $out .= ' document.cookie = "DOLCOLLAPSE_'.$object->table_element.'_extrafields_'.$key.'=1; path='.$_SERVER["PHP_SELF"].'"'."\n";
2050  $out .= ' }'."\n";
2051  $out .= ' });'."\n";
2052  $out .= ' });'."\n";
2053  $out .= '});'."\n";
2054  $out .= '</script>'."\n";
2055  }
2056  } else {
2057  $this->expand_display[$collapse_group] = 1;
2058  }
2059 
2060  return $out;
2061  }
2062 
2074  public function setOptionalsFromPost($extralabels, &$object, $onlykey = '', $todefaultifmissing = 0)
2075  {
2076  global $_POST, $langs;
2077 
2078  $nofillrequired = 0; // For error when required field left blank
2079  $error_field_required = array();
2080 
2081  if (isset($this->attributes[$object->table_element]['label']) && is_array($this->attributes[$object->table_element]['label'])) {
2082  $extralabels = $this->attributes[$object->table_element]['label'];
2083  }
2084 
2085  if (is_array($extralabels)) {
2086  // Get extra fields
2087  foreach ($extralabels as $key => $value) {
2088  if (!empty($onlykey) && $onlykey != '@GETPOSTISSET' && $key != $onlykey) {
2089  continue;
2090  }
2091 
2092  if (!empty($onlykey) && $onlykey == '@GETPOSTISSET' && !GETPOSTISSET('options_'.$key) && (! in_array($this->attributes[$object->table_element]['type'][$key], array('boolean', 'checkbox', 'chkbxlst')))) {
2093  //when unticking boolean field, it's not set in POST
2094  continue;
2095  }
2096 
2097  $key_type = $this->attributes[$object->table_element]['type'][$key];
2098  if ($key_type == 'separate') {
2099  continue;
2100  }
2101 
2102  $enabled = 1;
2103  if (isset($this->attributes[$object->table_element]['enabled'][$key])) { // 'enabled' is often a condition on module enabled or not
2104  $enabled = dol_eval($this->attributes[$object->table_element]['enabled'][$key], 1, 1, '2');
2105  }
2106 
2107  $visibility = 1;
2108  if (isset($this->attributes[$object->table_element]['list'][$key])) { // 'list' is option for visibility
2109  $visibility = intval(dol_eval($this->attributes[$object->table_element]['list'][$key], 1, 1, '2'));
2110  }
2111 
2112  $perms = 1;
2113  if (isset($this->attributes[$object->table_element]['perms'][$key])) {
2114  $perms = dol_eval($this->attributes[$object->table_element]['perms'][$key], 1, 1, '2');
2115  }
2116  if (empty($enabled)
2117  || (
2118  $onlykey === '@GETPOSTISSET'
2119  && in_array($this->attributes[$object->table_element]['type'][$key], array('boolean', 'checkbox', 'chkbxlst'))
2120  && in_array(abs($enabled), array(2, 5))
2121  && ! GETPOSTISSET('options_' . $key) // Update hidden checkboxes and multiselect only if they are provided
2122  )
2123  ) {
2124  continue;
2125  }
2126  $visibility_abs = abs($visibility);
2127  // not modify if extra field is not in update form (0 : never, 2 or -2 : list only, 5 or - 5 : list and view only)
2128  if (empty($visibility_abs) || $visibility_abs == 2 || $visibility_abs == 5) {
2129  continue;
2130  }
2131  if (empty($perms)) {
2132  continue;
2133  }
2134 
2135  if ($this->attributes[$object->table_element]['required'][$key]) { // Value is required
2136  // Check if functionally empty without using GETPOST (depending on the type of extrafield, a
2137  // technically non-empty value may be treated as empty functionally).
2138  // value can be alpha, int, array, etc...
2139  if ((!is_array($_POST["options_".$key]) && empty($_POST["options_".$key]) && $this->attributes[$object->table_element]['type'][$key] != 'select' && $_POST["options_".$key] != '0')
2140  || (!is_array($_POST["options_".$key]) && empty($_POST["options_".$key]) && $this->attributes[$object->table_element]['type'][$key] == 'select')
2141  || (!is_array($_POST["options_".$key]) && isset($_POST["options_".$key]) && $this->attributes[$object->table_element]['type'][$key] == 'sellist' && $_POST['options_'.$key] == '0')
2142  || (is_array($_POST["options_".$key]) && empty($_POST["options_".$key]))) {
2143  //print 'ccc'.$value.'-'.$this->attributes[$object->table_element]['required'][$key];
2144 
2145  // 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.
2146 
2147  $nofillrequired++;
2148  if (!empty($this->attributes[$object->table_element]['langfile'][$key])) {
2149  $langs->load($this->attributes[$object->table_element]['langfile'][$key]);
2150  }
2151  $error_field_required[$key] = $langs->transnoentitiesnoconv($value);
2152  }
2153  }
2154 
2155  if (in_array($key_type, array('date'))) {
2156  // Clean parameters
2157  $value_key = dol_mktime(12, 0, 0, GETPOST("options_".$key."month", 'int'), GETPOST("options_".$key."day", 'int'), GETPOST("options_".$key."year", 'int'));
2158  } elseif (in_array($key_type, array('datetime'))) {
2159  // Clean parameters
2160  $value_key = dol_mktime(GETPOST("options_".$key."hour", 'int'), GETPOST("options_".$key."min", 'int'), GETPOST("options_".$key."sec", 'int'), GETPOST("options_".$key."month", 'int'), GETPOST("options_".$key."day", 'int'), GETPOST("options_".$key."year", 'int'), 'tzuserrel');
2161  } elseif (in_array($key_type, array('datetimegmt'))) {
2162  // Clean parameters
2163  $value_key = dol_mktime(GETPOST("options_".$key."hour", 'int'), GETPOST("options_".$key."min", 'int'), GETPOST("options_".$key."sec", 'int'), GETPOST("options_".$key."month", 'int'), GETPOST("options_".$key."day", 'int'), GETPOST("options_".$key."year", 'int'), 'gmt');
2164  } elseif (in_array($key_type, array('checkbox', 'chkbxlst'))) {
2165  $value_arr = GETPOST("options_".$key, 'array'); // check if an array
2166  if (!empty($value_arr)) {
2167  $value_key = implode(',', $value_arr);
2168  } else {
2169  $value_key = '';
2170  }
2171  } elseif (in_array($key_type, array('price', 'double'))) {
2172  $value_arr = GETPOST("options_".$key, 'alpha');
2173  $value_key = price2num($value_arr);
2174  } elseif (in_array($key_type, array('pricecy', 'double'))) {
2175  $value_key = price2num(GETPOST("options_".$key, 'alpha')).':'.GETPOST("options_".$key."currency_id", 'alpha');
2176  } elseif (in_array($key_type, array('html'))) {
2177  $value_key = GETPOST("options_".$key, 'restricthtml');
2178  } elseif (in_array($key_type, array('text'))) {
2179  $label_security_check = 'alphanohtml';
2180  // by default 'alphanohtml' (better security); hidden conf MAIN_SECURITY_ALLOW_UNSECURED_LABELS_WITH_HTML allows basic html
2181  if (!empty($conf->global->MAIN_SECURITY_ALLOW_UNSECURED_REF_LABELS)) {
2182  $label_security_check = 'nohtml';
2183  } else {
2184  $label_security_check = empty($conf->global->MAIN_SECURITY_ALLOW_UNSECURED_LABELS_WITH_HTML) ? 'alphanohtml' : 'restricthtml';
2185  }
2186  $value_key = GETPOST("options_".$key, $label_security_check);
2187  } else {
2188  $value_key = GETPOST("options_".$key);
2189  if (in_array($key_type, array('link')) && $value_key == '-1') {
2190  $value_key = '';
2191  }
2192  }
2193 
2194  if (!empty($error_field_required[$key]) && $todefaultifmissing) {
2195  // Value is required but we have a default value and we asked to set empty value to the default value
2196  if (!empty($this->attributes[$object->table_element]['default']) && !is_null($this->attributes[$object->table_element]['default'][$key])) {
2197  $value_key = $this->attributes[$object->table_element]['default'][$key];
2198  unset($error_field_required[$key]);
2199  $nofillrequired--;
2200  }
2201  }
2202 
2203  $object->array_options["options_".$key] = $value_key;
2204  }
2205 
2206  if ($nofillrequired) {
2207  $langs->load('errors');
2208  $this->error = $langs->trans('ErrorFieldsRequired').' : '.implode(', ', $error_field_required);
2209  setEventMessages($this->error, null, 'errors');
2210  return -1;
2211  } else {
2212  return 1;
2213  }
2214  } else {
2215  return 0;
2216  }
2217  }
2218 
2227  public function getOptionalsFromPost($extrafieldsobjectkey, $keyprefix = '', $keysuffix = '')
2228  {
2229  global $_POST;
2230 
2231  if (is_string($extrafieldsobjectkey) && !empty($this->attributes[$extrafieldsobjectkey]['label']) && is_array($this->attributes[$extrafieldsobjectkey]['label'])) {
2232  $extralabels = $this->attributes[$extrafieldsobjectkey]['label'];
2233  } else {
2234  $extralabels = $extrafieldsobjectkey;
2235  }
2236 
2237  if (is_array($extralabels)) {
2238  $array_options = array();
2239 
2240  // Get extra fields
2241  foreach ($extralabels as $key => $value) {
2242  $key_type = '';
2243  if (is_string($extrafieldsobjectkey)) {
2244  $key_type = $this->attributes[$extrafieldsobjectkey]['type'][$key];
2245  }
2246 
2247  if (in_array($key_type, array('date'))) {
2248  $dateparamname_start = $keysuffix . 'options_' . $key . $keyprefix . '_start';
2249  $dateparamname_end = $keysuffix . 'options_' . $key . $keyprefix . '_end';
2250  if (GETPOSTISSET($dateparamname_start . 'year') && GETPOSTISSET($dateparamname_end . 'year')) {
2251  // values provided as a date pair (start date + end date), each date being broken down as year, month, day, etc.
2252  $value_key = array(
2253  'start' => dol_mktime(0, 0, 0, GETPOST($dateparamname_start . 'month', 'int'), GETPOST($dateparamname_start . 'day', 'int'), GETPOST($dateparamname_start . 'year', 'int')),
2254  'end' => dol_mktime(23, 59, 59, GETPOST($dateparamname_end . 'month', 'int'), GETPOST($dateparamname_end . 'day', 'int'), GETPOST($dateparamname_end . 'year', 'int'))
2255  );
2256  } elseif (GETPOSTISSET($keysuffix."options_".$key.$keyprefix."year")) {
2257  // Clean parameters
2258  $value_key = dol_mktime(12, 0, 0, GETPOST($keysuffix."options_".$key.$keyprefix."month", 'int'), GETPOST($keysuffix."options_".$key.$keyprefix."day", 'int'), GETPOST($keysuffix."options_".$key.$keyprefix."year", 'int'));
2259  } else {
2260  continue; // Value was not provided, we should not set it.
2261  }
2262  } elseif (in_array($key_type, array('datetime', 'datetimegmt'))) {
2263  $dateparamname_start = $keysuffix . 'options_' . $key . $keyprefix . '_start';
2264  $dateparamname_end = $keysuffix . 'options_' . $key . $keyprefix . '_end';
2265  if (GETPOSTISSET($dateparamname_start . 'year') && GETPOSTISSET($dateparamname_end . 'year')) {
2266  // values provided as a date pair (start date + end date), each date being broken down as year, month, day, etc.
2267  $dateparamname_end_hour = GETPOST($dateparamname_end . 'hour', 'int') !='-1' ? GETPOST($dateparamname_end . 'hour', 'int') : '23';
2268  $dateparamname_end_min = GETPOST($dateparamname_end . 'min', 'int') !='-1' ? GETPOST($dateparamname_end . 'min', 'int') : '59';
2269  $dateparamname_end_sec = GETPOST($dateparamname_end . 'sec', 'int') !='-1' ? GETPOST($dateparamname_end . 'sec', 'int') : '59';
2270  if ($key_type == 'datetimegmt') {
2271  $value_key = array(
2272  'start' => dol_mktime(GETPOST($dateparamname_start . 'hour', 'int'), GETPOST($dateparamname_start . 'min', 'int'), GETPOST($dateparamname_start . 'sec', 'int'), GETPOST($dateparamname_start . 'month', 'int'), GETPOST($dateparamname_start . 'day', 'int'), GETPOST($dateparamname_start . 'year', 'int'), 'gmt'),
2273  'end' => dol_mktime($dateparamname_end_hour, $dateparamname_end_min, $dateparamname_end_sec, GETPOST($dateparamname_end . 'month', 'int'), GETPOST($dateparamname_end . 'day', 'int'), GETPOST($dateparamname_end . 'year', 'int'), 'gmt')
2274  );
2275  } else {
2276  $value_key = array(
2277  'start' => dol_mktime(GETPOST($dateparamname_start . 'hour', 'int'), GETPOST($dateparamname_start . 'min', 'int'), GETPOST($dateparamname_start . 'sec', 'int'), GETPOST($dateparamname_start . 'month', 'int'), GETPOST($dateparamname_start . 'day', 'int'), GETPOST($dateparamname_start . 'year', 'int'), 'tzuserrel'),
2278  'end' => dol_mktime($dateparamname_end_hour, $dateparamname_end_min, $dateparamname_end_sec, GETPOST($dateparamname_end . 'month', 'int'), GETPOST($dateparamname_end . 'day', 'int'), GETPOST($dateparamname_end . 'year', 'int'), 'tzuserrel')
2279  );
2280  }
2281  } elseif (GETPOSTISSET($keysuffix."options_".$key.$keyprefix."year")) {
2282  // Clean parameters
2283  if ($key_type == 'datetimegmt') {
2284  $value_key = dol_mktime(GETPOST($keysuffix."options_".$key.$keyprefix."hour", 'int'), GETPOST($keysuffix."options_".$key.$keyprefix."min", 'int'), GETPOST($keysuffix."options_".$key.$keyprefix."sec", 'int'), GETPOST($keysuffix."options_".$key.$keyprefix."month", 'int'), GETPOST($keysuffix."options_".$key.$keyprefix."day", 'int'), GETPOST($keysuffix."options_".$key.$keyprefix."year", 'int'), 'gmt');
2285  } else {
2286  $value_key = dol_mktime(GETPOST($keysuffix."options_".$key.$keyprefix."hour", 'int'), GETPOST($keysuffix."options_".$key.$keyprefix."min", 'int'), GETPOST($keysuffix."options_".$key.$keyprefix."sec", 'int'), GETPOST($keysuffix."options_".$key.$keyprefix."month", 'int'), GETPOST($keysuffix."options_".$key.$keyprefix."day", 'int'), GETPOST($keysuffix."options_".$key.$keyprefix."year", 'int'), 'tzuserrel');
2287  }
2288  } else {
2289  continue; // Value was not provided, we should not set it.
2290  }
2291  } elseif ($key_type == 'select') {
2292  // to detect if we are in search context
2293  if (GETPOSTISARRAY($keysuffix."options_".$key.$keyprefix)) {
2294  $value_arr = GETPOST($keysuffix."options_".$key.$keyprefix, 'array:aZ09');
2295  // Make sure we get an array even if there's only one selected
2296  $value_arr = (array) $value_arr;
2297  $value_key = implode(',', $value_arr);
2298  } else {
2299  $value_key = GETPOST($keysuffix."options_".$key.$keyprefix);
2300  }
2301  } elseif (in_array($key_type, array('checkbox', 'chkbxlst'))) {
2302  if (!GETPOSTISSET($keysuffix."options_".$key.$keyprefix)) {
2303  continue; // Value was not provided, we should not set it.
2304  }
2305  $value_arr = GETPOST($keysuffix."options_".$key.$keyprefix);
2306  // Make sure we get an array even if there's only one checkbox
2307  $value_arr = (array) $value_arr;
2308  $value_key = implode(',', $value_arr);
2309  } elseif (in_array($key_type, array('price', 'double', 'int'))) {
2310  if (!GETPOSTISSET($keysuffix."options_".$key.$keyprefix)) {
2311  continue; // Value was not provided, we should not set it.
2312  }
2313  $value_arr = GETPOST($keysuffix."options_".$key.$keyprefix);
2314  if ($keysuffix != 'search_') { // If value is for a search, we must keep complex string like '>100 <=150'
2315  $value_key = price2num($value_arr);
2316  } else {
2317  $value_key = $value_arr;
2318  }
2319  } elseif (in_array($key_type, array('boolean'))) {
2320  if (!GETPOSTISSET($keysuffix."options_".$key.$keyprefix)) {
2321  $value_key = '';
2322  } else {
2323  $value_arr = GETPOST($keysuffix."options_".$key.$keyprefix);
2324  $value_key = $value_arr;
2325  }
2326  } elseif (in_array($key_type, array('html'))) {
2327  if (!GETPOSTISSET($keysuffix."options_".$key.$keyprefix)) {
2328  continue; // Value was not provided, we should not set it.
2329  }
2330  $value_key = dol_htmlcleanlastbr(GETPOST($keysuffix."options_".$key.$keyprefix, 'restricthtml'));
2331  } else {
2332  if (!GETPOSTISSET($keysuffix."options_".$key.$keyprefix)) {
2333  continue; // Value was not provided, we should not set it.
2334  }
2335  $value_key = GETPOST($keysuffix."options_".$key.$keyprefix);
2336  }
2337 
2338  $array_options[$keysuffix."options_".$key] = $value_key; // No keyprefix here. keyprefix is used only for read.
2339  }
2340 
2341  return $array_options;
2342  }
2343 
2344  return 0;
2345  }
2346 }
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:449
Class to manage categories.
Class to manage a WYSIWYG editor.
Class to manage standard extra fields.
update($attrname, $label, $type, $length, $elementtype, $unique=0, $required=0, $pos=0, $param='', $alwayseditable=0, $perms='', $list='', $help='', $default='', $computed='', $entity='', $langfile='', $enabled='1', $totalizable=0, $printable=0, $moreparams=array())
Modify type of a personalized attribute.
getOptionalsFromPost($extrafieldsobjectkey, $keyprefix='', $keysuffix='')
return array_options array of data of extrafields value of object sent by a search form
showOutputField($key, $value, $moreparam='', $extrafieldsobjectkey='')
Return HTML string to put an output field into a page.
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.
update_label($attrname, $label, $type, $size, $elementtype, $unique=0, $required=0, $pos=0, $param='', $alwayseditable=0, $perms='', $list='0', $help='', $default='', $computed='', $entity='', $langfile='', $enabled='1', $totalizable=0, $printable=0, $moreparams=array())
Modify description of personalized 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 ...
create_label($attrname, $label='', $type='', $pos=0, $size=0, $elementtype='member', $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.
showSeparator($key, $object, $colspan=2, $display_type='card', $mode='')
Return HTML string to print separator extrafield.
create($attrname, $type='varchar', $length=255, $elementtype='member', $unique=0, $required=0, $default_value='', $param='', $perms='', $list='0', $computed='', $help='', $moreparams=array())
Add a new optional attribute.
delete_label($attrname, $elementtype='member')
Delete description of an optional attribute.
fetch_name_optionals_label($elementtype, $forceload=false)
Load the array of extrafields defintion $this->attributes.
__construct($db)
Constructor.
setOptionalsFromPost($extralabels, &$object, $onlykey='', $todefaultifmissing=0)
Fill array_options property of object by extrafields value (using for data sent by forms)
Class to manage generation of HTML components Only common components must be here.
if(isModEnabled('facture') && $user->hasRight('facture', 'lire')) if((isModEnabled('fournisseur') &&empty($conf->global->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') &&!empty($user->rights->tax->charges->lire)) if(isModEnabled('facture') &&isModEnabled('commande') && $user->hasRight("commande", "lire") &&empty($conf->global->WORKFLOW_DISABLE_CREATE_INVOICE_FROM_ORDER)) $sql
Social contributions to pay.
Definition: index.php:746
if($cancel &&! $id) if($action=='add' &&! $cancel) if($action=='delete') if($id) $form
Actions.
Definition: card.php:143
dol_mktime($hour, $minute, $second, $month, $day, $year, $gm='auto', $check=1)
Return a timestamp date built from detailed informations (by default a local PHP server timestamp) Re...
dol_print_ip($ip, $mode=0)
Return an IP formated to be shown on screen.
price2num($amount, $rounding='', $option=0)
Function that return a number with universal decimal format (decimal separator is '.
dol_print_error($db='', $error='', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
img_object($titlealt, $picto, $moreatt='', $pictoisfullpath=false, $srconly=0, $notitle=0)
Show a picto called object_picto (generic function)
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_date($time, $format='', $tzoutput='auto', $outputlangs='', $encodetooutput=false)
Output date in a string format according to outputlangs (or langs if not defined).
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.
dol_eval($s, $returnvalue=0, $hideerrors=1, $onlysimplestring='1')
Replace eval function to add more security.
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_url($url, $target='_blank', $max=32, $withpicto=0, $morecss='float')
Show Url link.
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.
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...