mirror of
https://github.com/Combodo/iTop.git
synced 2026-02-13 07:24:13 +01:00
Data Exchange - Improved to allow the import of complex attributes like passwords and documents + few fixes
SVN:trunk[1106]
This commit is contained in:
@@ -204,12 +204,27 @@ abstract class AttributeDefinition
|
||||
|
||||
public function MakeRealValue($proposedValue) {return $proposedValue;} // force an allowed value (type conversion and possibly forces a value as mySQL would do upon writing!)
|
||||
|
||||
public function GetSQLExpressions() {return array();} // returns suffix/expression pairs (1 in most of the cases), for READING (Select)
|
||||
public function GetSQLExpressions($sPrefix = '') {return array();} // returns suffix/expression pairs (1 in most of the cases), for READING (Select)
|
||||
public function FromSQLToValue($aCols, $sPrefix = '') {return null;} // returns a value out of suffix/value pairs, for SELECT result interpretation
|
||||
public function GetSQLColumns() {return array();} // returns column/spec pairs (1 in most of the cases), for STRUCTURING (DB creation)
|
||||
public function GetSQLValues($value) {return array();} // returns column/value pairs (1 in most of the cases), for WRITING (Insert, Update)
|
||||
public function RequiresIndex() {return false;}
|
||||
|
||||
// Import - differs slightly from SQL input, but identical in most cases
|
||||
//
|
||||
public function GetImportColumns() {return $this->GetSQLColumns();}
|
||||
public function FromImportToValue($aCols, $sPrefix = '')
|
||||
{
|
||||
$aValues = array();
|
||||
foreach ($this->GetSQLExpressions($sPrefix) as $sAlias => $sExpr)
|
||||
{
|
||||
// This is working, based on the assumption that importable fields
|
||||
// are not computed fields => the expression is the name of a column
|
||||
$aValues[$sPrefix.$sAlias] = $aCols[$sExpr];
|
||||
}
|
||||
return $this->FromSQLToValue($aValues, $sPrefix);
|
||||
}
|
||||
|
||||
public function GetValidationPattern()
|
||||
{
|
||||
return '';
|
||||
@@ -414,7 +429,7 @@ class AttributeDBFieldVoid extends AttributeDefinition
|
||||
//
|
||||
protected function ScalarToSQL($value) {return $value;} // format value as a valuable SQL literal (quoted outside)
|
||||
|
||||
public function GetSQLExpressions()
|
||||
public function GetSQLExpressions($sPrefix = '')
|
||||
{
|
||||
$aColumns = array();
|
||||
// Note: to optimize things, the existence of the attribute is determined by the existence of one column with an empty suffix
|
||||
@@ -1941,9 +1956,16 @@ class AttributeExternalField extends AttributeDefinition
|
||||
return $oExtAttDef->GetSQLCol();
|
||||
}
|
||||
|
||||
public function GetSQLExpressions()
|
||||
public function GetSQLExpressions($sPrefix = '')
|
||||
{
|
||||
return array('' => $this->GetCode());
|
||||
if ($sPrefix == '')
|
||||
{
|
||||
return array('' => $this->GetCode());
|
||||
}
|
||||
else
|
||||
{
|
||||
return $sPrefix;
|
||||
}
|
||||
}
|
||||
|
||||
public function GetLabel()
|
||||
@@ -2096,7 +2118,7 @@ class AttributeExternalField extends AttributeDefinition
|
||||
|
||||
|
||||
// Do not overload GetSQLExpression here because this is handled in the joins
|
||||
//public function GetSQLExpressions() {return array();}
|
||||
//public function GetSQLExpressions($sPrefix = '') {return array();}
|
||||
|
||||
// Here, we get the data...
|
||||
public function FromSQLToValue($aCols, $sPrefix = '')
|
||||
@@ -2187,13 +2209,17 @@ class AttributeBlob extends AttributeDefinition
|
||||
return $proposedValue;
|
||||
}
|
||||
|
||||
public function GetSQLExpressions()
|
||||
public function GetSQLExpressions($sPrefix = '')
|
||||
{
|
||||
if ($sPrefix == '')
|
||||
{
|
||||
$sPrefix = $this->GetCode();
|
||||
}
|
||||
$aColumns = array();
|
||||
// Note: to optimize things, the existence of the attribute is determined by the existence of one column with an empty suffix
|
||||
$aColumns[''] = $this->GetCode().'_mimetype';
|
||||
$aColumns['_data'] = $this->GetCode().'_data';
|
||||
$aColumns['_filename'] = $this->GetCode().'_filename';
|
||||
$aColumns[''] = $sPrefix.'_mimetype';
|
||||
$aColumns['_data'] = $sPrefix.'_data';
|
||||
$aColumns['_filename'] = $sPrefix.'_filename';
|
||||
return $aColumns;
|
||||
}
|
||||
|
||||
@@ -2331,12 +2357,16 @@ class AttributeOneWayPassword extends AttributeDefinition
|
||||
return $oPassword;
|
||||
}
|
||||
|
||||
public function GetSQLExpressions()
|
||||
public function GetSQLExpressions($sPrefix = '')
|
||||
{
|
||||
if ($sPrefix == '')
|
||||
{
|
||||
$sPrefix = $this->GetCode();
|
||||
}
|
||||
$aColumns = array();
|
||||
// Note: to optimize things, the existence of the attribute is determined by the existence of one column with an empty suffix
|
||||
$aColumns[''] = $this->GetCode().'_hash';
|
||||
$aColumns['_salt'] = $this->GetCode().'_salt';
|
||||
$aColumns[''] = $sPrefix.'_hash';
|
||||
$aColumns['_salt'] = $sPrefix.'_salt';
|
||||
return $aColumns;
|
||||
}
|
||||
|
||||
@@ -2391,6 +2421,27 @@ class AttributeOneWayPassword extends AttributeDefinition
|
||||
return $aColumns;
|
||||
}
|
||||
|
||||
public function GetImportColumns()
|
||||
{
|
||||
$aColumns = array();
|
||||
$aColumns[$this->GetCode()] = 'TINYTEXT';
|
||||
return $aColumns;
|
||||
}
|
||||
|
||||
public function FromImportToValue($aCols, $sPrefix = '')
|
||||
{
|
||||
if (!isset($aCols[$sPrefix]))
|
||||
{
|
||||
$sAvailable = implode(', ', array_keys($aCols));
|
||||
throw new MissingColumnException("Missing column '$sPrefix' from {$sAvailable}");
|
||||
}
|
||||
$sClearPwd = $aCols[$sPrefix];
|
||||
|
||||
$oPassword = new ormPassword('', '');
|
||||
$oPassword->SetPassword($sClearPwd);
|
||||
return $oPassword;
|
||||
}
|
||||
|
||||
public function GetFilterDefinitions()
|
||||
{
|
||||
return array();
|
||||
@@ -2574,9 +2625,13 @@ class AttributeComputedFieldVoid extends AttributeDefinition
|
||||
//
|
||||
// protected function ScalarToSQL($value) {return $value;} // format value as a valuable SQL literal (quoted outside)
|
||||
|
||||
public function GetSQLExpressions()
|
||||
public function GetSQLExpressions($sPrefix = '')
|
||||
{
|
||||
return array('' => $this->GetCode());
|
||||
if ($sPrefix == '')
|
||||
{
|
||||
$sPrefix = $this->GetCode();
|
||||
}
|
||||
return array('' => $sPrefix);
|
||||
}
|
||||
|
||||
public function FromSQLToValue($aCols, $sPrefix = '')
|
||||
|
||||
@@ -94,7 +94,7 @@ class Config
|
||||
),
|
||||
'skip_check_ext_keys' => array(
|
||||
'type' => 'bool',
|
||||
'description' => 'Disable external key check when checking the value of attribtutes',
|
||||
'description' => 'Disable external key check when checking the value of attributes',
|
||||
'default' => false,
|
||||
'value' => false,
|
||||
'source_of_value' => '',
|
||||
|
||||
@@ -396,23 +396,25 @@ abstract class DBObject
|
||||
}
|
||||
}
|
||||
|
||||
// Compute scalar attributes that depend on any other type of attribute
|
||||
public function DoComputeValues()
|
||||
public function ComputeValues()
|
||||
{
|
||||
if (is_callable(array($this, 'ComputeValues')))
|
||||
}
|
||||
|
||||
// Compute scalar attributes that depend on any other type of attribute
|
||||
final public function DoComputeValues()
|
||||
{
|
||||
// TODO - use a flag rather than checking the call stack -> this will certainly accelerate things
|
||||
|
||||
// First check that we are not currently computing the fields
|
||||
// (yes, we need to do some things like Set/Get to compute the fields which will in turn trigger the update...)
|
||||
foreach (debug_backtrace() as $aCallInfo)
|
||||
{
|
||||
// First check that we are not currently computing the fields
|
||||
// (yes, we need to do some things like Set/Get to compute the fields which will in turn trigger the update...)
|
||||
foreach (debug_backtrace() as $aCallInfo)
|
||||
{
|
||||
if (!array_key_exists("class", $aCallInfo)) continue;
|
||||
if ($aCallInfo["class"] != get_class($this)) continue;
|
||||
if ($aCallInfo["function"] != "ComputeValues") continue;
|
||||
return; //skip!
|
||||
}
|
||||
|
||||
$this->ComputeValues();
|
||||
if (!array_key_exists("class", $aCallInfo)) continue;
|
||||
if ($aCallInfo["class"] != get_class($this)) continue;
|
||||
if ($aCallInfo["function"] != "ComputeValues") continue;
|
||||
return; //skip!
|
||||
}
|
||||
$this->ComputeValues();
|
||||
}
|
||||
|
||||
public function GetAsHTML($sAttCode)
|
||||
|
||||
@@ -1657,18 +1657,29 @@ abstract class MetaModel
|
||||
}
|
||||
return $aSubClasses;
|
||||
}
|
||||
public static function GetClasses($sCategory = '')
|
||||
public static function GetClasses($sCategories = '', $bStrict = false)
|
||||
{
|
||||
if (array_key_exists($sCategory, self::$m_Category2Class))
|
||||
$aCategories = explode(',', $sCategories);
|
||||
$aClasses = array();
|
||||
foreach($aCategories as $sCategory)
|
||||
{
|
||||
return self::$m_Category2Class[$sCategory];
|
||||
}
|
||||
$sCategory = trim($sCategory);
|
||||
if (strlen($sCategory) == 0)
|
||||
{
|
||||
return array_keys(self::$m_aClassParams);
|
||||
}
|
||||
|
||||
//if (count(self::$m_Category2Class) > 0)
|
||||
//{
|
||||
// throw new CoreException("unkown class category '$sCategory', expecting a value in {".implode(', ', array_keys(self::$m_Category2Class))."}");
|
||||
//}
|
||||
return array();
|
||||
if (array_key_exists($sCategory, self::$m_Category2Class))
|
||||
{
|
||||
$aClasses = array_merge($aClasses, self::$m_Category2Class[$sCategory]);
|
||||
}
|
||||
elseif ($bStrict)
|
||||
{
|
||||
throw new CoreException("unkown class category '$sCategory', expecting a value in {".implode(', ', array_keys(self::$m_Category2Class))."}");
|
||||
}
|
||||
}
|
||||
|
||||
return array_unique($aClasses);
|
||||
}
|
||||
|
||||
public static function HasTable($sClass)
|
||||
|
||||
@@ -537,7 +537,7 @@ Dict::Add('EN US', 'English', 'English', array(
|
||||
'Core:SynchroLogTitle' => '%1$s - %2$s',
|
||||
'Core:Synchro:Nb_Replica' => 'Replica processed: %1$s',
|
||||
'Core:Synchro:Nb_Class:Objects' => '%1$s: %2$s',
|
||||
'Class:SynchroDataSource/Error:AtLeastOneReconciliationKeyMustBeSpecified' => 'At Least one reconciliation key must be specified.',
|
||||
'Class:SynchroDataSource/Error:AtLeastOneReconciliationKeyMustBeSpecified' => 'At Least one reconciliation key must be specified, or the reconciliation policy must be to use the primary key.',
|
||||
'Class:SynchroDataSource/Error:DeleteRetentionDurationMustBeSpecified' => 'A delete retention period must be specified, since objects are to be deleted after being marked as obsolete',
|
||||
'Class:SynchroDataSource/Error:DeletePolicyUpdateMustBeSpecified' => 'Obsolete objects are to be updated, but no update is specified.',
|
||||
'Core:SynchroReplica:PublicData' => 'Public Data',
|
||||
|
||||
@@ -40,7 +40,7 @@ class UserExternal extends User
|
||||
"key_type" => "autoincrement",
|
||||
"name_attcode" => "login",
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => array(),
|
||||
"reconc_keys" => array('login'),
|
||||
"db_table" => "",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
|
||||
@@ -35,7 +35,7 @@ class UserLDAP extends UserInternal
|
||||
"key_type" => "autoincrement",
|
||||
"name_attcode" => "login",
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => array(),
|
||||
"reconc_keys" => array('login'),
|
||||
"db_table" => "",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
|
||||
@@ -35,7 +35,7 @@ class UserLocal extends UserInternal
|
||||
"key_type" => "autoincrement",
|
||||
"name_attcode" => "login",
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => array(),
|
||||
"reconc_keys" => array('login'),
|
||||
"db_table" => "priv_user_local",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
|
||||
@@ -52,7 +52,7 @@ class SynchroDataSource extends cmdbAbstractObject
|
||||
MetaModel::Init_AddAttribute(new AttributeString("description", array("allowed_values"=>null, "sql"=>"description", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeEnum("status", array("allowed_values"=>new ValueSetEnum('implementation,production,obsolete'), "sql"=>"status", "default_value"=>"implementation", "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeExternalKey("user_id", array("targetclass"=>"User", "jointype"=>null, "allowed_values"=>null, "sql"=>"user_id", "is_null_allowed"=>true, "on_target_delete"=>DEL_MANUAL, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeClass("scope_class", array("class_category"=>"bizmodel", "more_values"=>"", "sql"=>"scope_class", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeClass("scope_class", array("class_category"=>"bizmodel,addon/authentication", "more_values"=>"", "sql"=>"scope_class", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
|
||||
// Declared here for a future usage, but ignored so far
|
||||
MetaModel::Init_AddAttribute(new AttributeString("scope_restriction", array("allowed_values"=>null, "sql"=>"scope_restriction", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
|
||||
@@ -60,7 +60,7 @@ class SynchroDataSource extends cmdbAbstractObject
|
||||
//MetaModel::Init_AddAttribute(new AttributeDateTime("last_synchro_date", array("allowed_values"=>null, "sql"=>"last_synchro_date", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
|
||||
// Format: seconds (int)
|
||||
MetaModel::Init_AddAttribute(new AttributeDuration("full_load_periodicity", array("allowed_values"=>null, "sql"=>"full_load_periodicity", "default_value"=>"", "is_null_allowed"=>true, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeDuration("full_load_periodicity", array("allowed_values"=>null, "sql"=>"full_load_periodicity", "default_value"=>86400, "is_null_allowed"=>true, "depends_on"=>array())));
|
||||
|
||||
// MetaModel::Init_AddAttribute(new AttributeString("reconciliation_list", array("allowed_values"=>null, "sql"=>"reconciliation_list", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeEnum("reconciliation_policy", array("allowed_values"=>new ValueSetEnum('use_primary_key,use_attributes'), "sql"=>"reconciliation_policy", "default_value"=>"use_attributes", "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
@@ -433,9 +433,9 @@ EOF
|
||||
/*
|
||||
* Overload the standard behavior
|
||||
*/
|
||||
public function DoCheckToWrite()
|
||||
public function ComputeValues()
|
||||
{
|
||||
parent::DoCheckToWrite();
|
||||
parent::ComputeValues();
|
||||
|
||||
if ($this->IsNew())
|
||||
{
|
||||
@@ -467,6 +467,10 @@ EOF
|
||||
}
|
||||
$this->Set('attribute_list', $oAttributeSet);
|
||||
}
|
||||
}
|
||||
public function DoCheckToWrite()
|
||||
{
|
||||
parent::DoCheckToWrite();
|
||||
|
||||
// Check that there is at least one reconciliation key defined
|
||||
if ($this->Get('reconciliation_policy') == 'use_attributes')
|
||||
@@ -676,6 +680,70 @@ EOF
|
||||
throw new SynchroExceptionNotStarted(Dict::S('Core:SyncDataSourceAccessRestriction'));
|
||||
}
|
||||
|
||||
// Get the list of SQL columns
|
||||
$sClass = $this->GetTargetClass();
|
||||
$aAttCodesExpected = array();
|
||||
$aAttCodesToReconcile = array();
|
||||
$aAttCodesToUpdate = array();
|
||||
$sSelectAtt = "SELECT SynchroAttribute WHERE sync_source_id = :source_id AND (update = 1 OR reconcile = 1)";
|
||||
$oSetAtt = new DBObjectSet(DBObjectSearch::FromOQL($sSelectAtt), array() /* order by*/, array('source_id' => $this->GetKey()) /* aArgs */);
|
||||
while ($oSyncAtt = $oSetAtt->Fetch())
|
||||
{
|
||||
if ($oSyncAtt->Get('update'))
|
||||
{
|
||||
$aAttCodesToUpdate[$oSyncAtt->Get('attcode')] = $oSyncAtt;
|
||||
}
|
||||
if ($oSyncAtt->Get('reconcile'))
|
||||
{
|
||||
$aAttCodesToReconcile[$oSyncAtt->Get('attcode')] = $oSyncAtt;
|
||||
}
|
||||
$aAttCodesExpected[$oSyncAtt->Get('attcode')] = $oSyncAtt;
|
||||
}
|
||||
$aColumns = $this->GetSQLColumns(array_keys($aAttCodesExpected));
|
||||
$aExtDataFields = array_keys($aColumns);
|
||||
$aExtDataFields[] = 'primary_key';
|
||||
$aExtDataSpec = array(
|
||||
'table' => $this->GetDataTable(),
|
||||
'join_key' => 'id',
|
||||
'fields' => $aExtDataFields
|
||||
);
|
||||
|
||||
// Get the list of attributes, determine reconciliation keys and update targets
|
||||
//
|
||||
if ($this->Get('reconciliation_policy') == 'use_attributes')
|
||||
{
|
||||
$aReconciliationKeys = $aAttCodesToReconcile;
|
||||
}
|
||||
elseif ($this->Get('reconciliation_policy') == 'use_primary_key')
|
||||
{
|
||||
// Override the setings made at the attribute level !
|
||||
$aReconciliationKeys = array("primary_key" => null);
|
||||
}
|
||||
|
||||
$oStatLog->AddTrace("Update of: {".implode(', ', array_keys($aAttCodesToUpdate))."}");
|
||||
$oStatLog->AddTrace("Reconciliation on: {".implode(', ', array_keys($aReconciliationKeys))."}");
|
||||
|
||||
if (count($aAttCodesToUpdate) == 0)
|
||||
{
|
||||
$oStatLog->AddTrace("No attribute to update");
|
||||
throw new SynchroExceptionNotStarted('There is no attribute to update');
|
||||
}
|
||||
if (count($aReconciliationKeys) == 0)
|
||||
{
|
||||
$oStatLog->AddTrace("No attribute for reconciliation");
|
||||
throw new SynchroExceptionNotStarted('No attribute for reconciliation');
|
||||
}
|
||||
|
||||
$aAttributes = array();
|
||||
foreach($aAttCodesToUpdate as $sAttCode => $oSyncAtt)
|
||||
{
|
||||
$oAttDef = MetaModel::GetAttributeDef($this->GetTargetClass(), $sAttCode);
|
||||
if ($oAttDef->IsWritable() && $oAttDef->IsScalar())
|
||||
{
|
||||
$aAttributes[$sAttCode] = $oSyncAtt;
|
||||
}
|
||||
}
|
||||
|
||||
$sDeletePolicy = $this->Get('delete_policy');
|
||||
|
||||
// Count the replicas
|
||||
@@ -742,58 +810,6 @@ EOF
|
||||
|
||||
// Get all the replicas that are 'new' or modified
|
||||
//
|
||||
// Get the list of SQL columns
|
||||
$sClass = $this->GetTargetClass();
|
||||
$aAttCodesExpected = array();
|
||||
$aAttCodesToReconcile = array();
|
||||
$aAttCodesToUpdate = array();
|
||||
$sSelectAtt = "SELECT SynchroAttribute WHERE sync_source_id = :source_id AND (update = 1 OR reconcile = 1)";
|
||||
$oSetAtt = new DBObjectSet(DBObjectSearch::FromOQL($sSelectAtt), array() /* order by*/, array('source_id' => $this->GetKey()) /* aArgs */);
|
||||
while ($oSyncAtt = $oSetAtt->Fetch())
|
||||
{
|
||||
if ($oSyncAtt->Get('update'))
|
||||
{
|
||||
$aAttCodesToUpdate[$oSyncAtt->Get('attcode')] = $oSyncAtt;
|
||||
}
|
||||
if ($oSyncAtt->Get('reconcile'))
|
||||
{
|
||||
$aAttCodesToReconcile[$oSyncAtt->Get('attcode')] = $oSyncAtt;
|
||||
}
|
||||
$aAttCodesExpected[$oSyncAtt->Get('attcode')] = $oSyncAtt;
|
||||
}
|
||||
$aColumns = $this->GetSQLColumns(array_keys($aAttCodesExpected));
|
||||
$aExtDataFields = array_keys($aColumns);
|
||||
$aExtDataFields[] = 'primary_key';
|
||||
$aExtDataSpec = array(
|
||||
'table' => $this->GetDataTable(),
|
||||
'join_key' => 'id',
|
||||
'fields' => $aExtDataFields
|
||||
);
|
||||
|
||||
// Get the list of reconciliation keys
|
||||
if ($this->Get('reconciliation_policy') == 'use_attributes')
|
||||
{
|
||||
$aReconciliationKeys = $aAttCodesToReconcile;
|
||||
}
|
||||
elseif ($this->Get('reconciliation_policy') == 'use_primary_key')
|
||||
{
|
||||
// Override the setings made at the attribute level !
|
||||
$aReconciliationKeys = array("primary_key" => null);
|
||||
}
|
||||
|
||||
$oStatLog->AddTrace("Update of: {".implode(', ', array_keys($aAttCodesToUpdate))."}");
|
||||
$oStatLog->AddTrace("Reconciliation on: {".implode(', ', array_keys($aReconciliationKeys))."}");
|
||||
|
||||
$aAttributes = array();
|
||||
foreach($aAttCodesToUpdate as $sAttCode => $oSyncAtt)
|
||||
{
|
||||
$oAttDef = MetaModel::GetAttributeDef($this->GetTargetClass(), $sAttCode);
|
||||
if ($oAttDef->IsWritable() && $oAttDef->IsScalar())
|
||||
{
|
||||
$aAttributes[$sAttCode] = $oSyncAtt;
|
||||
}
|
||||
}
|
||||
|
||||
$sSelectToSync = "SELECT SynchroReplica WHERE (status = 'new' OR status = 'modified') AND sync_source_id = :source_id";
|
||||
$oSetToSync = new DBObjectSet(DBObjectSearch::FromOQL($sSelectToSync), array() /* order by*/, array('source_id' => $this->GetKey()) /* aArgs */, $aExtDataSpec, 0 /* limitCount */, 0 /* limitStart */);
|
||||
|
||||
@@ -855,7 +871,7 @@ EOF
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach($oAttDef->GetSQLColumns() as $sField => $sDBFieldType)
|
||||
foreach($oAttDef->GetImportColumns() as $sField => $sDBFieldType)
|
||||
{
|
||||
$aColumns[$sField] = $sDBFieldType;
|
||||
}
|
||||
@@ -1181,8 +1197,10 @@ class SynchroReplica extends DBObject implements iDisplay
|
||||
MetaModel::Init_InheritAttributes();
|
||||
|
||||
MetaModel::Init_AddAttribute(new AttributeExternalKey("sync_source_id", array("targetclass"=>"SynchroDataSource", "jointype"=> "", "allowed_values"=>null, "sql"=>"sync_source_id", "is_null_allowed"=>false, "on_target_delete"=>DEL_AUTO, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeExternalField("base_class", array("allowed_values"=>null, "extkey_attcode"=> 'sync_source_id', "target_attcode"=>"scope_class")));
|
||||
|
||||
MetaModel::Init_AddAttribute(new AttributeInteger("dest_id", array("allowed_values"=>null, "sql"=>"dest_id", "default_value"=>0, "is_null_allowed"=>true, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeClass("dest_class", array("class_category"=>"bizmodel", "more_values"=>"", "sql"=>"dest_class", "default_value"=>'Organization', "is_null_allowed"=>true, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeClass("dest_class", array("class_category"=>"", "more_values"=>"", "sql"=>"dest_class", "default_value"=>'Organization', "is_null_allowed"=>true, "depends_on"=>array())));
|
||||
|
||||
MetaModel::Init_AddAttribute(new AttributeDateTime("status_last_seen", array("allowed_values"=>null, "sql"=>"status_last_seen", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeEnum("status", array("allowed_values"=>new ValueSetEnum('new,synchronized,modified,orphan,obsolete'), "sql"=>"status", "default_value"=>"new", "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
@@ -1247,6 +1265,7 @@ class SynchroReplica extends DBObject implements iDisplay
|
||||
// If needed, construct the query used for the reconciliation
|
||||
if (!isset(self::$aSearches[$oDataSource->GetKey()]))
|
||||
{
|
||||
$aCriterias = array();
|
||||
foreach($aReconciliationKeys as $sFilterCode => $oSyncAtt)
|
||||
{
|
||||
$aCriterias[] = ($sFilterCode == 'primary_key' ? 'id' : $sFilterCode).' = :'.$sFilterCode;
|
||||
@@ -1498,44 +1517,62 @@ class SynchroReplica extends DBObject implements iDisplay
|
||||
/**
|
||||
* Get the value from the 'Extended Data' located in the synchro_data_xxx table for this replica
|
||||
*/
|
||||
protected function GetValueFromExtData($sColumnName, $oSyncAtt, &$oStatLog)
|
||||
{
|
||||
// $aData should contain attributes defined either for reconciliation or create/update
|
||||
protected function GetValueFromExtData($sAttCode, $oSyncAtt, &$oStatLog)
|
||||
{
|
||||
// $aData should contain attributes defined either for reconciliation or create/update
|
||||
$aData = $this->GetExtendedData();
|
||||
|
||||
// In any case, a null column means "ignore this column"
|
||||
//
|
||||
if (is_null($aData[$sColumnName]))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
$sClass = $this->Get('base_class');
|
||||
$oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode);
|
||||
|
||||
if (!is_null($oSyncAtt) && ($oSyncAtt instanceof SynchroAttExtKey))
|
||||
{
|
||||
$rawValue = $aData[$sAttCode];
|
||||
if (is_null($rawValue))
|
||||
{
|
||||
// Null means "ignore" this attribute
|
||||
return null;
|
||||
}
|
||||
|
||||
$sReconcAttCode = $oSyncAtt->Get('reconciliation_attcode');
|
||||
if (!empty($sReconcAttCode))
|
||||
{
|
||||
$oDataSource = MetaModel::GetObject('SynchroDataSource', $this->Get('sync_source_id'));
|
||||
$sClass = $oDataSource->GetTargetClass();
|
||||
$oAttDef = MetaModel::GetAttributeDef($sClass, $sColumnName);
|
||||
$sRemoteClass = $oAttDef->GetTargetClass();
|
||||
$oObj = MetaModel::GetObjectByColumn($sRemoteClass, $sReconcAttCode, $aData[$sColumnName], false);
|
||||
if ($oObj)
|
||||
{
|
||||
return $oObj->GetKey();
|
||||
$sRemoteClass = $oAttDef->GetTargetClass();
|
||||
$oObj = MetaModel::GetObjectByColumn($sRemoteClass, $sReconcAttCode, $rawValue, false);
|
||||
if ($oObj)
|
||||
{
|
||||
$retValue = $oObj->GetKey();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Note: differs from null (in which case the value would be left unchanged)
|
||||
$oStatLog->AddTrace("Could not find [unique] object for '$sColumnName': searched on $sReconcAttCode = '$aData[$sColumnName]'", $this);
|
||||
return 0;
|
||||
$oStatLog->AddTrace("Could not find [unique] object for '$sAttCode': searched on $sReconcAttCode = '$rawValue'", $this);
|
||||
$retValue = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$retValue = $rawValue;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$aColumns = $oAttDef->GetImportColumns();
|
||||
foreach($aColumns as $sColumn => $sFormat)
|
||||
{
|
||||
// In any case, a null column means "ignore this attribute"
|
||||
//
|
||||
if (is_null($aData[$sColumn]))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
$retValue = $oAttDef->FromImportToValue($aData, $sAttCode);
|
||||
}
|
||||
|
||||
return $aData[$sColumnName];
|
||||
}
|
||||
|
||||
return $retValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps the given context parameter name to the appropriate filter/search code for this class
|
||||
* @param string $sContextParam Name of the context parameter, i.e. 'org_id'
|
||||
|
||||
Reference in New Issue
Block a user