From 20d0d33b60bc5ebe855e91519b769cf2f3d01d01 Mon Sep 17 00:00:00 2001 From: Denis Flaven Date: Thu, 24 Feb 2011 17:09:50 +0000 Subject: [PATCH] Synchro Data Sources Implementation on going... SVN:trunk[1096] --- css/light-grey.css | 20 +- dictionaries/dictionary.itop.core.php | 67 ++++++- synchro/synchrodatasource.class.inc.php | 249 +++++++++++++----------- 3 files changed, 216 insertions(+), 120 deletions(-) diff --git a/css/light-grey.css b/css/light-grey.css index c0949a8cc..37afbf0a0 100644 --- a/css/light-grey.css +++ b/css/light-grey.css @@ -919,4 +919,22 @@ span.form_validation { } .wiki_broken_link { text-decoration: line-through; -} \ No newline at end of file +} +.synoptics, .synoptics tr td { + background: transparent; + padding:10px; + font-size:1em; + vertical-align:middle; + color:#fff; + text-align:center; +} +.synoptics tr td.arrow { + color:#333; + border-top: 1px dashed #333; + width:100px; +} +.synoptics tr.synoptics_header td { + color:#000; font-size:1em; + vertical-align:middle; + text-align:center; +} diff --git a/dictionaries/dictionary.itop.core.php b/dictionaries/dictionary.itop.core.php index 67b9eb290..1cd8af296 100644 --- a/dictionaries/dictionary.itop.core.php +++ b/dictionaries/dictionary.itop.core.php @@ -239,13 +239,13 @@ Dict::Add('EN US', 'English', 'English', array( Dict::Add('EN US', 'English', 'English', array( 'Class:Event' => 'Log Event', 'Class:Event+' => 'An application internal event', - 'Class:Event/Attribute:message' => 'message', + 'Class:Event/Attribute:message' => 'Message', 'Class:Event/Attribute:message+' => 'short description of the event', - 'Class:Event/Attribute:date' => 'date', + 'Class:Event/Attribute:date' => 'Date', 'Class:Event/Attribute:date+' => 'date and time at which the changes have been recorded', - 'Class:Event/Attribute:userinfo' => 'user info', + 'Class:Event/Attribute:userinfo' => 'User info', 'Class:Event/Attribute:userinfo+' => 'identification of the user that was doing the action that triggered this event', - 'Class:Event/Attribute:finalclass' => 'type', + 'Class:Event/Attribute:finalclass' => 'Type', 'Class:Event/Attribute:finalclass+' => '', )); @@ -329,6 +329,21 @@ Dict::Add('EN US', 'English', 'English', array( 'Class:EventWebService/Attribute:data+' => 'Result data', )); +// +// Class: EventLoginUsage +// + +Dict::Add('EN US', 'English', 'English', array( + 'Class:EventLoginUsage' => 'Login Usage', + 'Class:EventLoginUsage+' => 'Connection to the application', + 'Class:EventLoginUsage/Attribute:user_id' => 'Login', + 'Class:EventLoginUsage/Attribute:user_id+' => 'Login', + 'Class:EventLoginUsage/Attribute:contact_name' => 'User Name', + 'Class:EventLoginUsage/Attribute:contact_name+' => 'User Name', + 'Class:EventLoginUsage/Attribute:contact_email' => 'User Email', + 'Class:EventLoginUsage/Attribute:contact_email+' => 'Email Address of the User', +)); + // // Class: Action // @@ -479,5 +494,47 @@ Dict::Add('EN US', 'English', 'English', array( 'Class:lnkTriggerAction/Attribute:order+' => 'Actions execution order', )); - +// +// Synchro Data Source +// +Dict::Add('EN US', 'English', 'English', array( + 'Core:SynchroAttributes' => 'Attributes', + 'Core:SynchroStatus' => 'Status', + 'Core:Synchro:ErrorsLabel' => 'Errors', + 'Core:Synchro:CreatedLabel' => 'Created', + 'Core:Synchro:ModifiedLabel' => 'Modified', + 'Core:Synchro:UnchangedLabel' => 'Unchanged', + 'Core:Synchro:ReconciledErrorsLabel' => 'Errors', + 'Core:Synchro:ReconciledLabel' => 'Reconciled', + 'Core:Synchro:ReconciledNewLabel' => 'Created', + 'Core:SynchroReconcile:Yes' => 'Yes', + 'Core:SynchroReconcile:No' => 'No', + 'Core:SynchroUpdate:Yes' => 'Yes', + 'Core:SynchroUpdate:No' => 'No', + 'Core:Synchro:LastestStatus' => 'Latest Status', + 'Core:Synchro:History' => 'Synchronization History', + 'Core:Synchro:NeverRun' => 'This synchro was never run. No log yet.', + 'Core:Synchro:SynchroEndedOn_Date' => 'The latest synchronization ended on %1$s.', + 'Core:Synchro:SynchroRunningStartedOn_Date' => 'The synchronization started on $1$s is still running...', + 'Menu:DataSources' => 'Synchronization Data Sources', + 'Menu:DataSources+' => 'All Synchronization Data Sources', + 'Core:Synchro:label_repl_ignored' => 'Ignored (%1$d)', + 'Core:Synchro:label_repl_disappeared' => 'Disappeared (%1$d)', + 'Core:Synchro:label_repl_existing' => 'Existing (%1$d)', + 'Core:Synchro:label_repl_new' => 'New (%1$d)', + 'Core:Synchro:label_obj_deleted' => 'Deleted (%1$d)', + 'Core:Synchro:label_obj_obsoleted' => 'Obsoleted (%1$d)', + 'Core:Synchro:label_obj_disappeared_errors' => 'Errors (%1$d)', + 'Core:Synchro:label_obj_unchanged' => 'Unchanged (%1$d)', + 'Core:Synchro:label_obj_updated' => 'Updated (%1$d)', + 'Core:Synchro:label_obj_updated_errors' => 'Errors (%1$d)', + 'Core:Synchro:label_obj_new_unchanged' => 'Unchanged (%1$d)', + 'Core:Synchro:label_obj_new_updated' => 'Updated (%1$d)', + 'Core:Synchro:label_obj_created' => 'Created (%1$d)', + 'Core:Synchro:label_obj_new_errors' => 'Errors (%1$d)', + 'Core:Synchro:History' => 'Synchronization History', + 'Core:SynchroLogTitle' => '%1$s - %2$s', + 'Core:Synchro:Nb_Replica' => '%1$s Replica', + 'Core:Synchro:Nb_Objects' => '%1$s Objects', +)); ?> diff --git a/synchro/synchrodatasource.class.inc.php b/synchro/synchrodatasource.class.inc.php index d6503b1a1..6428983ee 100644 --- a/synchro/synchrodatasource.class.inc.php +++ b/synchro/synchrodatasource.class.inc.php @@ -138,111 +138,119 @@ class SynchroDataSource extends cmdbAbstractObject } } $oPage->Table($aAttribs, $aValues); - $oPage->SetCurrentTab(Dict::S('Core:SynchroStatus')); - - $sSelectSynchroLog = 'SELECT SynchroLog WHERE sync_source_id = :source_id'; - $oSetSynchroLog = new CMDBObjectSet(DBObjectSearch::FromOQL($sSelectSynchroLog), array('start_date' => false) /* order by*/, array('source_id' => $this->GetKey())); - - if ($oSetSynchroLog->Count() > 0) - { - $oLastLog = $oSetSynchroLog->Fetch(); - $sStartDate = $oLastLog->Get('start_date'); - $oLastLog->Get('stats_nb_replica_seen'); - if ($oLastLog->Get('status') == 'running') - { - // Still running ! - $oPage->p('

'.Dict::Format('Core:Synchro:SynchroRunningStartedOn_Date', $sStartDate).'

'); - } - else - { - $sEndDate = $oLastLog->Get('end_date'); - $oPage->p('

'.Dict::Format('Core:Synchro:SynchroEndedOn_Date', $sEndDate).'

'); - } - - $iDeleted = $oLastLog->Get('stats_nb_obj_deleted'); - $iObsoleted = $oLastLog->Get('stats_nb_obj_obsoleted'); - $iDisappearedErrors = $oLastLog->Get('stats_nb_obj_obsoleted_errors') + $oLastLog->Get('stats_nb_obj_deleted_errors'); - $iUpdated = $oLastLog->Get('stats_nb_obj_updated'); - $iUpdatedErrors = $oLastLog->Get('stats_nb_obj_updated_errors'); - $iReconciled = $oLastLog->Get('stats_nb_replica_reconciled'); - $iReconciledErrors = $oLastLog->Get('stats_nb_replica_reconciled_errors'); - $iCreated = $oLastLog->Get('stats_nb_obj_created'); - $iCreatedErrors = $oLastLog->Get('stats_nb_obj_created_errors'); - $iDisappeared = $iDisappearedErrors + $iObsoleted + $iDeleted; - $iNewErrors = $iCreatedErrors + $iReconciledErrors; - $iNew = $iCreated + $iCreatedErrors + $iReconciled + $iReconciledErrors; - $iExisting = $oLastLog->Get('stats_nb_replica_seen') - $iNew; - $iUnchanged = $iExisting - $iUpdated - $iUpdatedErrors; - $iIgnored = $oLastLog->Get('stats_nb_replica_total') - $iNew - $iExisting - $iDisappeared; - - $fOpacity = 0.3; - $sNewOpacity = ($iNew ==0) ? "opacity:$fOpacity;" : ""; - $sExistingOpacity = ($iExisting ==0) ? "opacity:$fOpacity;" : ""; - $sDisappearedOpacity = ($iDisappeared ==0) ? "opacity:$fOpacity;" : ""; - $sIgnoredOpacity = ($iIgnored ==0) ? "opacity:$fOpacity;" : ""; - - $sCreateOpacity = ($iCreated ==0) ? "opacity:$fOpacity;" : ""; - $sReconciledOpacity = ($iReconciled ==0) ? "opacity:$fOpacity;" : ""; - $sNewErrorsOpacity = ($iNewErrors ==0) ? "opacity:$fOpacity;" : ""; - - $sUnchangedOpacity = ($iUnchanged ==0) ? "opacity:$fOpacity;" : ""; - $sUpdatedOpacity = ($iUpdated ==0) ? "opacity:$fOpacity;" : ""; - $sUpdatedErrorsOpacity = ($iUpdatedErrors ==0) ? "opacity:$fOpacity;" : ""; - - $sDeletedOpacity = ($iDeleted ==0) ? "opacity:$fOpacity;" : ""; - $sObsoletedOpacity = ($iObsoleted ==0) ? "opacity:$fOpacity;" : ""; - $sDisappearedErrorsOpacity = ($iDisappearedErrors ==0) ? "opacity:$fOpacity;" : ""; - - $oPage->add( -<< - .synoptics, .synoptics tr td { background: transparent; padding:10px; font-size:1em; vertical-align:middle; color:#fff; text-align:center;} - .synoptics tr td.arrow { color:#333; border-top: 1px dashed #333; width:100px; } - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Ignored ($iIgnored) 
Disappeared ($iDisappeared)=>Deleted ($iDeleted)
Obsoleted ($iObsoleted)
Errors ($iDisappearedErrors)
Existing ($iExisting)=>Unchanged ($iUnchanged)
Updated ($iUpdated)
Errors ($iUpdatedErrors)
New ($iNew)=>Errors ($iNewErrors)
Reconciled ($iReconciled)
Created ($iCreated)
-EOF - ); - } - else - { - $oPage->p('

'.Dict::S('Core:Synchro:NeverRun').'

'); - } - + $this->DisplayStatusTab($oPage); } parent::DisplayBareRelations($oPage, $bEditMode); } + /** + * Displays the status (SynchroLog) of the datasource in a graphical manner + * @param $oPage WebPage + * @return void + */ + protected function DisplayStatusTab(WebPage $oPage) + { + $oPage->SetCurrentTab(Dict::S('Core:SynchroStatus')); + + $sSelectSynchroLog = 'SELECT SynchroLog WHERE sync_source_id = :source_id'; + $oSetSynchroLog = new CMDBObjectSet(DBObjectSearch::FromOQL($sSelectSynchroLog), array('start_date' => false) /* order by*/, array('source_id' => $this->GetKey())); + + if ($oSetSynchroLog->Count() > 0) + { + $oLastLog = $oSetSynchroLog->Fetch(); + $sStartDate = $oLastLog->Get('start_date'); + $oLastLog->Get('stats_nb_replica_seen'); + if ($oLastLog->Get('status') == 'running') + { + // Still running ! + $oPage->p('

'.Dict::Format('Core:Synchro:SynchroRunningStartedOn_Date', $sStartDate).'

'); + } + else + { + $sEndDate = $oLastLog->Get('end_date'); + $oPage->p('

'.Dict::Format('Core:Synchro:SynchroEndedOn_Date', $sEndDate).'

'); + } + + $oPage->add(' + + + +EOF +); + $oPage->add($this->HtmlBox('repl_ignored', $iIgnored, '#999').''); + $oPage->add("\n"); + $oPage->add($this->HtmlBox('repl_disappeared', $iDisappeared, '#630', 'rowspan="3"').''.$this->HtmlBox('obj_deleted', $iDeleted, '#000')); + $oPage->add("\n"); + $oPage->add($this->HtmlBox('obj_obsoleted', $iDisappeared, '#630')); + $oPage->add("\n"); + $oPage->add($this->HtmlBox('obj_disappeared_errors', $iDisappearedErrors, '#C00')); + $oPage->add("\n"); + $oPage->add($this->HtmlBox('repl_existing', $iExisting, '#093', 'rowspan="3"').''.$this->HtmlBox('obj_unchanged', $iUnchanged, '#393')); + $oPage->add("\n"); + $oPage->add($this->HtmlBox('obj_updated', $iUpdated, '#3C3')); + $oPage->add("\n"); + $oPage->add($this->HtmlBox('obj_updated_errors', $iUpdatedErrors, '#C00')); + $oPage->add("\n"); + $oPage->add($this->HtmlBox('repl_new', $iNew, '#339', 'rowspan="4"').''.$this->HtmlBox('obj_new_unchanged', $iNewUnchanged, '#393')); + $oPage->add("\n"); + $oPage->add($this->HtmlBox('obj_new_updated', $iNewUpdated, '#3C3')); + $oPage->add("\n"); + $oPage->add($this->HtmlBox('obj_created', $iCreated, '#339')); + $oPage->add("\n"); + $oPage->add($this->HtmlBox('obj_new_errors', $iNewErrors, '#C00')); + $oPage->add("\n
'); + $oPage->add('

'.Dict::S('Core:Synchro:History').'

'); + $oSetSynchroLog->Rewind(); + $oPage->add(''); + $oPage->add('
'); + $iDeleted = $oLastLog->Get('stats_nb_obj_deleted'); + $iObsoleted = $oLastLog->Get('stats_nb_obj_obsoleted'); + $iDisappearedErrors = $oLastLog->Get('stats_nb_obj_obsoleted_errors') + $oLastLog->Get('stats_nb_obj_deleted_errors'); + $iUpdated = $oLastLog->Get('stats_nb_obj_updated'); + $iUpdatedErrors = $oLastLog->Get('stats_nb_obj_updated_errors'); + $iNewUpdated = $oLastLog->Get('stats_nb_obj_new_updated'); + $iNewUnchanged = $oLastLog->Get('stats_nb_obj_new_unchanged'); + $iReconciledErrors = $oLastLog->Get('stats_nb_replica_reconciled_errors'); + $iCreated = $oLastLog->Get('stats_nb_obj_created'); + $iCreatedErrors = $oLastLog->Get('stats_nb_obj_created_errors'); + $iDisappeared = $iDisappearedErrors + $iObsoleted + $iDeleted; + $iNewErrors = $iCreatedErrors + $iReconciledErrors; + $iNew = $iCreated + $iCreatedErrors + $iNewUpdated + $iNewUnchanged + $iReconciledErrors; + $iExisting = $oLastLog->Get('stats_nb_replica_seen') - $iNew; + $iUnchanged = $iExisting - $iUpdated - $iUpdatedErrors; + $iIgnored = $oLastLog->Get('stats_nb_replica_total') - $iNew - $iExisting - $iDisappeared; + + $iNbObjects = $iNew + $iExisting + $iDisappeared; + $iReplicas = $iNbObjects + $iIgnored; + $sNbReplica = Dict::Format('Core:Synchro:Nb_Replica', "$iReplicas"); + $sNbObjects = Dict::Format('Core:Synchro:Nb_Objects', "$iNbObjects"); + $oPage->add( +<< +
$sNbReplica $sNbObjects
 
=>
=>
=>
\n"); + $oPage->add(''); + } + else + { + $oPage->p('

'.Dict::S('Core:Synchro:NeverRun').'

'); + } + } + + public function HtmlBox($sId, $iCount, $sColor, $sHTMLAttribs = '') + { + $sCount = "$iCount"; + $sLabel = Dict::Format('Core:Synchro:label_'.$sId, $iCount); + $sOpacity = ($iCount==0) ? "opacity:0.3;" : ""; + return "$sLabel"; + } public function GetAttributeFlags($sAttCode) { if (($sAttCode == 'scope_class') && (!$this->IsNew())) @@ -445,8 +453,10 @@ EOF $oStatLog->Set('stats_nb_obj_created_errors', 0); $oStatLog->Set('stats_nb_obj_updated', 0); $oStatLog->Set('stats_nb_obj_updated_errors', 0); - $oStatLog->Set('stats_nb_replica_reconciled', 0); +// $oStatLog->Set('stats_nb_replica_reconciled', 0); $oStatLog->Set('stats_nb_replica_reconciled_errors', 0); + $oStatLog->Set('stats_nb_obj_new_updated', 0); + $oStatLog->Set('stats_nb_obj_new_unchanged',0); $sSelectTotal = "SELECT SynchroReplica WHERE sync_source_id = :source_id"; $oSetTotal = new DBObjectSet(DBObjectSearch::FromOQL($sSelectTotal), array() /* order by*/, array('source_id' => $this->GetKey())); @@ -841,12 +851,14 @@ class SynchroLog extends cmdbAbstractObject MetaModel::Init_AddAttribute(new AttributeInteger("stats_nb_obj_created_errors", array("allowed_values"=>null, "sql"=>"stats_nb_obj_created_errors", "default_value"=>0, "is_null_allowed"=>false, "depends_on"=>array()))); MetaModel::Init_AddAttribute(new AttributeInteger("stats_nb_obj_updated", array("allowed_values"=>null, "sql"=>"stats_nb_obj_updated", "default_value"=>0, "is_null_allowed"=>false, "depends_on"=>array()))); MetaModel::Init_AddAttribute(new AttributeInteger("stats_nb_obj_updated_errors", array("allowed_values"=>null, "sql"=>"stats_nb_obj_updated_errors", "default_value"=>0, "is_null_allowed"=>false, "depends_on"=>array()))); - MetaModel::Init_AddAttribute(new AttributeInteger("stats_nb_replica_reconciled", array("allowed_values"=>null, "sql"=>"stats_nb_replica_reconciled", "default_value"=>0, "is_null_allowed"=>false, "depends_on"=>array()))); +// MetaModel::Init_AddAttribute(new AttributeInteger("stats_nb_replica_reconciled", array("allowed_values"=>null, "sql"=>"stats_nb_replica_reconciled", "default_value"=>0, "is_null_allowed"=>false, "depends_on"=>array()))); MetaModel::Init_AddAttribute(new AttributeInteger("stats_nb_replica_reconciled_errors", array("allowed_values"=>null, "sql"=>"stats_nb_replica_reconciled_errors", "default_value"=>0, "is_null_allowed"=>false, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeInteger("stats_nb_obj_new_updated", array("allowed_values"=>null, "sql"=>"stats_nb_obj_new_updated", "default_value"=>0, "is_null_allowed"=>false, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeInteger("stats_nb_obj_new_unchanged", array("allowed_values"=>null, "sql"=>"stats_nb_obj_new_unchanged", "default_value"=>0, "is_null_allowed"=>false, "depends_on"=>array()))); // Display lists - MetaModel::Init_SetZListItems('details', array('sync_source_id', 'start_date', 'end_date', 'status', 'stats_nb_replica_total', 'stats_nb_replica_seen', 'stats_nb_obj_created', 'stats_nb_replica_reconciled', 'stats_nb_obj_updated', 'stats_nb_obj_obsoleted', 'stats_nb_obj_deleted', - 'stats_nb_obj_created_errors', 'stats_nb_replica_reconciled_errors', 'stats_nb_obj_updated_errors', 'stats_nb_obj_obsoleted_errors', 'stats_nb_obj_deleted_errors')); // Attributes to be displayed for the complete details + MetaModel::Init_SetZListItems('details', array('sync_source_id', 'start_date', 'end_date', 'status', 'stats_nb_replica_total', 'stats_nb_replica_seen', 'stats_nb_obj_created', /*'stats_nb_replica_reconciled',*/ 'stats_nb_obj_updated', 'stats_nb_obj_obsoleted', 'stats_nb_obj_deleted', + 'stats_nb_obj_created_errors', 'stats_nb_replica_reconciled_errors', 'stats_nb_obj_updated_errors', 'stats_nb_obj_obsoleted_errors', 'stats_nb_obj_deleted_errors', 'stats_nb_obj_new_unchanged', 'stats_nb_obj_new_updated')); // Attributes to be displayed for the complete details MetaModel::Init_SetZListItems('list', array('sync_source_id', 'start_date', 'end_date', 'status', 'stats_nb_replica_seen')); // Attributes to be displayed for a list // Search criteria // MetaModel::Init_SetZListItems('standard_search', array('name')); // Criteria of the std search form @@ -1005,12 +1017,12 @@ class SynchroReplica extends DBObject if ($oDataSource->Get('action_on_one') == 'update') { $oDestObj = $oDestSet->Fetch(); - $this->UpdateObjectFromReplica($oDestObj, $aAttributes, $oChange, $oStatLog, $aTraces, 'stats_nb_replica_reconciled'); + $this->UpdateObjectFromReplica($oDestObj, $aAttributes, $oChange, $oStatLog, $aTraces, 'stats_nb_obj_new', 'stats_nb_replica_reconciled_errors'); $this->Set('dest_id', $oDestObj->GetKey()); $this->Set('status_dest_creator', false); $this->Set('dest_class', get_class($oDestObj)); - $oStatLog->Inc('stats_nb_replica_reconciled'); + $oStatLog->Inc('stats_nb_replica_reconciled'); //@@@ } else { @@ -1037,7 +1049,7 @@ class SynchroReplica extends DBObject { // assumed to be 'take_first' $oDestObj = $oDestSet->Fetch(); - $this->UpdateObjectFromReplica($oDestObj, $aAttributes, $oChange, $oStatLog, $aTraces, 'stats_nb_replica_reconciled'); + $this->UpdateObjectFromReplica($oDestObj, $aAttributes, $oChange, $oStatLog, $aTraces, 'stats_nb_obj_new', 'stats_nb_replica_reconciled_errors'); $this->Set('dest_id', $oDestObj->GetKey()); $this->Set('status_dest_creator', false); $this->Set('dest_class', get_class($oDestObj)); @@ -1055,7 +1067,7 @@ class SynchroReplica extends DBObject } else { - $this->UpdateObjectFromReplica($oDestObj, $aAttributes, $oChange, $oStatLog, $aTraces, 'stats_nb_obj_updated'); + $this->UpdateObjectFromReplica($oDestObj, $aAttributes, $oChange, $oStatLog, $aTraces, 'stats_nb_obj', 'stats_nb_obj_updated_errors'); } break; @@ -1067,7 +1079,7 @@ 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, &$aTraces, $sStatsCode) + protected function UpdateObjectFromReplica($oDestObj, $aAttributes, $oChange, &$oStatLog, &$aTraces, $sStatsCode, $sStatsCodeError) { $aValueTrace = array(); foreach($aAttributes as $sAttCode) @@ -1081,9 +1093,18 @@ class SynchroReplica extends DBObject } try { - $oDestObj->DBUpdateTracked($oChange); - $aTraces[] = "Updated object ".$oDestObj->GetHyperLink()." (".implode(', ', $aValueTrace).")"; - $oStatLog->Inc($sStatsCode); + // Really modified ? + if ($oDestObj->IsModified()) + { + $oDestObj->DBUpdateTracked($oChange); + $aTraces[] = "Updated object ".$oDestObj->GetHyperLink()." (".implode(', ', $aValueTrace).")"; + $oStatLog->Inc($sStatsCode.'_updated'); + } + else + { + $aTraces[] = "Unchanged object ".$oDestObj->GetHyperLink()." (".implode(', ', $aValueTrace).")"; + $oStatLog->Inc($sStatsCode.'_unchanged'); + } $this->Set('status_last_error', ''); $this->Set('status', 'synchronized'); @@ -1092,7 +1113,7 @@ class SynchroReplica extends DBObject { $aTraces[] = "Failed to update destination object: {$e->getMessage()}"; $this->SetLastError('Unable to update destination object: ', $e); - $oStatLog->Inc($sStatsCode.'_errors'); + $oStatLog->Inc($sStatsCodeError); } }