From 6aea67a5b96fca933027b33fde892efda9a3c64a Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Wed, 1 Apr 2020 23:15:53 +0200 Subject: [PATCH] Work on extralanguages --- htdocs/core/class/commonobject.class.php | 24 +- htdocs/core/class/extrafields.class.php | 26 +- htdocs/core/class/extralanguages.class.php | 1333 ++++++++++++++++++++ htdocs/core/class/html.form.class.php | 76 +- 4 files changed, 1400 insertions(+), 59 deletions(-) create mode 100644 htdocs/core/class/extralanguages.class.php diff --git a/htdocs/core/class/commonobject.class.php b/htdocs/core/class/commonobject.class.php index 1d5ebbc4fa6..bc1fd5e75b7 100644 --- a/htdocs/core/class/commonobject.class.php +++ b/htdocs/core/class/commonobject.class.php @@ -629,7 +629,7 @@ abstract class CommonObject */ public function getBannerAddress($htmlkey, $object) { - global $conf, $langs, $form; + global $conf, $langs, $form, $extralanguages; $countriesusingstate = array('AU', 'US', 'IN', 'GB', 'ES', 'UK', 'TR'); // See also option MAIN_FORCE_STATE_INTO_ADDRESS @@ -673,18 +673,24 @@ abstract class CommonObject $out .= dol_print_address($coords, 'address_'.$htmlkey.'_'.$this->id, $this->element, $this->id, 1, ', '); $outdone++; $outdone++; - $useextralanguages = $conf->global->PDF_USE_ALSO_LANGUAGE_CODE; - if ($useextralanguages) { - $this->fetchValuesForExtraLanguages(); - $extralanguages = array(); - if (isset($this->array_languages['address'])) $extralanguages[] = reset(array_keys($this->array_languages['address'])); - if (isset($this->array_languages['town'])) $extralanguages[] = reset(array_keys($this->array_languages['town'])); + // List of extra languages + $arrayoflangcode = array(); + if (! empty($conf->global->PDF_USE_ALSO_LANGUAGE_CODE)) $arrayoflangcode[] = $conf->global->PDF_USE_ALSO_LANGUAGE_CODE; - if (is_array($extralanguages) && count($extralanguages)) { + if (is_array($arrayoflangcode) && count($arrayoflangcode)) { + if (! is_object($extralanguages)) { + include_once DOL_DOCUMENT_ROOT.'/core/class/extralanguages.class.php'; + $extralanguages = new ExtraLanguages($this->db); + } + $extralanguages->fetch_name_extralanguages('societe'); + + if (! empty($extralanguages->attributes['societe']['address']) || ! empty($extralanguages->attributes['societe']['town'])) + { + $this->fetchValuesForExtraLanguages(); if (! is_object($form)) $form = new Form($this->db); $htmltext = ''; // If there is extra languages - foreach($extralanguages as $key => $extralangcode) { + foreach($arrayoflangcode as $extralangcode) { $s=picto_from_langcode($extralangcode, 'class="pictoforlang paddingright"'); $coords = $this->getFullAddress(1, ', ', $conf->global->MAIN_SHOW_REGION_IN_STATE_SELECT, $extralangcode); $htmltext .= $s.dol_print_address($coords, 'address_'.$htmlkey.'_'.$this->id, $this->element, $this->id, 1, ', '); diff --git a/htdocs/core/class/extrafields.class.php b/htdocs/core/class/extrafields.class.php index 7a9373d59db..f044943272b 100644 --- a/htdocs/core/class/extrafields.class.php +++ b/htdocs/core/class/extrafields.class.php @@ -842,7 +842,7 @@ class ExtraFields /** * Load array this->attributes, or old this->attribute_xxx like attribute_label, attribute_type, ... * - * @param string $elementtype Type of element ('adherent', 'commande', 'thirdparty', 'facture', 'propal', 'product', ...). + * @param string $elementtype Type of element ('' = all, 'adherent', 'commande', 'thirdparty', 'facture', 'propal', 'product', ...). * @param boolean $forceload Force load of extra fields whatever is status of cache. * @return array Array of attributes keys+label for all extra fields. */ @@ -859,30 +859,6 @@ class ExtraFields $array_name_label = array(); - // To avoid conflicts with external modules. TODO Remove this. - if (empty($forceload) && !empty($conf->global->MAIN_EXTRAFIELDS_DISABLED)) return $array_name_label; - - // If already loaded - // TODO Enable this cache test - // if (empty($forceload) && ! empty($this->attributes[$tab->elementtype]['loaded'])) return $array_name_label; - - // Set array of label of entity - // Remove completely loading of label. This should be done by presentation. - /* - $labelmulticompany=array(); - if (!empty($conf->multicompany->enabled)) - { - $sql_entity_name='SELECT rowid, label FROM '.MAIN_DB_PREFIX.'entity WHERE rowid in (0,'.$conf->entity.')'; - $resql_entity_name=$this->db->query($sql_entity_name); - if ($resql_entity_name) - { - while ($obj = $this->db->fetch_object($resql_entity_name)) - { - $labelmulticompany[$obj->rowid]=$obj->label; - } - } - }*/ - // 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 $sql = "SELECT rowid,name,label,type,size,elementtype,fieldunique,fieldrequired,param,pos,alwayseditable,perms,langs,list,printable,totalizable,fielddefault,fieldcomputed,entity,enabled,help"; $sql .= " FROM ".MAIN_DB_PREFIX."extrafields"; diff --git a/htdocs/core/class/extralanguages.class.php b/htdocs/core/class/extralanguages.class.php new file mode 100644 index 00000000000..768169cd3eb --- /dev/null +++ b/htdocs/core/class/extralanguages.class.php @@ -0,0 +1,1333 @@ + + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * \file htdocs/core/class/extralanguages.class.php + * \ingroup core + * \brief File of class to manage extra fields + */ + + +/** + * Class to manage standard extra languages + */ +class ExtraLanguages +{ + /** + * @var DoliDB Database handler. + */ + public $db; + + /** + * @var array New array to store extralanguages definition + */ + public $attributes; + + /** + * @var string Error code (or message) + */ + public $error = ''; + + /** + * @var string[] Array of Error code (or message) + */ + public $errors = array(); + + /** + * @var string DB Error number + */ + public $errno; + + + /** + * Constructor + * + * @param DoliDB $db Database handler + */ + public function __construct($db) + { + $this->db = $db; + $this->error = ''; + $this->errors = array(); + $this->attributes = array(); + } + + + // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps + /** + * Load array this->attributes + * + * @param string $elementtype Type of element ('' = all, 'adherent', 'commande', 'thirdparty', 'facture', 'propal', 'product', ...). + * @param boolean $forceload Force load of extra fields whatever is status of cache. + * @return array Array of attributes keys+label for all extra fields. + */ + public function fetch_name_extralanguages($elementtype, $forceload = false) + { + // phpcs:enable + global $conf; + + if (empty($elementtype)) return array(); + + if ($elementtype == 'thirdparty') $elementtype = 'societe'; + if ($elementtype == 'contact') $elementtype = 'socpeople'; + if ($elementtype == 'order_supplier') $elementtype = 'commande_fournisseur'; + + $array_name_label = array( + 'societe' => array('name'=>'Name'), + 'contact' => array('firstname' => 'Firstname', 'lastname' => 'Lastname') + ); + + $this->attributes = $array_name_label; + + return $array_name_label; + } + + + /** + * Return HTML string to put an input field into a page + * Code very similar with showInputField of common object + * + * @param string $key Key of attribute + * @param string $value Preselected value to show (for date type it must be in timestamp format, for amount or price it must be a php numeric value) + * @param string $moreparam To add more parametes on html input tag + * @param string $keysuffix Prefix string to add after name and id of field (can be used to avoid duplicate names) + * @param string $keyprefix Suffix string to add before name and id of field (can be used to avoid duplicate names) + * @param string $morecss More css (to defined size of field. Old behaviour: may also be a numeric) + * @param int $objectid Current object id + * @param string $extrafieldsobjectkey If defined (for example $object->table_element), use the new method to get extrafields data + * @param string $mode 1=Used for search filters + * @return string + */ + public function showInputField($key, $value, $moreparam = '', $keysuffix = '', $keyprefix = '', $morecss = '', $objectid = 0, $extrafieldsobjectkey = '', $mode = 0) + { + global $conf, $langs, $form; + + if (!is_object($form)) + { + require_once DOL_DOCUMENT_ROOT.'/core/class/html.form.class.php'; + $form = new Form($this->db); + } + + $out = ''; + + if (!preg_match('/options_$/', $keyprefix)) // Because we work on extrafields, we add 'options_' to prefix if not already added + { + $keyprefix = $keyprefix.'options_'; + } + + if (!empty($extrafieldsobjectkey)) + { + $label = $this->attributes[$extrafieldsobjectkey]['label'][$key]; + $type = $this->attributes[$extrafieldsobjectkey]['type'][$key]; + $size = $this->attributes[$extrafieldsobjectkey]['size'][$key]; + $default = $this->attributes[$extrafieldsobjectkey]['default'][$key]; + $computed = $this->attributes[$extrafieldsobjectkey]['computed'][$key]; + $unique = $this->attributes[$extrafieldsobjectkey]['unique'][$key]; + $required = $this->attributes[$extrafieldsobjectkey]['required'][$key]; + $param = $this->attributes[$extrafieldsobjectkey]['param'][$key]; + $perms = dol_eval($this->attributes[$extrafieldsobjectkey]['perms'][$key], 1); + $langfile = $this->attributes[$extrafieldsobjectkey]['langfile'][$key]; + $list = dol_eval($this->attributes[$extrafieldsobjectkey]['list'][$key], 1); + $totalizable = $this->attributes[$extrafieldsobjectkey]['totalizable'][$key]; + $help = $this->attributes[$extrafieldsobjectkey]['help'][$key]; + $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) + } + else // Old usage + { + $label = $this->attribute_label[$key]; + $type = $this->attribute_type[$key]; + $size = $this->attribute_size[$key]; + $elementtype = $this->attribute_elementtype[$key]; // Seems not used + $default = $this->attribute_default[$key]; + $computed = $this->attribute_computed[$key]; + $unique = $this->attribute_unique[$key]; + $required = $this->attribute_required[$key]; + $param = $this->attribute_param[$key]; + $langfile = $this->attribute_langfile[$key]; + $list = $this->attribute_list[$key]; + $totalizable = $this->attribute_totalizable[$key]; + $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) + } + + if ($computed) + { + if (!preg_match('/^search_/', $keyprefix)) return ''.$langs->trans("AutomaticallyCalculated").''; + else return ''; + } + + if (empty($morecss)) + { + if ($type == 'date') + { + $morecss = 'minwidth100imp'; + } + elseif ($type == 'datetime' || $type == 'link') + { + $morecss = 'minwidth200imp'; + } + elseif (in_array($type, array('int', 'integer', 'double', 'price'))) + { + $morecss = 'maxwidth75'; + } + elseif ($type == 'password') + { + $morecss = 'maxwidth100'; + } + elseif ($type == 'url') + { + $morecss = 'minwidth400'; + } + elseif ($type == 'boolean') + { + $morecss = ''; + } + else + { + if (round($size) < 12) + { + $morecss = 'minwidth100'; + } + elseif (round($size) <= 48) + { + $morecss = 'minwidth200'; + } + else + { + $morecss = 'minwidth400'; + } + } + } + + if (in_array($type, array('date', 'datetime'))) + { + $tmp = explode(',', $size); + $newsize = $tmp[0]; + + $showtime = in_array($type, array('datetime')) ? 1 : 0; + + // Do not show current date when field not required (see selectDate() method) + if (!$required && $value == '') $value = '-1'; + + // TODO Must also support $moreparam + $out = $form->selectDate($value, $keyprefix.$key.$keysuffix, $showtime, $showtime, $required, '', 1, (($keyprefix != 'search_' && $keyprefix != 'search_options_') ? 1 : 0), 0, 1); + } + elseif (in_array($type, array('int', 'integer'))) + { + $tmp = explode(',', $size); + $newsize = $tmp[0]; + $out = ''; + } + elseif (preg_match('/varchar/', $type)) + { + $out = ''; + } + elseif (in_array($type, array('mail', 'phone', 'url'))) + { + $out = ''; + } + elseif ($type == 'text') + { + if (!preg_match('/search_/', $keyprefix)) // If keyprefix is search_ or search_options_, we must just use a simple text field + { + require_once DOL_DOCUMENT_ROOT.'/core/class/doleditor.class.php'; + $doleditor = new DolEditor($keyprefix.$key.$keysuffix, $value, '', 200, 'dolibarr_notes', 'In', false, false, false, ROWS_5, '90%'); + $out = $doleditor->Create(1); + } + else + { + $out = ''; + } + } + elseif ($type == 'html') + { + if (!preg_match('/search_/', $keyprefix)) // If keyprefix is search_ or search_options_, we must just use a simple text field + { + require_once DOL_DOCUMENT_ROOT.'/core/class/doleditor.class.php'; + $doleditor = new DolEditor($keyprefix.$key.$keysuffix, $value, '', 200, 'dolibarr_notes', 'In', false, false, !empty($conf->fckeditor->enabled) && $conf->global->FCKEDITOR_ENABLE_SOCIETE, ROWS_5, '90%'); + $out = $doleditor->Create(1); + } + else + { + $out = ''; + } + } + elseif ($type == 'boolean') + { + if (empty($mode)) + { + $checked = ''; + if (!empty($value)) { + $checked = ' checked value="1" '; + } else { + $checked = ' value="1" '; + } + $out = ''; + } + else + { + $out .= $form->selectyesno($keyprefix.$key.$keysuffix, $value, 1, false, 1); + } + } + elseif ($type == 'price') + { + if (!empty($value)) { // $value in memory is a php numeric, we format it into user number format. + $value = price($value); + } + $out = ' '.$langs->getCurrencySymbol($conf->currency); + } + elseif ($type == 'double') + { + if (!empty($value)) { // $value in memory is a php numeric, we format it into user number format. + $value = price($value); + } + $out = ' '; + } + elseif ($type == 'select') + { + $out = ''; + if (!empty($conf->use_javascript_ajax) && !empty($conf->global->MAIN_EXTRAFIELDS_USE_SELECT2)) + { + include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php'; + $out .= ajax_combobox($keyprefix.$key.$keysuffix, array(), 0); + } + + $out .= ''; + } + elseif ($type == 'sellist') + { + $out = ''; + if (!empty($conf->use_javascript_ajax) && !empty($conf->global->MAIN_EXTRAFIELDS_USE_SELECT2)) + { + include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php'; + $out .= ajax_combobox($keyprefix.$key.$keysuffix, array(), 0); + } + + $out .= ''; + } + elseif ($type == 'checkbox') + { + $value_arr = explode(',', $value); + $out = $form->multiselectarray($keyprefix.$key.$keysuffix, (empty($param['options']) ?null:$param['options']), $value_arr, '', 0, '', 0, '100%'); + } + elseif ($type == 'radio') + { + $out = ''; + foreach ($param['options'] as $keyopt => $val) + { + $out .= ''.$val.'
'; + } + } + elseif ($type == 'chkbxlst') + { + if (is_array($value)) { + $value_arr = $value; + } + else { + $value_arr = explode(',', $value); + } + + if (is_array($param['options'])) { + $param_list = array_keys($param['options']); + $InfoFieldList = explode(":", $param_list[0]); + $parentName = ''; + $parentField = ''; + // 0 : tableName + // 1 : label field name + // 2 : key fields name (if differ of rowid) + // 3 : key field parent (for dependent lists) + // 4 : where clause filter on column or table extrafield, syntax field='value' or extra.field=value + // 5 : id category type + // 6 : ids categories list separated by comma for category root + $keyList = (empty($InfoFieldList[2]) ? 'rowid' : $InfoFieldList[2].' as rowid'); + + if (count($InfoFieldList) > 3 && !empty($InfoFieldList[3])) { + list ($parentName, $parentField) = explode('|', $InfoFieldList[3]); + $keyList .= ', '.$parentField; + } + if (count($InfoFieldList) > 4 && !empty($InfoFieldList[4])) { + if (strpos($InfoFieldList[4], 'extra.') !== false) { + $keyList = 'main.'.$InfoFieldList[2].' as rowid'; + } else { + $keyList = $InfoFieldList[2].' as rowid'; + } + } + + $filter_categorie = false; + if (count($InfoFieldList) > 5) { + if ($InfoFieldList[0] == 'categorie') { + $filter_categorie = true; + } + } + + if ($filter_categorie === false) { + $fields_label = explode('|', $InfoFieldList[1]); + if (is_array($fields_label)) { + $keyList .= ', '; + $keyList .= implode(', ', $fields_label); + } + + $sqlwhere = ''; + $sql = 'SELECT '.$keyList; + $sql .= ' FROM '.MAIN_DB_PREFIX.$InfoFieldList[0]; + if (!empty($InfoFieldList[4])) { + // can use SELECT request + if (strpos($InfoFieldList[4], '$SEL$') !== false) { + $InfoFieldList[4] = str_replace('$SEL$', 'SELECT', $InfoFieldList[4]); + } + + // current object id can be use into filter + if (strpos($InfoFieldList[4], '$ID$') !== false && !empty($objectid)) { + $InfoFieldList[4] = str_replace('$ID$', $objectid, $InfoFieldList[4]); + } elseif (preg_match("#^.*list.php$#", $_SERVER["PHP_SELF"])) { + // Pattern for word=$ID$ + $word = '\b[a-zA-Z0-9-\.-_]+\b=\$ID\$'; + + // Removing space arount =, ( and ) + $InfoFieldList[4] = preg_replace('# *(=|\(|\)) *#', '$1', $InfoFieldList[4]); + + $nbPreg = 1; + // While we have parenthesis + while ($nbPreg != 0) { + // Init des compteurs + $nbPregRepl = $nbPregSel = 0; + // On retire toutes les parenthèses sans = avant + $InfoFieldList[4] = preg_replace('#([^=])(\([^)^(]*('.$word.')[^)^(]*\))#', '$1 $3 ', $InfoFieldList[4], -1, $nbPregRepl); + // On retire les espaces autour des = et parenthèses + $InfoFieldList[4] = preg_replace('# *(=|\(|\)) *#', '$1', $InfoFieldList[4]); + // On retire toutes les parenthèses avec = avant + $InfoFieldList[4] = preg_replace('#\b[a-zA-Z0-9-\.-_]+\b=\([^)^(]*('.$word.')[^)^(]*\)#', '$1 ', $InfoFieldList[4], -1, $nbPregSel); + // On retire les espaces autour des = et parenthèses + $InfoFieldList[4] = preg_replace('# *(=|\(|\)) *#', '$1', $InfoFieldList[4]); + + // Calcul du compteur général pour la boucle + $nbPreg = $nbPregRepl + $nbPregSel; + } + + // Si l'on a un AND ou un OR, avant ou après + preg_match('#(AND|OR|) *('.$word.') *(AND|OR|)#', $InfoFieldList[4], $matchCondition); + while (!empty($matchCondition[0])) { + // If the two sides differ but are not empty + if (!empty($matchCondition[1]) && !empty($matchCondition[3]) && $matchCondition[1] != $matchCondition[3]) { + // Nobody sain would do that without parentheses + $InfoFieldList[4] = str_replace('$ID$', '0', $InfoFieldList[4]); + } else { + if (!empty($matchCondition[1])) { + $boolCond = (($matchCondition[1] == "AND") ? ' AND TRUE ' : ' OR FALSE '); + $InfoFieldList[4] = str_replace($matchCondition[0], $boolCond.$matchCondition[3], $InfoFieldList[4]); + } elseif (!empty($matchCondition[3])) { + $boolCond = (($matchCondition[3] == "AND") ? ' TRUE AND ' : ' FALSE OR'); + $InfoFieldList[4] = str_replace($matchCondition[0], $boolCond, $InfoFieldList[4]); + } else { + $InfoFieldList[4] = " TRUE "; + } + } + + // Si l'on a un AND ou un OR, avant ou après + preg_match('#(AND|OR|) *('.$word.') *(AND|OR|)#', $InfoFieldList[4], $matchCondition); + } + } else { + $InfoFieldList[4] = str_replace('$ID$', '0', $InfoFieldList[4]); + } + + // We have to join on extrafield table + if (strpos($InfoFieldList[4], 'extra.') !== false) { + $sql .= ' as main, '.MAIN_DB_PREFIX.$InfoFieldList[0].'_extrafields as extra'; + $sqlwhere .= ' WHERE extra.fk_object=main.'.$InfoFieldList[2].' AND '.$InfoFieldList[4]; + } else { + $sqlwhere .= ' WHERE '.$InfoFieldList[4]; + } + } else { + $sqlwhere .= ' WHERE 1=1'; + } + // Some tables may have field, some other not. For the moment we disable it. + if (in_array($InfoFieldList[0], array('tablewithentity'))) { + $sqlwhere .= ' AND entity = '.$conf->entity; + } + // $sql.=preg_replace('/^ AND /','',$sqlwhere); + // print $sql; + + $sql .= $sqlwhere; + dol_syslog(get_class($this).'::showInputField type=chkbxlst', LOG_DEBUG); + $resql = $this->db->query($sql); + if ($resql) { + $num = $this->db->num_rows($resql); + $i = 0; + + $data = array(); + + while ($i < $num) { + $labeltoshow = ''; + $obj = $this->db->fetch_object($resql); + + $notrans = false; + // Several field into label (eq table:code|libelle:rowid) + $fields_label = explode('|', $InfoFieldList[1]); + if (is_array($fields_label)) { + $notrans = true; + foreach ($fields_label as $field_toshow) { + $labeltoshow .= $obj->$field_toshow.' '; + } + } else { + $labeltoshow = $obj->{$InfoFieldList[1]}; + } + $labeltoshow = dol_trunc($labeltoshow, 45); + + if (is_array($value_arr) && in_array($obj->rowid, $value_arr)) { + foreach ($fields_label as $field_toshow) { + $translabel = $langs->trans($obj->$field_toshow); + if ($translabel != $obj->$field_toshow) { + $labeltoshow = dol_trunc($translabel, 18).' '; + } else { + $labeltoshow = dol_trunc($obj->$field_toshow, 18).' '; + } + } + + $data[$obj->rowid] = $labeltoshow; + } else { + if (!$notrans) { + $translabel = $langs->trans($obj->{$InfoFieldList[1]}); + if ($translabel != $obj->{$InfoFieldList[1]}) { + $labeltoshow = dol_trunc($translabel, 18); + } else { + $labeltoshow = dol_trunc($obj->{$InfoFieldList[1]}, 18); + } + } + if (empty($labeltoshow)) + $labeltoshow = '(not defined)'; + + if (is_array($value_arr) && in_array($obj->rowid, $value_arr)) { + $data[$obj->rowid] = $labeltoshow; + } + + if (!empty($InfoFieldList[3]) && $parentField) { + $parent = $parentName.':'.$obj->{$parentField}; + } + + $data[$obj->rowid] = $labeltoshow; + } + + $i++; + } + $this->db->free($resql); + + $out = $form->multiselectarray($keyprefix . $key . $keysuffix, $data, $value_arr, '', 0, '', 0, '100%'); + } else { + print 'Error in request ' . $sql . ' ' . $this->db->lasterror() . '. Check setup of extra parameters.
'; + } + } else { + require_once DOL_DOCUMENT_ROOT . '/categories/class/categorie.class.php'; + $data = $form->select_all_categories(Categorie::$MAP_ID_TO_CODE[$InfoFieldList[5]], '', 'parent', 64, $InfoFieldList[6], 1, 1); + $out = $form->multiselectarray($keyprefix . $key . $keysuffix, $data, $value_arr, '', 0, '', 0, '100%'); + } + } + } + elseif ($type == 'link') + { + $param_list=array_keys($param['options']); // $param_list='ObjectName:classPath' + $showempty=(($required && $default != '')?0:1); + $out=$form->selectForForms($param_list[0], $keyprefix.$key.$keysuffix, $value, $showempty, '', '', $morecss); + } + elseif ($type == 'password') + { + // If prefix is 'search_', field is used as a filter, we use a common text field. + $out=''; // Hidden field to reduce impact of evil Google Chrome autopopulate bug. + $out.=''; + } + if (!empty($hidden)) { + $out=''; + } + /* Add comments + if ($type == 'date') $out.=' (YYYY-MM-DD)'; + elseif ($type == 'datetime') $out.=' (YYYY-MM-DD HH:MM:SS)'; + */ + /*if (! empty($help) && $keyprefix != 'search_options_') { + $out .= $form->textwithpicto('', $help, 1, 'help', '', 0, 3); + }*/ + return $out; + } + + + /** + * Return HTML string to put an output field into a page + * + * @param string $key Key of attribute + * @param string $value Value to show + * @param string $moreparam To add more parameters on html input tag (only checkbox use html input for output rendering) + * @param string $extrafieldsobjectkey If defined (for example $object->table_element), function uses the new method to get extrafields data + * @return string Formated value + */ + public function showOutputField($key, $value, $moreparam = '', $extrafieldsobjectkey = '') + { + global $conf, $langs; + + if (!empty($extrafieldsobjectkey)) + { + $label = $this->attributes[$extrafieldsobjectkey]['label'][$key]; + $type = $this->attributes[$extrafieldsobjectkey]['type'][$key]; + $size = $this->attributes[$extrafieldsobjectkey]['size'][$key]; + $default = $this->attributes[$extrafieldsobjectkey]['default'][$key]; + $computed = $this->attributes[$extrafieldsobjectkey]['computed'][$key]; + $unique = $this->attributes[$extrafieldsobjectkey]['unique'][$key]; + $required = $this->attributes[$extrafieldsobjectkey]['required'][$key]; + $param = $this->attributes[$extrafieldsobjectkey]['param'][$key]; + $perms = dol_eval($this->attributes[$extrafieldsobjectkey]['perms'][$key], 1); + $langfile = $this->attributes[$extrafieldsobjectkey]['langfile'][$key]; + $list = dol_eval($this->attributes[$extrafieldsobjectkey]['list'][$key], 1); + $help = $this->attributes[$extrafieldsobjectkey]['help'][$key]; + $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) + } + else // Old usage + { + //dol_syslog("Warning: parameter 'extrafieldsobjectkey' is missing", LOG_WARNING); + $label = $this->attribute_label[$key]; + $type = $this->attribute_type[$key]; + $size = $this->attribute_size[$key]; + $default = $this->attribute_default[$key]; + $computed = $this->attribute_computed[$key]; + $unique = $this->attribute_unique[$key]; + $required = $this->attribute_required[$key]; + $param = $this->attribute_param[$key]; + $perms = dol_eval($this->attribute_perms[$key], 1); + $langfile = $this->attribute_langfile[$key]; + $list = dol_eval($this->attribute_list[$key], 1); + $help = ''; // Not supported with old syntax + $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) + } + + if ($hidden) return ''; // This is a protection. If field is hidden, we should just not call this method. + + //if ($computed) $value = // $value is already calculated into $value before calling this method + + $showsize = 0; + if ($type == 'date') + { + $showsize = 10; + $value = dol_print_date($value, 'day'); + } + elseif ($type == 'datetime') + { + $showsize = 19; + $value = dol_print_date($value, 'dayhour'); + } + elseif ($type == 'int') + { + $showsize = 10; + } + elseif ($type == 'double') + { + if (!empty($value)) { + //$value=price($value); + $sizeparts = explode(",", $size); + $number_decimals = $sizeparts[1]; + $value = price($value, 0, $langs, 0, 0, $number_decimals, ''); + } + } + elseif ($type == 'boolean') + { + $checked = ''; + if (!empty($value)) { + $checked = ' checked '; + } + $value = ''; + } + elseif ($type == 'mail') + { + $value = dol_print_email($value, 0, 0, 0, 64, 1, 1); + } + elseif ($type == 'url') + { + $value = dol_print_url($value, '_blank', 32, 1); + } + elseif ($type == 'phone') + { + $value = dol_print_phone($value, '', 0, 0, '', ' ', 'phone'); + } + elseif ($type == 'price') + { + $value = price($value, 0, $langs, 0, 0, -1, $conf->currency); + } + elseif ($type == 'select') + { + if ($langfile && $param['options'][$value]) $value = $langs->trans($param['options'][$value]); + else $value = $param['options'][$value]; + } + elseif ($type == 'sellist') + { + $param_list = array_keys($param['options']); + $InfoFieldList = explode(":", $param_list[0]); + + $selectkey = "rowid"; + $keyList = 'rowid'; + + if (count($InfoFieldList) >= 3) + { + $selectkey = $InfoFieldList[2]; + $keyList = $InfoFieldList[2].' as rowid'; + } + + $fields_label = explode('|', $InfoFieldList[1]); + if (is_array($fields_label)) { + $keyList .= ', '; + $keyList .= implode(', ', $fields_label); + } + + $sql = 'SELECT '.$keyList; + $sql .= ' FROM '.MAIN_DB_PREFIX.$InfoFieldList[0]; + if (strpos($InfoFieldList[4], 'extra') !== false) + { + $sql .= ' as main'; + } + if ($selectkey == 'rowid' && empty($value)) { + $sql .= " WHERE ".$selectkey."=0"; + } elseif ($selectkey == 'rowid') { + $sql .= " WHERE ".$selectkey."=".$this->db->escape($value); + } else { + $sql .= " WHERE ".$selectkey."='".$this->db->escape($value)."'"; + } + + //$sql.= ' AND entity = '.$conf->entity; + + dol_syslog(get_class($this).':showOutputField:$type=sellist', LOG_DEBUG); + $resql = $this->db->query($sql); + if ($resql) + { + $value = ''; // value was used, so now we reste it to use it to build final output + + $obj = $this->db->fetch_object($resql); + + // Several field into label (eq table:code|libelle:rowid) + $fields_label = explode('|', $InfoFieldList[1]); + + if (is_array($fields_label) && count($fields_label) > 1) + { + foreach ($fields_label as $field_toshow) + { + $translabel = ''; + if (!empty($obj->$field_toshow)) { + $translabel = $langs->trans($obj->$field_toshow); + } + if ($translabel != $field_toshow) { + $value .= dol_trunc($translabel, 18).' '; + } else { + $value .= $obj->$field_toshow.' '; + } + } + } + else + { + $translabel = ''; + if (!empty($obj->{$InfoFieldList[1]})) { + $translabel = $langs->trans($obj->{$InfoFieldList[1]}); + } + if ($translabel != $obj->{$InfoFieldList[1]}) { + $value = dol_trunc($translabel, 18); + } else { + $value = $obj->{$InfoFieldList[1]}; + } + } + } + else dol_syslog(get_class($this).'::showOutputField error '.$this->db->lasterror(), LOG_WARNING); + } + elseif ($type == 'radio') + { + $value = $param['options'][$value]; + } + elseif ($type == 'checkbox') + { + $value_arr = explode(',', $value); + $value = ''; + $toprint = array(); + if (is_array($value_arr)) + { + foreach ($value_arr as $keyval=>$valueval) { + $toprint[] = '
  • '.$param['options'][$valueval].'
  • '; + } + } + $value = '
      '.implode(' ', $toprint).'
    '; + } + elseif ($type == 'chkbxlst') + { + $value_arr = explode(',', $value); + + $param_list = array_keys($param['options']); + $InfoFieldList = explode(":", $param_list[0]); + + $selectkey = "rowid"; + $keyList = 'rowid'; + + if (count($InfoFieldList) >= 3) { + $selectkey = $InfoFieldList[2]; + $keyList = $InfoFieldList[2].' as rowid'; + } + + $fields_label = explode('|', $InfoFieldList[1]); + if (is_array($fields_label)) { + $keyList .= ', '; + $keyList .= implode(', ', $fields_label); + } + + $sql = 'SELECT '.$keyList; + $sql .= ' FROM '.MAIN_DB_PREFIX.$InfoFieldList[0]; + if (strpos($InfoFieldList[4], 'extra') !== false) { + $sql .= ' as main'; + } + // $sql.= " WHERE ".$selectkey."='".$this->db->escape($value)."'"; + // $sql.= ' AND entity = '.$conf->entity; + + dol_syslog(get_class($this).':showOutputField:$type=chkbxlst', LOG_DEBUG); + $resql = $this->db->query($sql); + if ($resql) { + $value = ''; // value was used, so now we reste it to use it to build final output + $toprint = array(); + while ($obj = $this->db->fetch_object($resql)) { + // Several field into label (eq table:code|libelle:rowid) + $fields_label = explode('|', $InfoFieldList[1]); + if (is_array($value_arr) && in_array($obj->rowid, $value_arr)) { + if (is_array($fields_label) && count($fields_label) > 1) { + foreach ($fields_label as $field_toshow) { + $translabel = ''; + if (!empty($obj->$field_toshow)) { + $translabel = $langs->trans($obj->$field_toshow); + } + if ($translabel != $field_toshow) { + $toprint[] = '
  • '.dol_trunc($translabel, 18).'
  • '; + } else { + $toprint[] = '
  • '.$obj->$field_toshow.'
  • '; + } + } + } else { + $translabel = ''; + if (!empty($obj->{$InfoFieldList[1]})) { + $translabel = $langs->trans($obj->{$InfoFieldList[1]}); + } + if ($translabel != $obj->{$InfoFieldList[1]}) { + $toprint[] = '
  • '.dol_trunc($translabel, 18).'
  • '; + } else { + $toprint[] = '
  • '.$obj->{$InfoFieldList[1]}.'
  • '; + } + } + } + } + $value = '
      '.implode(' ', $toprint).'
    '; + } else { + dol_syslog(get_class($this).'::showOutputField error '.$this->db->lasterror(), LOG_WARNING); + } + } + elseif ($type == 'link') + { + $out = ''; + + // Only if something to display (perf) + if ($value) // If we have -1 here, pb is into insert, not into ouptut (fix insert instead of changing code here to compensate) + { + $param_list = array_keys($param['options']); // $param_list='ObjectName:classPath' + + $InfoFieldList = explode(":", $param_list[0]); + $classname = $InfoFieldList[0]; + $classpath = $InfoFieldList[1]; + if (!empty($classpath)) + { + dol_include_once($InfoFieldList[1]); + if ($classname && class_exists($classname)) + { + $object = new $classname($this->db); + $object->fetch($value); + $value = $object->getNomUrl(3); + } + } + else + { + dol_syslog('Error bad setup of extrafield', LOG_WARNING); + return 'Error bad setup of extrafield'; + } + } + } + elseif ($type == 'text') + { + $value = dol_htmlentitiesbr($value); + } + elseif ($type == 'html') + { + $value = dol_htmlentitiesbr($value); + } + elseif ($type == 'password') + { + $value = dol_trunc(preg_replace('/./i', '*', $value), 8, 'right', 'UTF-8', 1); + } + else + { + $showsize = round($size); + if ($showsize > 48) $showsize = 48; + } + + //print $type.'-'.$size; + $out = $value; + + return $out; + } + + /** + * Return tag to describe alignement to use for this extrafield + * + * @param string $key Key of attribute + * @param string $extrafieldsobjectkey If defined, use the new method to get extrafields data + * @return string Formated value + */ + public function getAlignFlag($key, $extrafieldsobjectkey = '') + { + global $conf, $langs; + + if (!empty($extrafieldsobjectkey)) $type = $this->attributes[$extrafieldsobjectkey]['type'][$key]; + else $type = $this->attribute_type[$key]; + + $align = ''; + + if ($type == 'date') + { + $align = "center"; + } + elseif ($type == 'datetime') + { + $align = "center"; + } + elseif ($type == 'int') + { + $align = "right"; + } + elseif ($type == 'price') + { + $align="right"; + } + elseif ($type == 'double') + { + $align = "right"; + } + elseif ($type == 'boolean') + { + $align = "center"; + } + elseif ($type == 'radio') + { + $align = "center"; + } + elseif ($type == 'checkbox') + { + $align = "center"; + } + elseif ($type == 'price') + { + $align = "right"; + } + + return $align; + } + + /** + * Return HTML string to print separator extrafield + * + * @param string $key Key of attribute + * @param string $object Object + * @param int $colspan Value of colspan to use (it must includes the first column with title) + * @return string HTML code with line for separator + */ + public function showSeparator($key, $object, $colspan = 2) + { + global $langs; + + $out = ''; + $out .= $langs->trans($this->attributes[$object->table_element]['label'][$key]); + $out .= ''; + + $extrafield_param = $this->attributes[$object->table_element]['param'][$key]; + if (!empty($extrafield_param) && is_array($extrafield_param)) { + $extrafield_param_list = array_keys($extrafield_param['options']); + + if (count($extrafield_param_list) > 0) { + $extrafield_collapse_display_value = intval($extrafield_param_list[0]); + if ($extrafield_collapse_display_value == 1 || $extrafield_collapse_display_value == 2) { + // Set the collapse_display status to cookie in priority or if ignorecollapsesetup is 1, if cookie and ignorecollapsesetup not defined, use the setup. + $collapse_display = ((isset($_COOKIE['DOLCOLLAPSE_'.$object->table_element.'_extrafields_'.$key]) || GETPOST('ignorecollapsesetup', 'int')) ? ($_COOKIE['DOLCOLLAPSE_'.$object->table_element.'_extrafields_'.$key] ? true : false) : ($extrafield_collapse_display_value == 2 ? false : true)); + $extrafields_collapse_num = $this->attributes[$object->table_element]['pos'][$key]; + + $out .= ''; + $out .= ''; + } + } + } + + return $out; + } + + /** + * Fill array_options property of object by extrafields value (using for data sent by forms) + * + * @param array $extralabels Deprecated (old $array of extrafields, now set this to null) + * @param object $object Object + * @param string $onlykey Only the following key is filled. When we make update of only one extrafield ($action = 'update_extras'), calling page must set this to avoid to have other extrafields being reset. + * @return int 1 if array_options set, 0 if no value, -1 if error (field required missing for example) + */ + public function setOptionalsFromPost($extralabels, &$object, $onlykey = '') + { + global $_POST, $langs; + + $nofillrequired = 0; // For error when required field left blank + $error_field_required = array(); + + if (is_array($this->attributes[$object->table_element]['label'])) $extralabels = $this->attributes[$object->table_element]['label']; + + if (is_array($extralabels)) + { + // Get extra fields + foreach ($extralabels as $key => $value) + { + if (!empty($onlykey) && $key != $onlykey) continue; + + $key_type = $this->attributes[$object->table_element]['type'][$key]; + if ($key_type == 'separate') continue; + + $enabled = 1; + if (isset($this->attributes[$object->table_element]['list'][$key])) + { + $enabled = dol_eval($this->attributes[$object->table_element]['list'][$key], 1); + } + $perms = 1; + if (isset($this->attributes[$object->table_element]['perms'][$key])) + { + $perms = dol_eval($this->attributes[$object->table_element]['perms'][$key], 1); + } + if (empty($enabled)) continue; + if (empty($perms)) continue; + + if ($this->attributes[$object->table_element]['required'][$key]) // Value is required + { + // Check if empty without using GETPOST, value can be alpha, int, array, etc... + if ((!is_array($_POST["options_".$key]) && empty($_POST["options_".$key]) && $this->attributes[$object->table_element]['type'][$key] != 'select' && $_POST["options_".$key] != '0') + || (!is_array($_POST["options_".$key]) && empty($_POST["options_".$key]) && $this->attributes[$object->table_element]['type'][$key] == 'select') + || (is_array($_POST["options_".$key]) && empty($_POST["options_".$key]))) + { + //print 'ccc'.$value.'-'.$this->attributes[$object->table_element]['required'][$key]; + $nofillrequired++; + $error_field_required[] = $langs->transnoentitiesnoconv($value); + } + } + + if (in_array($key_type, array('date'))) + { + // Clean parameters + // TODO GMT date in memory must be GMT so we should add gm=true in parameters + $value_key = dol_mktime(0, 0, 0, $_POST["options_".$key."month"], $_POST["options_".$key."day"], $_POST["options_".$key."year"]); + } + elseif (in_array($key_type, array('datetime'))) + { + // Clean parameters + // TODO GMT date in memory must be GMT so we should add gm=true in parameters + $value_key = dol_mktime($_POST["options_".$key."hour"], $_POST["options_".$key."min"], 0, $_POST["options_".$key."month"], $_POST["options_".$key."day"], $_POST["options_".$key."year"]); + } + elseif (in_array($key_type, array('checkbox', 'chkbxlst'))) + { + $value_arr = GETPOST("options_".$key, 'array'); // check if an array + if (!empty($value_arr)) { + $value_key = implode($value_arr, ','); + } else { + $value_key = ''; + } + } + elseif (in_array($key_type, array('price', 'double'))) + { + $value_arr = GETPOST("options_".$key, 'alpha'); + $value_key = price2num($value_arr); + } + else + { + $value_key = GETPOST("options_".$key); + if (in_array($key_type, array('link')) && $value_key == '-1') $value_key = ''; + } + + $object->array_options["options_".$key] = $value_key; + } + + if ($nofillrequired) { + $langs->load('errors'); + setEventMessages($langs->trans('ErrorFieldsRequired').' : '.implode(', ', $error_field_required), null, 'errors'); + return -1; + } + else { + return 1; + } + } + else { + return 0; + } + } + + /** + * return array_options array of data of extrafields value of object sent by a search form + * + * @param array|string $extrafieldsobjectkey array of extrafields (old usage) or value of object->table_element (new usage) + * @param string $keyprefix Prefix string to add into name and id of field (can be used to avoid duplicate names) + * @param string $keysuffix Suffix string to add into name and id of field (can be used to avoid duplicate names) + * @return array|int array_options set or 0 if no value + */ + public function getOptionalsFromPost($extrafieldsobjectkey, $keyprefix = '', $keysuffix = '') + { + global $_POST; + + if (is_string($extrafieldsobjectkey) && is_array($this->attributes[$extrafieldsobjectkey]['label'])) + { + $extralabels = $this->attributes[$extrafieldsobjectkey]['label']; + } + else + { + $extralabels = $extrafieldsobjectkey; + } + + if (is_array($extralabels)) + { + $array_options = array(); + + // Get extra fields + foreach ($extralabels as $key => $value) + { + $key_type = ''; + if (is_string($extrafieldsobjectkey)) + { + $key_type = $this->attributes[$extrafieldsobjectkey]['type'][$key]; + } + + if (in_array($key_type, array('date', 'datetime'))) + { + if (!GETPOSTISSET($keysuffix."options_".$key.$keyprefix."year")) continue; // Value was not provided, we should not set it. + // Clean parameters + $value_key = dol_mktime(GETPOST($keysuffix."options_".$key.$keyprefix."hour", 'int'), GETPOST($keysuffix."options_".$key.$keyprefix."min", 'int'), 0, GETPOST($keysuffix."options_".$key.$keyprefix."month", 'int'), GETPOST($keysuffix."options_".$key.$keyprefix."day", 'int'), GETPOST($keysuffix."options_".$key.$keyprefix."year", 'int')); + } + elseif (in_array($key_type, array('checkbox', 'chkbxlst'))) + { + if (!GETPOSTISSET($keysuffix."options_".$key.$keyprefix)) continue; // Value was not provided, we should not set it. + $value_arr = GETPOST($keysuffix."options_".$key.$keyprefix); + // Make sure we get an array even if there's only one checkbox + $value_arr = (array) $value_arr; + $value_key = implode(',', $value_arr); + } + elseif (in_array($key_type, array('price', 'double', 'int'))) + { + if (!GETPOSTISSET($keysuffix."options_".$key.$keyprefix)) continue; // Value was not provided, we should not set it. + $value_arr = GETPOST($keysuffix."options_".$key.$keyprefix); + $value_key = price2num($value_arr); + } + else + { + if (!GETPOSTISSET($keysuffix."options_".$key.$keyprefix)) continue; // Value was not provided, we should not set it. + $value_key = GETPOST($keysuffix."options_".$key.$keyprefix); + } + + $array_options[$keysuffix."options_".$key] = $value_key; // No keyprefix here. keyprefix is used only for read. + } + + return $array_options; + } + + return 0; + } +} diff --git a/htdocs/core/class/html.form.class.php b/htdocs/core/class/html.form.class.php index 7404b3c6945..0b8185b3854 100644 --- a/htdocs/core/class/html.form.class.php +++ b/htdocs/core/class/html.form.class.php @@ -329,12 +329,24 @@ class Form */ public function widgetForTranslation($fieldname, $object, $perm, $typeofdata = 'string', $check = '', $morecss = '') { - global $conf, $langs; + global $conf, $langs, $extralanguages; $result = ''; - if (! empty($conf->global->PDF_USE_ALSO_LANGUAGE_CODE)) { - $langcode = $conf->global->PDF_USE_ALSO_LANGUAGE_CODE; + // List of extra languages + $arrayoflangcode = array(); + if (! empty($conf->global->PDF_USE_ALSO_LANGUAGE_CODE)) $arrayoflangcode[] = $conf->global->PDF_USE_ALSO_LANGUAGE_CODE; + + if (is_array($arrayoflangcode) && count($arrayoflangcode)) { + if (! is_object($extralanguages)) { + include_once DOL_DOCUMENT_ROOT.'/core/class/extralanguages.class.php'; + $extralanguages = new ExtraLanguages($this->db); + } + $extralanguages->fetch_name_extralanguages('societe'); + + if (! is_array($extralanguages->attributes[$object->element]) || empty($extralanguages->attributes[$object->element][$fieldname])) { + return ''; // No extralang field to show + } $result .='
    '; $s=img_picto($langs->trans("ShowOtherLanguages"), 'language', '', false, 0, 0, '', 'fa-15 editfieldlang'); @@ -343,22 +355,28 @@ class Form $result .=''; $result .= ''; } @@ -7260,7 +7278,7 @@ class Form */ public function showrefnav($object, $paramid, $morehtml = '', $shownav = 1, $fieldid = 'rowid', $fieldref = 'ref', $morehtmlref = '', $moreparam = '', $nodbprefix = 0, $morehtmlleft = '', $morehtmlstatus = '', $morehtmlright = '') { - global $langs, $conf, $hookmanager; + global $langs, $conf, $hookmanager, $extralanguages; $ret = ''; if (empty($fieldid)) $fieldid = 'rowid'; @@ -7360,16 +7378,24 @@ class Form { $ret .= dol_htmlentities($object->name); - $useextralanguages = $conf->global->PDF_USE_ALSO_LANGUAGE_CODE; - if ($useextralanguages) { - $object->fetchValuesForExtraLanguages(); - $extralanguages = array(); - if (isset($object->array_languages['name'])) $extralanguages[] = reset(array_keys($object->array_languages['name'])); + // List of extra languages + $arrayoflangcode = array(); + if (! empty($conf->global->PDF_USE_ALSO_LANGUAGE_CODE)) $arrayoflangcode[] = $conf->global->PDF_USE_ALSO_LANGUAGE_CODE; + + if (is_array($arrayoflangcode) && count($arrayoflangcode)) { + if (! is_object($extralanguages)) { + include_once DOL_DOCUMENT_ROOT.'/core/class/extralanguages.class.php'; + $extralanguages = new ExtraLanguages($this->db); + } + $extralanguages->fetch_name_extralanguages('societe'); + + if (! empty($extralanguages->attributes['societe']['name'])) + { + $object->fetchValuesForExtraLanguages(); - if (is_array($extralanguages) && count($extralanguages)) { $htmltext = ''; // If there is extra languages - foreach($extralanguages as $extralangcode) { + foreach($arrayoflangcode as $extralangcode) { $s=picto_from_langcode($extralangcode, 'class="pictoforlang paddingright"'); $htmltext .= $s.$object->array_languages['name'][$extralangcode]; }