forked from Wavyzz/dolibarr
Fix/140/t250062/extrafields multicompany data loss (#34022)
* insertExtrafields(): simplify by returning 0 early if array_options is empty * insertExtrafields(): simplify by using local variables $newValue and $attributeType * insertExtrafields(): refactor by grouping the empty value cases for geodatabase-type extrafields * insertExtrafields(): refactor by using a static mapping of geodata types to their ST_* db function on ExtraField class * FIX: when an object that is shared across multiple entities already has some extrafields from another entity that are not reachable from the current entity, their values are lost * Compliance with - phan ( Closure Closure($key) has no declared or inferred parameter type for $key) - php-stan (Error: Property ExtraFields::$geoDataTypes has no type specified)
This commit is contained in:
@@ -6704,7 +6704,7 @@ abstract class CommonObject
|
||||
{
|
||||
global $langs, $user;
|
||||
|
||||
if (getDolGlobalString('MAIN_EXTRAFIELDS_DISABLED')) {
|
||||
if (getDolGlobalString('MAIN_EXTRAFIELDS_DISABLED') || empty($this->array_options)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -6714,349 +6714,318 @@ abstract class CommonObject
|
||||
|
||||
$error = 0;
|
||||
|
||||
if (!empty($this->array_options)) {
|
||||
// Check parameters
|
||||
$langs->load('admin');
|
||||
require_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php';
|
||||
$extrafields = new ExtraFields($this->db);
|
||||
$target_extrafields = $extrafields->fetch_name_optionals_label($this->table_element);
|
||||
// Check parameters
|
||||
$langs->load('admin');
|
||||
require_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php';
|
||||
$extrafields = new ExtraFields($this->db);
|
||||
$target_extrafields = $extrafields->fetch_name_optionals_label($this->table_element);
|
||||
|
||||
// Eliminate copied source object extra fields that do not exist in target object
|
||||
$new_array_options = array();
|
||||
foreach ($this->array_options as $key => $value) {
|
||||
if (in_array(substr($key, 8), array_keys($target_extrafields))) { // We remove the 'options_' from $key for test
|
||||
$new_array_options[$key] = $value;
|
||||
} elseif (in_array($key, array_keys($target_extrafields))) { // We test on $key that does not contain the 'options_' prefix
|
||||
$new_array_options['options_'.$key] = $value;
|
||||
// Eliminate copied source object extra fields that do not exist in target object
|
||||
$new_array_options = array();
|
||||
foreach ($this->array_options as $key => $value) {
|
||||
if (in_array(substr($key, 8), array_keys($target_extrafields))) { // We remove the 'options_' from $key for test
|
||||
$new_array_options[$key] = $value;
|
||||
} elseif (in_array($key, array_keys($target_extrafields))) { // We test on $key that does not contain the 'options_' prefix
|
||||
$new_array_options['options_'.$key] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($new_array_options as $key => $value) {
|
||||
$attributeKey = substr($key, 8); // Remove 'options_' prefix
|
||||
$attributeType = $extrafields->attributes[$this->table_element]['type'][$attributeKey];
|
||||
$attributeLabel = $langs->transnoentities($extrafields->attributes[$this->table_element]['label'][$attributeKey]);
|
||||
$attributeParam = $extrafields->attributes[$this->table_element]['param'][$attributeKey];
|
||||
$attributeRequired = $extrafields->attributes[$this->table_element]['required'][$attributeKey];
|
||||
$attributeUnique = $extrafields->attributes[$this->table_element]['unique'][$attributeKey];
|
||||
$attrfieldcomputed = $extrafields->attributes[$this->table_element]['computed'][$attributeKey];
|
||||
|
||||
// If we clone, we have to clean unique extrafields to prevent duplicates.
|
||||
// This behaviour can be prevented by external code by changing $this->context['createfromclone'] value in createFrom hook
|
||||
if (!empty($this->context['createfromclone']) && $this->context['createfromclone'] == 'createfromclone' && !empty($attributeUnique)) {
|
||||
$new_array_options[$key] = null;
|
||||
}
|
||||
|
||||
// If we create product combination, we have to clean unique extrafields to prevent duplicates.
|
||||
// This behaviour can be prevented by external code by changing $this->context['createproductcombination'] value in hook
|
||||
if (!empty($this->context['createproductcombination']) && $this->context['createproductcombination'] == 'createproductcombination' && !empty($attributeUnique)) {
|
||||
$new_array_options[$key] = null;
|
||||
}
|
||||
|
||||
// Similar code than into insertExtraFields
|
||||
if ($attributeRequired) {
|
||||
$v = $this->array_options[$key];
|
||||
if (ExtraFields::isEmptyValue($v, $attributeType)) {
|
||||
$langs->load("errors");
|
||||
dol_syslog("Mandatory field '".$key."' is empty during create and set to required into definition of extrafields");
|
||||
$this->errors[] = $langs->trans('ErrorFieldRequired', $attributeLabel);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($new_array_options as $key => $value) {
|
||||
$attributeKey = substr($key, 8); // Remove 'options_' prefix
|
||||
$attributeType = $extrafields->attributes[$this->table_element]['type'][$attributeKey];
|
||||
$attributeLabel = $langs->transnoentities($extrafields->attributes[$this->table_element]['label'][$attributeKey]);
|
||||
$attributeParam = $extrafields->attributes[$this->table_element]['param'][$attributeKey];
|
||||
$attributeRequired = $extrafields->attributes[$this->table_element]['required'][$attributeKey];
|
||||
$attributeUnique = $extrafields->attributes[$this->table_element]['unique'][$attributeKey];
|
||||
$attrfieldcomputed = $extrafields->attributes[$this->table_element]['computed'][$attributeKey];
|
||||
|
||||
// If we clone, we have to clean unique extrafields to prevent duplicates.
|
||||
// This behaviour can be prevented by external code by changing $this->context['createfromclone'] value in createFrom hook
|
||||
if (!empty($this->context['createfromclone']) && $this->context['createfromclone'] == 'createfromclone' && !empty($attributeUnique)) {
|
||||
if (!empty($attrfieldcomputed)) {
|
||||
if (getDolGlobalString('MAIN_STORE_COMPUTED_EXTRAFIELDS')) {
|
||||
$value = dol_eval($attrfieldcomputed, 1, 0, '2');
|
||||
dol_syslog($langs->trans("Extrafieldcomputed")." on ".$attributeLabel."(".$value.")", LOG_DEBUG);
|
||||
$new_array_options[$key] = $value;
|
||||
} else {
|
||||
$new_array_options[$key] = null;
|
||||
}
|
||||
}
|
||||
|
||||
// If we create product combination, we have to clean unique extrafields to prevent duplicates.
|
||||
// This behaviour can be prevented by external code by changing $this->context['createproductcombination'] value in hook
|
||||
if (!empty($this->context['createproductcombination']) && $this->context['createproductcombination'] == 'createproductcombination' && !empty($attributeUnique)) {
|
||||
$new_array_options[$key] = null;
|
||||
}
|
||||
|
||||
// Similar code than into insertExtraFields
|
||||
if ($attributeRequired) {
|
||||
$v = $this->array_options[$key];
|
||||
if (ExtraFields::isEmptyValue($v, $attributeType)) {
|
||||
$langs->load("errors");
|
||||
dol_syslog("Mandatory field '".$key."' is empty during create and set to required into definition of extrafields");
|
||||
$this->errors[] = $langs->trans('ErrorFieldRequired', $attributeLabel);
|
||||
switch ($attributeType) {
|
||||
case 'int':
|
||||
if (!is_numeric($value) && $value != '') {
|
||||
$this->errors[] = $langs->trans("ExtraFieldHasWrongValue", $attributeLabel);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
//dol_syslog("attributeLabel=".$attributeLabel, LOG_DEBUG);
|
||||
//dol_syslog("attributeType=".$attributeType, LOG_DEBUG);
|
||||
|
||||
if (!empty($attrfieldcomputed)) {
|
||||
if (getDolGlobalString('MAIN_STORE_COMPUTED_EXTRAFIELDS')) {
|
||||
$value = dol_eval($attrfieldcomputed, 1, 0, '2');
|
||||
dol_syslog($langs->trans("Extrafieldcomputed")." on ".$attributeLabel."(".$value.")", LOG_DEBUG);
|
||||
$new_array_options[$key] = $value;
|
||||
} else {
|
||||
} elseif ($value == '') {
|
||||
$new_array_options[$key] = null;
|
||||
}
|
||||
}
|
||||
|
||||
switch ($attributeType) {
|
||||
case 'int':
|
||||
if (!is_numeric($value) && $value != '') {
|
||||
$this->errors[] = $langs->trans("ExtraFieldHasWrongValue", $attributeLabel);
|
||||
return -1;
|
||||
} elseif ($value == '') {
|
||||
$new_array_options[$key] = null;
|
||||
}
|
||||
break;
|
||||
case 'price':
|
||||
case 'double':
|
||||
$value = price2num($value);
|
||||
if (!is_numeric($value) && $value != '') {
|
||||
dol_syslog($langs->trans("ExtraFieldHasWrongValue")." for ".$attributeLabel."(".$value."is not '".$attributeType."')", LOG_DEBUG);
|
||||
$this->errors[] = $langs->trans("ExtraFieldHasWrongValue", $attributeLabel);
|
||||
return -1;
|
||||
} elseif ($value == '') {
|
||||
$value = null;
|
||||
}
|
||||
//dol_syslog("double value"." on ".$attributeLabel."(".$value." is '".$attributeType."')", LOG_DEBUG);
|
||||
$new_array_options[$key] = $value;
|
||||
break;
|
||||
/*case 'select': // Not required, we chose value='0' for undefined values
|
||||
if ($value=='-1')
|
||||
{
|
||||
$this->array_options[$key] = null;
|
||||
}
|
||||
break;*/
|
||||
case 'password':
|
||||
$algo = '';
|
||||
if ($this->array_options[$key] != '' && is_array($extrafields->attributes[$this->table_element]['param'][$attributeKey]['options'])) {
|
||||
// If there is an encryption choice, we use it to encrypt data before insert
|
||||
$tmparrays = array_keys($extrafields->attributes[$this->table_element]['param'][$attributeKey]['options']);
|
||||
$algo = reset($tmparrays);
|
||||
if ($algo != '') {
|
||||
//global $action; // $action may be 'create', 'update', 'update_extras'...
|
||||
//var_dump($action);
|
||||
//var_dump($this->oldcopy);exit;
|
||||
if (is_object($this->oldcopy)) { // If this->oldcopy is not defined, we can't know if we change attribute or not, so we must keep value
|
||||
//var_dump('algo='.$algo.' '.$this->oldcopy->array_options[$key].' -> '.$this->array_options[$key]);
|
||||
if (isset($this->oldcopy->array_options[$key]) && $this->array_options[$key] == $this->oldcopy->array_options[$key]) {
|
||||
// If old value encrypted in database is same than submitted new value, it means we don't change it, so we don't update.
|
||||
if ($algo == 'dolcrypt') { // dolibarr reversible encryption
|
||||
if (!preg_match('/^dolcrypt:/', $this->array_options[$key])) {
|
||||
$new_array_options[$key] = dolEncrypt($this->array_options[$key]); // warning, must be called when on the master
|
||||
} else {
|
||||
$new_array_options[$key] = $this->array_options[$key]; // Value is kept
|
||||
}
|
||||
break;
|
||||
case 'price':
|
||||
case 'double':
|
||||
$value = price2num($value);
|
||||
if (!is_numeric($value) && $value != '') {
|
||||
dol_syslog($langs->trans("ExtraFieldHasWrongValue")." for ".$attributeLabel."(".$value."is not '".$attributeType."')", LOG_DEBUG);
|
||||
$this->errors[] = $langs->trans("ExtraFieldHasWrongValue", $attributeLabel);
|
||||
return -1;
|
||||
} elseif ($value == '') {
|
||||
$value = null;
|
||||
}
|
||||
//dol_syslog("double value"." on ".$attributeLabel."(".$value." is '".$attributeType."')", LOG_DEBUG);
|
||||
$new_array_options[$key] = $value;
|
||||
break;
|
||||
/*case 'select': // Not required, we chose value='0' for undefined values
|
||||
if ($value=='-1')
|
||||
{
|
||||
$this->array_options[$key] = null;
|
||||
}
|
||||
break;*/
|
||||
case 'password':
|
||||
$algo = '';
|
||||
if ($this->array_options[$key] != '' && is_array($extrafields->attributes[$this->table_element]['param'][$attributeKey]['options'])) {
|
||||
// If there is an encryption choice, we use it to encrypt data before insert
|
||||
$tmparrays = array_keys($extrafields->attributes[$this->table_element]['param'][$attributeKey]['options']);
|
||||
$algo = reset($tmparrays);
|
||||
if ($algo != '') {
|
||||
//global $action; // $action may be 'create', 'update', 'update_extras'...
|
||||
//var_dump($action);
|
||||
//var_dump($this->oldcopy);exit;
|
||||
if (is_object($this->oldcopy)) { // If this->oldcopy is not defined, we can't know if we change attribute or not, so we must keep value
|
||||
//var_dump('algo='.$algo.' '.$this->oldcopy->array_options[$key].' -> '.$this->array_options[$key]);
|
||||
if (isset($this->oldcopy->array_options[$key]) && $this->array_options[$key] == $this->oldcopy->array_options[$key]) {
|
||||
// If old value encrypted in database is same than submitted new value, it means we don't change it, so we don't update.
|
||||
if ($algo == 'dolcrypt') { // dolibarr reversible encryption
|
||||
if (!preg_match('/^dolcrypt:/', $this->array_options[$key])) {
|
||||
$new_array_options[$key] = dolEncrypt($this->array_options[$key]); // warning, must be called when on the master
|
||||
} else {
|
||||
$new_array_options[$key] = $this->array_options[$key]; // Value is kept
|
||||
}
|
||||
} else {
|
||||
// If value has changed
|
||||
if ($algo == 'dolcrypt') { // dolibarr reversible encryption
|
||||
if (!preg_match('/^dolcrypt:/', $this->array_options[$key])) {
|
||||
$new_array_options[$key] = dolEncrypt($this->array_options[$key]); // warning, must be called when on the master
|
||||
} else {
|
||||
$new_array_options[$key] = $this->array_options[$key]; // Value is kept
|
||||
}
|
||||
} else {
|
||||
$new_array_options[$key] = dol_hash($this->array_options[$key], $algo);
|
||||
}
|
||||
$new_array_options[$key] = $this->array_options[$key]; // Value is kept
|
||||
}
|
||||
} else {
|
||||
//var_dump('jjj'.$algo.' '.$this->oldcopy->array_options[$key].' -> '.$this->array_options[$key]);
|
||||
// If this->oldcopy is not defined, we can't know if we change attribute or not, so we must keep value
|
||||
if ($algo == 'dolcrypt' && !preg_match('/^dolcrypt:/', $this->array_options[$key])) { // dolibarr reversible encryption
|
||||
$new_array_options[$key] = dolEncrypt($this->array_options[$key]); // warning, must be called when on the master
|
||||
// If value has changed
|
||||
if ($algo == 'dolcrypt') { // dolibarr reversible encryption
|
||||
if (!preg_match('/^dolcrypt:/', $this->array_options[$key])) {
|
||||
$new_array_options[$key] = dolEncrypt($this->array_options[$key]); // warning, must be called when on the master
|
||||
} else {
|
||||
$new_array_options[$key] = $this->array_options[$key]; // Value is kept
|
||||
}
|
||||
} else {
|
||||
$new_array_options[$key] = $this->array_options[$key]; // Value is kept
|
||||
$new_array_options[$key] = dol_hash($this->array_options[$key], $algo);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// No encryption
|
||||
$new_array_options[$key] = $this->array_options[$key]; // Value is kept
|
||||
//var_dump('jjj'.$algo.' '.$this->oldcopy->array_options[$key].' -> '.$this->array_options[$key]);
|
||||
// If this->oldcopy is not defined, we can't know if we change attribute or not, so we must keep value
|
||||
if ($algo == 'dolcrypt' && !preg_match('/^dolcrypt:/', $this->array_options[$key])) { // dolibarr reversible encryption
|
||||
$new_array_options[$key] = dolEncrypt($this->array_options[$key]); // warning, must be called when on the master
|
||||
} else {
|
||||
$new_array_options[$key] = $this->array_options[$key]; // Value is kept
|
||||
}
|
||||
}
|
||||
} else { // Common usage
|
||||
} else {
|
||||
// No encryption
|
||||
$new_array_options[$key] = $this->array_options[$key]; // Value is kept
|
||||
}
|
||||
break;
|
||||
case 'date':
|
||||
case 'datetime':
|
||||
// If data is a string instead of a timestamp, we convert it
|
||||
if (!is_numeric($this->array_options[$key]) || $this->array_options[$key] != intval($this->array_options[$key])) {
|
||||
$this->array_options[$key] = strtotime($this->array_options[$key]);
|
||||
}
|
||||
$new_array_options[$key] = $this->db->idate($this->array_options[$key]);
|
||||
break;
|
||||
case 'datetimegmt':
|
||||
// If data is a string instead of a timestamp, we convert it
|
||||
if (!is_numeric($this->array_options[$key]) || $this->array_options[$key] != intval($this->array_options[$key])) {
|
||||
$this->array_options[$key] = strtotime($this->array_options[$key]);
|
||||
}
|
||||
$new_array_options[$key] = $this->db->idate($this->array_options[$key], 'gmt');
|
||||
break;
|
||||
case 'link':
|
||||
$param_list = array_keys($attributeParam['options']);
|
||||
// 0 : ObjectName
|
||||
// 1 : classPath
|
||||
$InfoFieldList = explode(":", $param_list[0]);
|
||||
dol_include_once($InfoFieldList[1]);
|
||||
if ($InfoFieldList[0] && class_exists($InfoFieldList[0])) {
|
||||
if ($value == '-1') { // -1 is key for no defined in combo list of objects
|
||||
$new_array_options[$key] = '';
|
||||
} elseif ($value) {
|
||||
$object = new $InfoFieldList[0]($this->db);
|
||||
'@phan-var-force CommonObject $object';
|
||||
} else { // Common usage
|
||||
$new_array_options[$key] = $this->array_options[$key]; // Value is kept
|
||||
}
|
||||
break;
|
||||
case 'date':
|
||||
case 'datetime':
|
||||
// If data is a string instead of a timestamp, we convert it
|
||||
if (!is_numeric($this->array_options[$key]) || $this->array_options[$key] != intval($this->array_options[$key])) {
|
||||
$this->array_options[$key] = strtotime($this->array_options[$key]);
|
||||
}
|
||||
$new_array_options[$key] = $this->db->idate($this->array_options[$key]);
|
||||
break;
|
||||
case 'datetimegmt':
|
||||
// If data is a string instead of a timestamp, we convert it
|
||||
if (!is_numeric($this->array_options[$key]) || $this->array_options[$key] != intval($this->array_options[$key])) {
|
||||
$this->array_options[$key] = strtotime($this->array_options[$key]);
|
||||
}
|
||||
$new_array_options[$key] = $this->db->idate($this->array_options[$key], 'gmt');
|
||||
break;
|
||||
case 'link':
|
||||
$param_list = array_keys($attributeParam['options']);
|
||||
// 0 : ObjectName
|
||||
// 1 : classPath
|
||||
$InfoFieldList = explode(":", $param_list[0]);
|
||||
dol_include_once($InfoFieldList[1]);
|
||||
if ($InfoFieldList[0] && class_exists($InfoFieldList[0])) {
|
||||
if ($value == '-1') { // -1 is key for no defined in combo list of objects
|
||||
$new_array_options[$key] = '';
|
||||
} elseif ($value) {
|
||||
$object = new $InfoFieldList[0]($this->db);
|
||||
'@phan-var-force CommonObject $object';
|
||||
|
||||
$objectId = 0;
|
||||
$objectId = 0;
|
||||
|
||||
$sqlFetchObject = "SELECT rowid FROM ".$this->db->prefix().$object->table_element;
|
||||
if (is_numeric($value)) {
|
||||
$sqlFetchObject .= " WHERE rowid = " . (int) $value;
|
||||
} else {
|
||||
$sqlFetchObject .= " WHERE ref = '" . $this->db->escape($value) . "'";
|
||||
}
|
||||
|
||||
$obj = $this->db->getRow($sqlFetchObject);
|
||||
|
||||
if ($obj !== false) {
|
||||
$objectId = $obj->rowid;
|
||||
$res = 1;
|
||||
} else {
|
||||
$res = -1;
|
||||
}
|
||||
|
||||
if ($res > 0) {
|
||||
$new_array_options[$key] = $objectId;
|
||||
} else {
|
||||
$this->error = "Id/Ref '".$value."' for object '".$object->element."' not found";
|
||||
return -1;
|
||||
}
|
||||
$sqlFetchObject = "SELECT rowid FROM ".$this->db->prefix().$object->table_element;
|
||||
if (is_numeric($value)) {
|
||||
$sqlFetchObject .= " WHERE rowid = " . (int) $value;
|
||||
} else {
|
||||
$sqlFetchObject .= " WHERE ref = '" . $this->db->escape($value) . "'";
|
||||
}
|
||||
|
||||
$obj = $this->db->getRow($sqlFetchObject);
|
||||
|
||||
if ($obj !== false) {
|
||||
$objectId = $obj->rowid;
|
||||
$res = 1;
|
||||
} else {
|
||||
$res = -1;
|
||||
}
|
||||
|
||||
if ($res > 0) {
|
||||
$new_array_options[$key] = $objectId;
|
||||
} else {
|
||||
$this->error = "Id/Ref '".$value."' for object '".$object->element."' not found";
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
dol_syslog('Error bad setup of extrafield', LOG_WARNING);
|
||||
}
|
||||
break;
|
||||
case 'checkbox':
|
||||
case 'chkbxlst':
|
||||
if (is_array($this->array_options[$key])) {
|
||||
$new_array_options[$key] = implode(',', $this->array_options[$key]);
|
||||
} else {
|
||||
$new_array_options[$key] = $this->array_options[$key];
|
||||
}
|
||||
break;
|
||||
} else {
|
||||
dol_syslog('Error bad setup of extrafield', LOG_WARNING);
|
||||
}
|
||||
break;
|
||||
case 'checkbox':
|
||||
case 'chkbxlst':
|
||||
if (is_array($this->array_options[$key])) {
|
||||
$new_array_options[$key] = implode(',', $this->array_options[$key]);
|
||||
} else {
|
||||
$new_array_options[$key] = $this->array_options[$key];
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$sqlColumnValues = ['fk_object' => (int) $this->id]; // key-value pairs for the SQL INSERT or UPDATE query
|
||||
|
||||
foreach ($new_array_options as $key => $newValue) {
|
||||
$attributeKey = substr($key, 8); // Remove 'options_' prefix
|
||||
$attributeType = $extrafields->attributes[$this->table_element]['type'][$attributeKey];
|
||||
if ($attributeType === 'separate') {
|
||||
// separator extrafields don't have data per object so they don't have a comlumn in the database
|
||||
continue;
|
||||
}
|
||||
$geoDataType = ExtraFields::$geoDataTypes[$attributeType] ?? null;
|
||||
// Add field of attribute
|
||||
if (! $geoDataType) {
|
||||
// not a geodata type
|
||||
if ($newValue != '') {
|
||||
$sqlColumnValues[$attributeKey] = "'".$this->db->escape($newValue)."'";
|
||||
} else {
|
||||
$sqlColumnValues[$attributeKey] = 'null';
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (empty($newValue)) {
|
||||
$sqlColumnValues[$attributeKey] = 'null';
|
||||
continue;
|
||||
}
|
||||
if (preg_match('/error/i', $newValue)) {
|
||||
dol_syslog(
|
||||
'Bad syntax string for '.$geoDataType['shortname'].' '.$newValue.' to generate SQL request',
|
||||
LOG_WARNING
|
||||
);
|
||||
$sqlColumnValues[$attributeKey] = 'null';
|
||||
continue;
|
||||
}
|
||||
|
||||
$this->db->begin();
|
||||
// Geodata type: Text must be a WKT string. Examples:
|
||||
// - point => "POINT(15 20)"
|
||||
// - multipts => "MULTIPOINT(0 0, 20 20, 60 60)"
|
||||
// - linestrg => "LINESTRING(0 0, 10 10, 20 25, 50 60)"
|
||||
// - polygon => "POLYGON((0 0,10 0,10 10,0 10,0 0),(5 5,7 5,7 7,5 7, 5 5))"
|
||||
$sqlColumnValues[$key] = $geoDataType['ST_Function']."('".$this->db->escape($newValue)."')";
|
||||
}
|
||||
|
||||
$table_element = $this->table_element;
|
||||
if ($table_element == 'categorie') {
|
||||
$table_element = 'categories'; // For compatibility
|
||||
}
|
||||
$this->db->begin();
|
||||
|
||||
dol_syslog(get_class($this)."::insertExtraFields delete then insert", LOG_DEBUG);
|
||||
$table_element = $this->table_element;
|
||||
if ($table_element == 'categorie') {
|
||||
$table_element = 'categories'; // For compatibility
|
||||
}
|
||||
$extrafieldsTable = $this->db->prefix() . $table_element . '_extrafields';
|
||||
|
||||
$sql_del = "DELETE FROM ".$this->db->prefix().$table_element."_extrafields WHERE fk_object = ".((int) $this->id);
|
||||
$this->db->query($sql_del);
|
||||
dol_syslog(get_class($this)."::insertExtraFields delete then insert", LOG_DEBUG);
|
||||
|
||||
$sql = "INSERT INTO ".$this->db->prefix().$table_element."_extrafields (fk_object";
|
||||
foreach ($new_array_options as $key => $value) {
|
||||
$attributeKey = substr($key, 8); // Remove 'options_' prefix
|
||||
// Add field of attribute
|
||||
if ($extrafields->attributes[$this->table_element]['type'][$attributeKey] != 'separate') { // Only for other type than separator
|
||||
$sql .= ",".$attributeKey;
|
||||
}
|
||||
}
|
||||
// if the extrafields row already exists for the object, we update it
|
||||
if ($this->db->getRow("SELECT 1 FROM {$extrafieldsTable} WHERE fk_object = ".((int) $this->id))) {
|
||||
array_shift($sqlColumnValues); // drop the 'fk_object' column because its value won't change
|
||||
$sqlColumnValueString = implode(
|
||||
',',
|
||||
/**
|
||||
* @param string $key
|
||||
* @return string
|
||||
*/
|
||||
array_map(function ($key) use ($sqlColumnValues) {
|
||||
return "{$key} = {$sqlColumnValues[$key]}";
|
||||
}, array_keys($sqlColumnValues))
|
||||
);
|
||||
$sql = "UPDATE {$extrafieldsTable} SET {$sqlColumnValueString} WHERE fk_object = ".((int) $this->id);
|
||||
} else {
|
||||
// We must insert a default value for fields for other entities that are mandatory to avoid not null error
|
||||
if (!empty($extrafields->attributes[$this->table_element]['mandatoryfieldsofotherentities']) && is_array($extrafields->attributes[$this->table_element]['mandatoryfieldsofotherentities'])) {
|
||||
foreach ($extrafields->attributes[$this->table_element]['mandatoryfieldsofotherentities'] as $tmpkey => $tmpval) {
|
||||
if (!isset($extrafields->attributes[$this->table_element]['type'][$tmpkey])) { // If field not already added previously
|
||||
$sql .= ",".$tmpkey;
|
||||
}
|
||||
$extrafieldsRequiredOnOtherEntities = $extrafields->attributes[$this->table_element]['mandatoryfieldsofotherentities'] ?? array();
|
||||
foreach ($extrafieldsRequiredOnOtherEntities as $key => $extrafieldType) {
|
||||
if (isset($sqlColumnValues[$key])) {
|
||||
// extrafield value already provided: no need to add it
|
||||
continue;
|
||||
}
|
||||
// default value: empty string, except for 'int', 'double' and 'price'
|
||||
$sqlColumnValues[$key] = "''";
|
||||
if (in_array($extrafieldType, array('int', 'double', 'price'))) {
|
||||
$sqlColumnValues[$key] = 0;
|
||||
}
|
||||
}
|
||||
$sql .= ") VALUES (".$this->id;
|
||||
$sqlColumns = implode(',', array_keys($sqlColumnValues));
|
||||
$sqlValues = implode(',', array_values($sqlColumnValues));
|
||||
$sql = "INSERT INTO {$extrafieldsTable} ({$sqlColumns}) VALUES ({$sqlValues})";
|
||||
}
|
||||
|
||||
foreach ($new_array_options as $key => $value) {
|
||||
$attributeKey = substr($key, 8); // Remove 'options_' prefix
|
||||
// Add field of attribute
|
||||
if (!in_array($extrafields->attributes[$this->table_element]['type'][$attributeKey], ['separate', 'point', 'multipts', 'linestrg', 'polygon'])) { // Only for other type than separator)
|
||||
if ($new_array_options[$key] != '' || $new_array_options[$key] == '0') {
|
||||
$sql .= ",'".$this->db->escape($new_array_options[$key])."'";
|
||||
} else {
|
||||
$sql .= ",null";
|
||||
}
|
||||
}
|
||||
if ($extrafields->attributes[$this->table_element]['type'][$attributeKey] == 'point') { // for point type
|
||||
if (!empty($new_array_options[$key])) {
|
||||
if (!preg_match('/error/i', $new_array_options[$key])) {
|
||||
// Text must be a WKT string, so "POINT(15 20)"
|
||||
$sql .= ",ST_PointFromText('".$this->db->escape($new_array_options[$key])."')";
|
||||
} else {
|
||||
dol_syslog("Bad syntax string for point ".$new_array_options[$key]." to generate SQL request", LOG_WARNING);
|
||||
$sql .= ",null";
|
||||
}
|
||||
} else {
|
||||
$sql .= ",null";
|
||||
}
|
||||
}
|
||||
if ($extrafields->attributes[$this->table_element]['type'][$attributeKey] == 'multipts') { // for point type
|
||||
if (!empty($new_array_options[$key])) {
|
||||
if (!preg_match('/error/i', $new_array_options[$key])) {
|
||||
// Text must be a WKT string, so "MULTIPOINT(0 0, 20 20, 60 60)"
|
||||
$sql .= ",ST_MultiPointFromText('".$this->db->escape($new_array_options[$key])."')";
|
||||
} else {
|
||||
dol_syslog("Bad syntax string for multipoint ".$new_array_options[$key]." to generate SQL request", LOG_WARNING);
|
||||
$sql .= ",null";
|
||||
}
|
||||
} else {
|
||||
$sql .= ",null";
|
||||
}
|
||||
}
|
||||
if ($extrafields->attributes[$this->table_element]['type'][$attributeKey] == 'linestrg') { // for linestring type
|
||||
if (!empty($new_array_options[$key])) {
|
||||
if (!preg_match('/error/i', $new_array_options[$key])) {
|
||||
// Text must be a WKT string, so "LINESTRING(0 0, 10 10, 20 25, 50 60)"
|
||||
$sql .= ",ST_LineFromText('".$this->db->escape($new_array_options[$key])."')";
|
||||
} else {
|
||||
dol_syslog("Bad syntax string for line ".$new_array_options[$key]." to generate SQL request", LOG_WARNING);
|
||||
$sql .= ",null";
|
||||
}
|
||||
} else {
|
||||
$sql .= ",null";
|
||||
}
|
||||
}
|
||||
if ($extrafields->attributes[$this->table_element]['type'][$attributeKey] == 'polygon') { // for polygon type
|
||||
if (!empty($new_array_options[$key])) {
|
||||
if (!preg_match('/error/i', $new_array_options[$key])) {
|
||||
// Text must be a WKT string, so "POLYGON((0 0,10 0,10 10,0 10,0 0),(5 5,7 5,7 7,5 7, 5 5))"
|
||||
$sql .= ",ST_PolyFromText('".$this->db->escape($new_array_options[$key])."')";
|
||||
} else {
|
||||
dol_syslog("Bad syntax string for polygon ".$new_array_options[$key]." to generate SQL request", LOG_WARNING);
|
||||
$sql .= ",null";
|
||||
}
|
||||
} else {
|
||||
$sql .= ",null";
|
||||
}
|
||||
}
|
||||
}
|
||||
// We must insert a default value for fields for other entities that are mandatory to avoid not null error
|
||||
if (!empty($extrafields->attributes[$this->table_element]['mandatoryfieldsofotherentities']) && is_array($extrafields->attributes[$this->table_element]['mandatoryfieldsofotherentities'])) {
|
||||
foreach ($extrafields->attributes[$this->table_element]['mandatoryfieldsofotherentities'] as $tmpkey => $tmpval) {
|
||||
if (!isset($extrafields->attributes[$this->table_element]['type'][$tmpkey])) { // If field not already added previously
|
||||
if (in_array($tmpval, array('int', 'double', 'price'))) {
|
||||
$sql .= ", 0";
|
||||
} else {
|
||||
$sql .= ", ''";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
$resql = $this->db->query($sql);
|
||||
if (!$resql) {
|
||||
$this->error = $this->db->lasterror();
|
||||
$error++;
|
||||
}
|
||||
|
||||
$sql .= ")";
|
||||
|
||||
$resql = $this->db->query($sql);
|
||||
if (!$resql) {
|
||||
$this->error = $this->db->lasterror();
|
||||
if (!$error && $trigger) {
|
||||
// Call trigger
|
||||
$this->context = array('extrafieldaddupdate' => 1);
|
||||
$result = $this->call_trigger($trigger, $userused);
|
||||
if ($result < 0) {
|
||||
$error++;
|
||||
}
|
||||
// End call trigger
|
||||
}
|
||||
|
||||
if (!$error && $trigger) {
|
||||
// Call trigger
|
||||
$this->context = array('extrafieldaddupdate' => 1);
|
||||
$result = $this->call_trigger($trigger, $userused);
|
||||
if ($result < 0) {
|
||||
$error++;
|
||||
}
|
||||
// End call trigger
|
||||
}
|
||||
|
||||
if ($error) {
|
||||
$this->db->rollback();
|
||||
return -1;
|
||||
} else {
|
||||
$this->db->commit();
|
||||
return 1;
|
||||
}
|
||||
if ($error) {
|
||||
$this->db->rollback();
|
||||
return -1;
|
||||
} else {
|
||||
return 0;
|
||||
$this->db->commit();
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user