2
0
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:
Florian Mortgat
2025-05-04 18:42:01 +02:00
committed by GitHub
parent 8bec4db5e5
commit 9d0d8f7ec5
2 changed files with 290 additions and 301 deletions

View File

@@ -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;
}
}