diff --git a/htdocs/api/class/api_setup.class.php b/htdocs/api/class/api_setup.class.php index 42a398ee3b52c..ddc38a004bdb6 100644 --- a/htdocs/api/class/api_setup.class.php +++ b/htdocs/api/class/api_setup.class.php @@ -1232,6 +1232,91 @@ public function deleteExtrafieldsFromNames($attrname, $elementtype) ); } + /** + * Update Extrafield object + * + * @param string $attrname extrafield attrname + * @param string $elementtype extrafield elementtype + * @param array $request_data Request datas + * @return int ID of extrafield + * + * @url PUT extrafields/{elementtype}/{attrname} + * + * @suppress PhanPluginUnknownArrayMethodParamType Luracast limitation + * + */ + public function updateExtrafields($attrname, $elementtype, $request_data = null) + { + if (!DolibarrApiAccess::$user->admin) { + throw new RestException(403, 'Only an admin user can create an extrafield'); + } + + $extrafields = new ExtraFields($this->db); + + $result = $extrafields->fetch_name_optionals_label($elementtype, false, $attrname); + if (!$result) { + throw new RestException(404, 'Extrafield not found from attrname and elementtype'); + } + + foreach ($request_data as $field => $value) { + $extrafields->$field = $this->_checkValForAPI($field, $value, $extrafields); + } + + // built in validation + $enabled = 1; // hardcoded because it seems to always be 1 in every row in the database + if ($request_data['entity']) { + $entity = $request_data['entity']; + } else { + throw new RestException(400, "Entity field absent"); + } + if ($request_data['label']) { + $label = $request_data['label']; + } else { + throw new RestException(400, "label field absent"); + } + + $alwayseditable = $request_data['alwayseditable']; + $default_value = $request_data['default_value']; + $totalizable = $request_data['totalizable']; + $printable = $request_data['printable']; + $required = $request_data['required']; + $langfile = $request_data['langfile']; + $computed = $request_data['computed']; + $unique = $request_data['unique']; + $param = $request_data['param']; + $perms = $request_data['perms']; + $size = $request_data['size']; + $type = $request_data['type']; + $list = $request_data['list']; + $help = $request_data['help']; + $pos = $request_data['pos']; + $moreparams = array(); + + dol_syslog(get_class($this).'::updateExtraField', LOG_DEBUG); + if ( 0 > $extrafields->updateExtraField($attrname, $label, $type, $pos, $size, $elementtype, $unique, $required, $default_value, $param, $alwayseditable, $perms, $list, $help, $computed, $entity, $langfile, $enabled, $totalizable, $printable, $moreparams)) { + throw new RestException(500, 'Error updating extrafield', array_merge(array($extrafields->errno), $extrafields->errors)); + } + + $sql = "SELECT t.rowid as id"; + $sql .= " FROM ".MAIN_DB_PREFIX."extrafields as t"; + $sql .= " WHERE elementtype = '".$this->db->escape($elementtype)."'"; + $sql .= " AND name = '".$this->db->escape($attrname)."'"; + + $resql = $this->db->query($sql); + if ($resql) { + if ($this->db->num_rows($resql)) { + $tab = $this->db->fetch_object($resql); + $id = (int) $tab->id; + } else { + $id = (int) -1; + } + } else { + $id = (int) -2; + } + + return $id; + } + /** * Get the list of towns. * diff --git a/htdocs/core/class/extrafields.class.php b/htdocs/core/class/extrafields.class.php index 32147ed912263..960f825300657 100644 --- a/htdocs/core/class/extrafields.class.php +++ b/htdocs/core/class/extrafields.class.php @@ -182,6 +182,78 @@ public function addExtraField($attrname, $label, $type, $pos, $size, $elementtyp } } + /** + * Update an existing extra field parameter + * + * @param string $attrname Code of attribute + * @param string $label label of attribute + * @param string $type Type of attribute ('boolean','int','varchar','text','html','date','datetime','price', 'pricecy', 'phone','mail','password','url','select','checkbox','separate',...) + * @param int $pos Position of attribute + * @param string $size Size/length definition of attribute ('5', '24,8', ...). For float, it contains 2 numeric separated with a comma. + * @param string $elementtype Element type. Same value than object->table_element (Example 'member', 'product', 'thirdparty', ...) + * @param int $unique Is field unique or not + * @param int $required Is field required or not + * @param string $default_value Defaulted value (In database. use the default_value feature for default value on screen. Example: '', '0', 'null', 'avalue') + * @param array|string $param Params for field (ex for select list : array('options' => array(value'=>'label of option')) ) + * @param int $alwayseditable Is attribute always editable regardless of the document status + * @param string $perms Permission to check + * @param string $list Visibility ('0'=never visible, '1'=visible on list+forms, '2'=list only, '3'=form only or 'eval string') + * @param string $help Text with help tooltip + * @param string $computed Computed value + * @param string $entity Entity of extrafields (for multicompany modules) + * @param string $langfile Language file + * @param string $enabled Condition to have the field enabled or not + * @param int $totalizable Is a measure. Must show a total on lists + * @param int $printable Is extrafield displayed on PDF + * @param array $moreparams More parameters. Example: array('css'=>, 'csslist'=>Css on list, 'cssview'=>...) + * @return int Return integer <=0 if KO, >0 if OK + */ + public function updateExtraField($attrname, $label, $type, $pos, $size, $elementtype, $unique = 0, $required = 0, $default_value = '', $param = '', $alwayseditable = 0, $perms = '', $list = '-1', $help = '', $computed = '', $entity = '', $langfile = '', $enabled = '1', $totalizable = 0, $printable = 0, $moreparams = array()) + { + if (empty($attrname)) { + return -1; + } + if (empty($label)) { + return -1; + } + + $result = 0; + + if ($type == 'separator' || $type == 'separate') { + $type = 'separate'; + $unique = 0; + $required = 0; + } // Force unique and not required if this is a separator field to avoid troubles. + if ($elementtype == 'thirdparty') { + $elementtype = 'societe'; + } + if ($elementtype == 'contact') { + $elementtype = 'socpeople'; + } + + // Create field into database except for separator type which is not stored in database + if ($type != 'separate') { + dol_syslog(get_class($this).'::thisupdate', LOG_DEBUG); + $result = $this->update($attrname, $label, $type, $size, $elementtype, $unique, $required, $pos, $param, $alwayseditable, $perms, $list, $help, $default_value, $computed, $entity, $langfile, $enabled, $totalizable, $printable, $moreparams); + } + $err1 = $this->errno; + if ($result > 0 || $err1 == 'DB_ERROR_COLUMN_ALREADY_EXISTS' || $type == 'separate') { + // Add declaration of field into table + dol_syslog(get_class($this).'::thislabel', LOG_DEBUG); + $result2 = $this->update_label($attrname, $label, $type, $size, $elementtype, $unique, $required, $pos, $param, $alwayseditable, $perms, $list, $help, $default_value, $computed, $entity, $langfile, $enabled, $totalizable, $printable, $moreparams); + $err2 = $this->errno; + if ($result2 > 0 || ($err1 == 'DB_ERROR_COLUMN_ALREADY_EXISTS' && $err2 == 'DB_ERROR_RECORD_ALREADY_EXISTS')) { + $this->error = ''; + $this->errno = '0'; + return 1; + } else { + return -2; + } + } else { + return -1; + } + } + /** * Add a new optional attribute. * This is a private method. For public method, use addExtraField. @@ -418,10 +490,11 @@ private function create_label($attrname, $label = '', $type = '', $pos = 0, $siz $sql .= " ".($cssview ? "'".$this->db->escape($cssview)."'" : "null"); $sql .= ')'; - dol_syslog(get_class($this)."::create_label", LOG_DEBUG); if ($this->db->query($sql)) { + dol_syslog(get_class($this)."::create_label_success", LOG_DEBUG); return 1; } else { + dol_syslog(get_class($this)."::create_label_error", LOG_DEBUG); $this->error = $this->db->lasterror(); $this->errno = $this->db->lasterrno(); return -1; @@ -617,19 +690,23 @@ public function update($attrname, $label, $type, $length, $elementtype, $unique } } + dol_syslog(get_class($this).'::DDLUpdateField', LOG_DEBUG); if ($type != 'separate') { // No table update when separate type $result = $this->db->DDLUpdateField($this->db->prefix().$table, $attrname, $field_desc); } if ($result > 0 || $type == 'separate') { if ($label) { + dol_syslog(get_class($this).'::update_label', LOG_DEBUG); $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); } if ($result > 0) { $sql = ''; if ($unique) { - $sql = "ALTER TABLE ".$this->db->prefix().$table." ADD UNIQUE INDEX uk_".$table."_".$attrname." (".$attrname.")"; + dol_syslog(get_class($this).'::update_unique', LOG_DEBUG); + $sql = "ALTER TABLE ".$this->db->prefix().$table." ADD UNIQUE INDEX uk_".$table."_".$this->db->sanitize($attrname)." (".$this->db->sanitize($attrname).")"; } else { - $sql = "ALTER TABLE ".$this->db->prefix().$table." DROP INDEX IF EXISTS uk_".$table."_".$attrname; + dol_syslog(get_class($this).'::update_common', LOG_DEBUG); + $sql = "ALTER TABLE ".$this->db->prefix().$table." DROP INDEX IF EXISTS uk_".$table."_".$this->db->sanitize($attrname); } dol_syslog(get_class($this).'::update', LOG_DEBUG); $resql = $this->db->query($sql, 1, 'dml'); @@ -654,6 +731,7 @@ public function update($attrname, $label, $type, $length, $elementtype, $unique // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps /** * Modify description of personalized attribute + * This is a private method. For public method, use updateExtraField. * * @param string $attrname Name of attribute * @param string $label Label of attribute