diff --git a/synchro/synchro_exec.php b/synchro/synchro_exec.php
index 979637034..8f754d999 100644
--- a/synchro/synchro_exec.php
+++ b/synchro/synchro_exec.php
@@ -134,7 +134,19 @@ try
else
{
$aResults = array();
- $oSynchroDataSource->Synchronize($aResults);
+ if ($bSimulate)
+ {
+ CMDBSource::Query('START TRANSACTION');
+ }
+ $oSynchroDataSource->Synchronize($aResults, null);
+ foreach ($aResults as $sMessage)
+ {
+ $oP->p("results: $sMessage");
+ }
+ if ($bSimulate)
+ {
+ CMDBSource::Query('ROLLBACK');
+ }
}
}
}
diff --git a/synchro/synchro_import.php b/synchro/synchro_import.php
index 38abe00df..9efb456af 100644
--- a/synchro/synchro_import.php
+++ b/synchro/synchro_import.php
@@ -465,11 +465,11 @@ try
//
if ($bSynchronize && !$bSimulate)
{
- $aDataToReplica = array();
- $oDataSource->Synchronize($aDataToReplica, $oLoadStartDate);
+ $aTraces = array();
+ $oDataSource->Synchronize($aTraces, $oLoadStartDate);
//echo "#@# Synchronize() returned :
\n";
//echo "
\n"; - //print_r($aDataToReplica); + //print_r($aTraces); //echo "\n"; } diff --git a/synchro/synchrodatasource.class.inc.php b/synchro/synchrodatasource.class.inc.php index 67ddc9363..f62d8296b 100644 --- a/synchro/synchrodatasource.class.inc.php +++ b/synchro/synchrodatasource.class.inc.php @@ -401,11 +401,11 @@ EOF * Perform a synchronization between the data stored in the replicas (&synchro_data_xxx_xx table) * and the iTop objects. If the lastFullLoadStartDate is NOT specified then the full_load_periodicity * is used to determine which records are obsolete. - * @param Hash $aDataToReplica Debugs/Trace information, one entry per replica + * @param Hash $aTraces Debugs/Trace information, one or more entries per replica * @param DateTime $oLastFullLoadStartDate Date of the last full load (start date/time), if known * @return void */ - public function Synchronize(&$aDataToReplica, $oLastFullLoadStartDate = null) + public function Synchronize(&$aTraces, $oLastFullLoadStartDate = null) { // Create a change used for logging all the modifications/creations happening during the synchro $oMyChange = MetaModel::NewObject("CMDBChange"); @@ -430,7 +430,7 @@ EOF try { - $this->DoSynchronize($aDataToReplica, $oLastFullLoadStartDate, $oMyChange, $oStatLog); + $this->DoSynchronize($oLastFullLoadStartDate, $oMyChange, $oStatLog, $aTraces); $oStatLog->Set('end_date', time()); $oStatLog->Set('status', 'completed'); @@ -442,9 +442,10 @@ EOF $oStatLog->Set('status', 'completed'); $oStatLog->DBUpdateTracked($oMyChange); } + return $oStatLog; } - protected function DoSynchronize(&$aDataToReplica, $oLastFullLoadStartDate, $oMyChange, &$oStatLog) + protected function DoSynchronize($oLastFullLoadStartDate, $oMyChange, &$oStatLog, &$aTraces) { // Get all the replicas that were not seen in the last import and mark them as obsolete if ($oLastFullLoadStartDate == null) @@ -470,8 +471,7 @@ EOF } } $sLimitDate = $oLastFullLoadStartDate->Format('Y-m-d H:i:s'); - // TO DO: remove trace - echo "
sLimitDate: $sLimitDate
\n"; + $aTraces[] = "Limit Date: $sLimitDate"; $sSelectToObsolete = "SELECT SynchroReplica WHERE sync_source_id = :source_id AND status IN ('new', 'synchronized', 'modified', 'orphan') AND status_last_seen < :last_import"; $oSetToObsolete = new DBObjectSet(DBObjectSearch::FromOQL($sSelectToObsolete), array() /* order by*/, array('source_id' => $this->GetKey(), 'last_import' => $sLimitDate)); while($oReplica = $oSetToObsolete->Fetch()) @@ -480,8 +480,7 @@ EOF $sUpdateOnObsolete = $this->Get('delete_policy'); if ( ($sUpdateOnObsolete == 'update') || ($sUpdateOnObsolete == 'update_then_delete') ) { - // TO DO: remove trace - echo "Destination object: (dest_id:".$oReplica->Get('dest_id').") to be updated.
"; + $aTraces[] = "Destination object: (dest_id:".$oReplica->Get('dest_id').") to be updated"; $aToUpdate = array(); $aToUpdate = explode(';', $this->Get('delete_policy_update')); //ex: 'status:obsolete;description:stopped', foreach($aToUpdate as $sUpdateSpec) @@ -494,10 +493,9 @@ EOF $aToUpdate[$sAttCode] = $sValue; } } - $oReplica->UpdateDestObject($aToUpdate, $oMyChange, $oStatLog); + $oReplica->UpdateDestObject($aToUpdate, $oMyChange, $oStatLog, $aTraces); } - // TO DO: remove trace - echo "Replica id:".$oReplica->GetKey()." (dest_id:".$oReplica->Get('dest_id').") marked as obsolete
"; + $aTraces[] = "Replica id:".$oReplica->GetKey()." (dest_id:".$oReplica->Get('dest_id').") marked as obsolete"; $oReplica->Set('status', 'obsolete'); $oReplica->DBUpdateTracked($oMyChange); } @@ -511,8 +509,6 @@ EOF // // Get the list of SQL columns $sClass = $this->GetTargetClass(); - // TO DO: remove trace - echo "TargetClass: $sClass
"; $aAttCodes = array(); $sSelectAtt = "SELECT SynchroAttribute WHERE sync_source_id = :source_id AND update = 1"; $oSetAtt = new DBObjectSet(DBObjectSearch::FromOQL($sSelectAtt), array() /* order by*/, array('source_id' => $this->GetKey()) /* aArgs */); @@ -544,8 +540,7 @@ EOF { $aReconciliationKeys[] = "primary_key"; } - // TO DO: remove trace - echo "Reconciliation on: {".implode(', ', $aReconciliationKeys)."}sDeletionDate: $sDeletionDate
\n"; - + $aTraces[] = "sDeletionDate: $sDeletionDate"; + $sSelectToDelete = "SELECT SynchroReplica WHERE sync_source_id = :source_id AND status IN ('obsolete') AND status_last_seen < :last_import"; $oSetToDelete = new DBObjectSet(DBObjectSearch::FromOQL($sSelectToDelete), array() /* order by*/, array('source_id' => $this->GetKey(), 'last_import' => $sDeletionDate)); while($oReplica = $oSetToDelete->Fetch()) @@ -601,13 +595,10 @@ EOF $sUpdateOnObsolete = $this->Get('delete_policy'); if ( ($sUpdateOnObsolete == 'delete') || ($sUpdateOnObsolete == 'update_then_delete') ) { - // TO DO: remove trace - echo "Destination object: (dest_id:".$oReplica->Get('dest_id').") to be DELETED.
"; - // TO DO: delete the dest object for real... - $oReplica->DeleteDestObject($oMyChange, $oStatLog); + $aTraces[] = "Destination object: (dest_id:".$oReplica->Get('dest_id').") to be DELETED"; + $oReplica->DeleteDestObject($oMyChange, $oStatLog, $aTraces); } - // TO DO: remove trace - echo "Replica id:".$oReplica->GetKey()." (dest_id:".$oReplica->Get('dest_id').") to be deleted
"; + $aTraces[] = "Replica id:".$oReplica->GetKey()." (dest_id:".$oReplica->Get('dest_id').") to be deleted"; $oReplica->DBDeleteTracked($oMyChange); } } @@ -912,7 +903,7 @@ class SynchroReplica extends DBObject } - public function Synchro($oDataSource, $aReconciliationKeys, $aAttributes, $oChange, $oStatLog) + public function Synchro($oDataSource, $aReconciliationKeys, $aAttributes, $oChange, &$oStatLog, &$aTraces) { switch($this->Get('status')) { @@ -931,7 +922,18 @@ class SynchroReplica extends DBObject $aFilterValues = array(); foreach($aReconciliationKeys as $sFilterCode) { - $aFilterValues[$sFilterCode] = $this->GetValueFromExtData($sFilterCode); + $value = $this->GetValueFromExtData($sFilterCode); + if (!is_null($value)) + { + $aFilterValues[$sFilterCode] = $value; + } + else + { + // Reconciliation could not be performed - log and EXIT + $this->SetLastError('Could not reconcile on null value: '.$sFilterCode); + $oStatLog->Set('stats_nb_errors', $oStatLog->Get('stats_nb_errors') + 1); + return; + } } $oDestSet = new DBObjectSet(self::$aSearches[$oDataSource->GetKey()], array(), $aFilterValues); $iCount = $oDestSet->Count(); @@ -940,13 +942,13 @@ class SynchroReplica extends DBObject { case 0: //echo "Nothing found for: ".self::$aSearches[$oDataSource->GetKey()]->ToOQL(true, $aFilterValues)."
"; - $this->CreateObjectFromReplica($oDataSource->GetTargetClass(), $aAttributes, $oChange, $oStatLog); + $this->CreateObjectFromReplica($oDataSource->GetTargetClass(), $aAttributes, $oChange, $oStatLog, $aTraces); break; case 1: //echo "Found 1 for: ".self::$aSearches[$oDataSource->GetKey()]->ToOQL(true, $aFilterValues)."
"; $oDestObj = $oDestSet->Fetch(); - $this->UpdateObjectFromReplica($oDestObj, $aAttributes, $oChange, $oStatLog); + $this->UpdateObjectFromReplica($oDestObj, $aAttributes, $oChange, $oStatLog, $aTraces); $this->Set('dest_id', $oDestObj->GetKey()); $this->Set('status_dest_creator', false); $this->Set('dest_class', get_class($oDestObj)); @@ -977,7 +979,7 @@ class SynchroReplica extends DBObject } else { - $this->UpdateObjectFromReplica($oDestObj, $aAttributes, $oChange, $oStatLog); + $this->UpdateObjectFromReplica($oDestObj, $aAttributes, $oChange, $oStatLog, $aTraces); } break; @@ -989,20 +991,23 @@ class SynchroReplica extends DBObject /** * Updates the destination object with the Extended data found in the synchro_data_XXXX table */ - protected function UpdateObjectFromReplica($oDestObj, $aAttributes, $oChange, &$oStatLog) + protected function UpdateObjectFromReplica($oDestObj, $aAttributes, $oChange, &$oStatLog, &$aTraces) { - // TO DO: remove trace - echo "Update object ".$oDestObj->GetHyperLink()."
"; + $aValueTrace = array(); foreach($aAttributes as $sAttCode) { $value = $this->GetValueFromExtData($sAttCode); - $oDestObj->Set($sAttCode, $value); - // TO DO: remove trace - echo "Setting $sAttCode to $value
"; + if (!is_null($value)) + { + $oDestObj->Set($sAttCode, $value); + $aValueTrace[] = "$sAttCode<$value"; + } } try { $oDestObj->DBUpdateTracked($oChange); + $aTraces[] = "Updated object ".$oDestObj->GetHyperLink()." (".implode(', ', $aValueTrace).")"; + $this->Set('status_last_error', ''); $this->Set('status', 'synchronized'); } @@ -1016,23 +1021,23 @@ class SynchroReplica extends DBObject /** * Creates the destination object populating it with the Extended data found in the synchro_data_XXXX table */ - protected function CreateObjectFromReplica($sClass, $aAttributes, $oChange, $oStatLog) + protected function CreateObjectFromReplica($sClass, $aAttributes, $oChange, &$oStatLog, &$aTraces) { - // TO DO: remove trace - echo "Creating new $sClass
"; $oDestObj = MetaModel::NewObject($sClass); - foreach($aAttributes as $sAttCode) - { - $value = $this->GetValueFromExtData($sAttCode); - $oDestObj->Set($sAttCode, $value); - // TO DO: remove trace - echo "Setting $sAttCode to $value
"; - } try { + $aValueTrace = array(); + foreach($aAttributes as $sAttCode) + { + $value = $this->GetValueFromExtData($sAttCode); + if (!is_null($value)) + { + $oDestObj->Set($sAttCode, $value); + $aValueTrace[] = "$sAttCode<$value"; + } + } $iNew = $oDestObj->DBInsertTracked($oChange); - // TO DO: remove trace - echo "Created: $iNew
"; + $aTraces[] = "Created $sClass::$iNew (".implode(', ', $aValueTrace).")"; $this->Set('dest_id', $oDestObj->GetKey()); $this->Set('dest_class', get_class($oDestObj)); @@ -1052,7 +1057,7 @@ class SynchroReplica extends DBObject /** * Update the destination object with given values */ - public function UpdateDestObject($aValues, $oChange, &$oStatLog) + public function UpdateDestObject($aValues, $oChange, &$oStatLog, &$aTraces) { try { @@ -1073,7 +1078,7 @@ class SynchroReplica extends DBObject /** * Delete the destination object */ - public function DeleteDestObject($oChange, &$oStatLog) + public function DeleteDestObject($oChange, &$oStatLog, &$aTraces) { if($this->Get('status_dest_creator')) { diff --git a/test/testlist.inc.php b/test/testlist.inc.php index ed47fb78b..09122f6b8 100644 --- a/test/testlist.inc.php +++ b/test/testlist.inc.php @@ -1838,28 +1838,34 @@ class TestDataExchange extends TestBizModel $oDataSource->Set('delete_policy_retention', $aSingleScenario['delete_policy_retention']); $iDataSourceId = $this->ObjectToDB($oDataSource); - // Specify the attributes for the data source - foreach($aSingleScenario['attributes'] as $aAttribInfo) - { - $oSyncAtt = new SynchroAttribute(); - $oSyncAtt->Set('sync_source_id', $iDataSourceId); - $oSyncAtt->Set('attcode', $aAttribInfo['attcode']); - $oSyncAtt->Set('update', $aAttribInfo['do_update']); - $oSyncAtt->Set('reconcile', $aAttribInfo['do_reconcile']); - $this->ObjectToDB($oSyncAtt); + $oAttributeSet = $oDataSource->Get('attribute_list'); + while ($oAttribute = $oAttributeSet->Fetch()) + { + if (array_key_exists($aSingleScenario['attributes'], $oAttribute->Get('attcode'))) + { + $aAttribInfo = $aSingleScenario['attributes'][$oAttribute->Get('attcode')]; + $oSyncAtt->Set('update', $aAttribInfo['do_update']); + $oSyncAtt->Set('reconcile', $aAttribInfo['do_reconcile']); + } + else + { + $oSyncAtt->Set('update', false); + $oSyncAtt->Set('reconcile', false); + } + $oAttribute->DBUpdateTracked(); } - + // Prepare list of prefixes -> make sure objects are unique with regard to the reconciliation scheme $aPrefixes = array(); // attcode => prefix foreach($aSourceAttributes as $iDummy => $sAttCode) { $aPrefixes[$sAttCode] = ''; // init with something } - foreach($aSingleScenario['attributes'] as $aAttribInfo) + foreach($aSingleScenario['attributes'] as $sAttCode => $aAttribInfo) { if ($aAttribInfo['do_reconcile']) { - $aPrefixes[$aAttribInfo['attcode']] = 'TEST_'.$iDataSourceId.'_'; + $aPrefixes[$sAttCode] = 'TEST_'.$iDataSourceId.'_'; } } @@ -2066,18 +2072,15 @@ class TestDataExchange extends TestBizModel ), ), 'attributes' => array( - array( - 'attcode' => 'org_id', + 'org_id' => array( 'do_reconcile' => false, 'do_update' => true, ), - array( - 'attcode' => 'name', + 'name' => array( 'do_reconcile' => true, 'do_update' => true, ), - array( - 'attcode' => 'status', + 'status' => array( 'do_reconcile' => false, 'do_update' => true, ), @@ -2120,18 +2123,15 @@ class TestDataExchange extends TestBizModel ), ), 'attributes' => array( - array( - 'attcode' => 'org_id', + 'org_id' => array( 'do_reconcile' => false, 'do_update' => true, ), - array( - 'attcode' => 'name', + 'name' => array( 'do_reconcile' => true, 'do_update' => true, ), - array( - 'attcode' => 'status', + 'status' => array( 'do_reconcile' => false, 'do_update' => true, ), @@ -2198,18 +2198,15 @@ class TestDataExchange extends TestBizModel ), ), 'attributes' => array( - array( - 'attcode' => 'org_id', + 'org_id' => array( 'do_reconcile' => false, 'do_update' => true, ), - array( - 'attcode' => 'name', + 'name' => array( 'do_reconcile' => true, 'do_update' => true, ), - array( - 'attcode' => 'status', + 'status' => array( 'do_reconcile' => false, 'do_update' => true, ),