Enhancement: when an (optional) external key cannot be reconciled, log a warning on the replica. the replicas containing a warning are then processed everytime in case the ext key changes

Also improved the search/display of replicas

SVN:trunk[1675]
This commit is contained in:
Denis Flaven
2011-11-18 11:29:04 +00:00
parent a5547d4d26
commit 18c9852db3
4 changed files with 187 additions and 27 deletions

View File

@@ -53,6 +53,9 @@ try
{
throw new ApplicationException(Dict::Format('UI:Error:1ParametersMissing', 'oql'));
}
$oFilter = DBObjectSearch::FromOQL($sOQL);
$oBlock1 = new DisplayBlock($oFilter, 'search', false, array('menu'=>false));
$oBlock1->Display($oP, 0);
$oP->add('<p class="page-header">'.MetaModel::GetClassIcon('SynchroReplica').Dict::S('Core:SynchroReplica:ListOfReplicas').'</p>');
$iSourceId = utils::ReadParam('datasource', null);
if ($iSourceId != null)
@@ -60,7 +63,6 @@ try
$oSource = MetaModel::GetObject('SynchroDataSource', $iSourceId);
$oP->p(Dict::Format('Core:SynchroReplica:BackToDataSource', $oSource->GetHyperlink()).'</a>');
}
$oFilter = DBObjectSearch::FromOQL($sOQL);
$oBlock = new DisplayBlock($oFilter, 'list', false, array('menu'=>false));
$oBlock->Display($oP, 1);
break;

View File

@@ -166,12 +166,12 @@ foreach(explode(',', $sDataSourcesList) as $iSDS)
$oP->p("Objects deletion errors: ".$oStatLog->Get('stats_nb_obj_deleted_errors'));
$oP->p("Objects obsoleted: ".$oStatLog->Get('stats_nb_obj_obsoleted'));
$oP->p("Objects obsolescence errors: ".$oStatLog->Get('stats_nb_obj_obsoleted_errors'));
$oP->p("Objects created: ".$oStatLog->Get('stats_nb_obj_created'));
$oP->p("Objects created: ".$oStatLog->Get('stats_nb_obj_created')." (".$oStatLog->Get('stats_nb_obj_created_warnings')." warnings)");
$oP->p("Objects creation errors: ".$oStatLog->Get('stats_nb_obj_created_errors'));
$oP->p("Objects updated: ".$oStatLog->Get('stats_nb_obj_updated'));
$oP->p("Objects updated: ".$oStatLog->Get('stats_nb_obj_updated')." (".$oStatLog->Get('stats_nb_obj_updated_warnings')." warnings)");
$oP->p("Objects update errors: ".$oStatLog->Get('stats_nb_obj_updated_errors'));
$oP->p("Objects reconciled (updated): ".$oStatLog->Get('stats_nb_obj_new_updated'));
$oP->p("Objects reconciled (unchanged): ".$oStatLog->Get('stats_nb_obj_new_unchanged'));
$oP->p("Objects reconciled (updated): ".$oStatLog->Get('stats_nb_obj_new_updated')." (".$oStatLog->Get('stats_nb_obj_new_updated_warnings')." warnings)");
$oP->p("Objects reconciled (unchanged): ".$oStatLog->Get('stats_nb_obj_new_unchanged')." (".$oStatLog->Get('stats_nb_obj_new_updated_warnings')." warnings)");
$oP->p("Objects reconciliation errors: ".$oStatLog->Get('stats_nb_replica_reconciled_errors'));
$oP->p("Replica disappeared, no action taken: ".$oStatLog->Get('stats_nb_replica_disappeared_no_action'));
}

View File

@@ -641,12 +641,12 @@ try
$oP->add_comment("Objects deletion errors: ".$oStatLog->Get('stats_nb_obj_deleted_errors'));
$oP->add_comment("Objects obsoleted: ".$oStatLog->Get('stats_nb_obj_obsoleted'));
$oP->add_comment("Objects obsolescence errors: ".$oStatLog->Get('stats_nb_obj_obsoleted_errors'));
$oP->add_comment("Objects created: ".$oStatLog->Get('stats_nb_obj_created'));
$oP->add_comment("Objects created: ".$oStatLog->Get('stats_nb_obj_created')." (".$oStatLog->Get('stats_nb_obj_created_warnings')." warnings)");
$oP->add_comment("Objects creation errors: ".$oStatLog->Get('stats_nb_obj_created_errors'));
$oP->add_comment("Objects updated: ".$oStatLog->Get('stats_nb_obj_updated'));
$oP->add_comment("Objects updated: ".$oStatLog->Get('stats_nb_obj_updated')." (".$oStatLog->Get('stats_nb_obj_updated_warnings')." warnings)");
$oP->add_comment("Objects update errors: ".$oStatLog->Get('stats_nb_obj_updated_errors'));
$oP->add_comment("Objects reconciled (updated): ".$oStatLog->Get('stats_nb_obj_new_updated'));
$oP->add_comment("Objects reconciled (unchanged): ".$oStatLog->Get('stats_nb_obj_new_unchanged'));
$oP->add_comment("Objects reconciled (updated): ".$oStatLog->Get('stats_nb_obj_new_updated')." (".$oStatLog->Get('stats_nb_obj_new_updated_warnings')." warnings)");
$oP->add_comment("Objects reconciled (unchanged): ".$oStatLog->Get('stats_nb_obj_new_unchanged')." (".$oStatLog->Get('stats_nb_obj_new_updated_warnings')." warnings)");
$oP->add_comment("Objects reconciliation errors: ".$oStatLog->Get('stats_nb_replica_reconciled_errors'));
$oP->add_comment("Replica disappeared, no action taken: ".$oStatLog->Get('stats_nb_replica_disappeared_no_action'));
}

View File

@@ -251,6 +251,19 @@ class SynchroDataSource extends cmdbAbstractObject
$sEndDate = $oLastLog->Get('end_date');
$iLastLog = $oLastLog->GetKey();
$oPage->p('<h2>'.Dict::Format('Core:Synchro:SynchroEndedOn_Date', $sEndDate).'</h2>');
$sOQL = "SELECT SynchroReplica WHERE sync_source_id=$iDSid";
$oSet = new DBObjectSet(DBObjectSearch::FromOQL($sOQL));
$iCountAllReplicas = $oSet->Count();
$sAllReplicas = "<a href=\"../synchro/replica.php?operation=oql&datasource=$iDSid&oql=$sOQL\">$iCountAllReplicas</a>";
$sOQL = "SELECT SynchroReplica WHERE sync_source_id=$iDSid AND status_last_error !=''";
$oSet = new DBObjectSet(DBObjectSearch::FromOQL($sOQL));
$iCountAllErrors = $oSet->Count();
$sAllErrors = "<a href=\"../synchro/replica.php?operation=oql&datasource=$iDSid&oql=$sOQL\">$iCountAllErrors</a>";
$sOQL = "SELECT SynchroReplica WHERE sync_source_id=$iDSid AND status_last_warning !=''";
$oSet = new DBObjectSet(DBObjectSearch::FromOQL($sOQL));
$iCountAllWarnings = $oSet->Count();
$sAllWarnings = "<a href=\"../synchro/replica.php?operation=oql&datasource=$iDSid&oql=$sOQL\">$iCountAllWarnings</a>";
$oPage->p('<h2>'.Dict::Format('Core:Synchro:ListReplicas_AllReplicas_Errors_Warnings', $sAllReplicas, $sAllErrors, $sAllWarnings).'</h2>');
}
$oPage->add('<table class="synoptics"><tr><td style="color:#333;vertical-align:top">');
@@ -273,6 +286,18 @@ class SynchroDataSource extends cmdbAbstractObject
$sScript .= "};\n";
$sScript .= <<<EOF
var sLastLog = '$iLastLog';
function ToggleSynoptics(sId, bShow)
{
if (bShow)
{
$(sId).show();
}
else
{
$(sId).hide();
}
}
function UpdateSynoptics(id)
{
var aValues = aSynchroLog[id];
@@ -310,6 +335,12 @@ class SynchroDataSource extends cmdbAbstractObject
{
$('#disappeared_errors_link').hide();
}
ToggleSynoptics('#cw_obj_created_warnings', aValues['obj_created_warnings'] > 0);
ToggleSynoptics('#cw_obj_new_updated_warnings', aValues['obj_new_updated_warnings'] > 0);
ToggleSynoptics('#cw_obj_new_unchanged_warnings', aValues['obj_new_unchanged_warnings'] > 0);
ToggleSynoptics('#cw_obj_updated_warnings', aValues['obj_updated_warnings'] > 0);
ToggleSynoptics('#cw_obj_unchanged_warnings', aValues['obj_unchanged_warnings'] > 0);
}
EOF
;
@@ -375,6 +406,10 @@ EOF
$sCount = "<span id=\"c_{$sId}\">$iCount</span>";
$sLabel = Dict::Format('Core:Synchro:label_'.$sId, $sCount);
$sOpacity = ($iCount==0) ? "opacity:0.3;" : "";
if (isset($aData[$sId.'_warnings']))
{
$sLabel .= " <span id=\"cw_{$sId}_warnings\"><img src=\"../images/error.png\" style=\"vertical-align:middle\"/> (<span id=\"c_{$sId}_warnings\">".$aData[$sId.'_warnings']."</span>)</span>";
}
return "<td id=\"$sId\" style=\"background-color:$sColor;$sOpacity;\" {$sHTMLAttribs}>{$sLabel}{$sErrorLink}</td>";
}
@@ -387,11 +422,15 @@ EOF
'obj_disappeared_errors' => $oLastLog->Get('stats_nb_obj_obsoleted_errors') + $oLastLog->Get('stats_nb_obj_deleted_errors'),
'obj_disappeared_no_action' => $oLastLog->Get('stats_nb_replica_disappeared_no_action'),
'obj_updated' => $oLastLog->Get('stats_nb_obj_updated'),
'obj_updated_warnings' => $oLastLog->Get('stats_nb_obj_updated_warnings'),
'obj_updated_errors' => $oLastLog->Get('stats_nb_obj_updated_errors'),
'obj_new_updated' => $oLastLog->Get('stats_nb_obj_new_updated'),
'obj_new_updated_warnings' => $oLastLog->Get('stats_nb_obj_new_updated_warnings'),
'obj_new_unchanged' => $oLastLog->Get('stats_nb_obj_new_unchanged'),
'obj_created' => $oLastLog->Get('stats_nb_obj_created'),
'obj_created_warnings' => $oLastLog->Get('stats_nb_obj_created_warnings'),
'obj_created_errors' => $oLastLog->Get('stats_nb_obj_created_errors'),
'obj_unchanged_warnings' => $oLastLog->Get('stats_nb_obj_unchanged_warnings'),
);
$iReconciledErrors = $oLastLog->Get('stats_nb_replica_reconciled_errors');
$iDisappeared = $aData['obj_disappeared_errors'] + $aData['obj_obsoleted'] + $aData['obj_deleted'] + $aData['obj_disappeared_no_action'];
@@ -949,13 +988,18 @@ EOF
$oStatLog->Set('stats_nb_obj_obsoleted_errors', 0);
$oStatLog->Set('stats_nb_obj_created', 0);
$oStatLog->Set('stats_nb_obj_created_errors', 0);
$oStatLog->Set('stats_nb_obj_created_warnings', 0);
$oStatLog->Set('stats_nb_obj_updated', 0);
$oStatLog->Set('stats_nb_obj_updated_warnings', 0);
$oStatLog->Set('stats_nb_obj_updated_errors', 0);
// $oStatLog->Set('stats_nb_replica_reconciled', 0);
$oStatLog->Set('stats_nb_obj_unchanged_warnings', 0);
// $oStatLog->Set('stats_nb_replica_reconciled', 0);
$oStatLog->Set('stats_nb_replica_reconciled_errors', 0);
$oStatLog->Set('stats_nb_replica_disappeared_no_action', 0);
$oStatLog->Set('stats_nb_obj_new_updated', 0);
$oStatLog->Set('stats_nb_obj_new_updated_warnings', 0);
$oStatLog->Set('stats_nb_obj_new_unchanged',0);
$oStatLog->Set('stats_nb_obj_new_unchanged_warnings',0);
$sSelectTotal = "SELECT SynchroReplica WHERE sync_source_id = :source_id";
$oSetTotal = new DBObjectSet(DBObjectSearch::FromOQL($sSelectTotal), array() /* order by*/, array('source_id' => $this->GetKey()));
@@ -989,14 +1033,14 @@ EOF
$sStatistics .= "<li>".$oStatLog->GetLabel('stats_nb_obj_deleted_errors').": ".$oStatLog->Get('stats_nb_obj_deleted_errors')."</li>\n";
$sStatistics .= "<li>".$oStatLog->GetLabel('stats_nb_obj_obsoleted').": ".$oStatLog->Get('stats_nb_obj_obsoleted')."</li>\n";
$sStatistics .= "<li>".$oStatLog->GetLabel('stats_nb_obj_obsoleted_errors').": ".$oStatLog->Get('stats_nb_obj_obsoleted_errors')."</li>\n";
$sStatistics .= "<li>".$oStatLog->GetLabel('stats_nb_obj_created').": ".$oStatLog->Get('stats_nb_obj_created')."</li>\n";
$sStatistics .= "<li>".$oStatLog->GetLabel('stats_nb_obj_created').": ".$oStatLog->Get('stats_nb_obj_created')." (".$oStatLog->Get('stats_nb_obj_created_warnings')." warnings)"."</li>\n";
$sStatistics .= "<li>".$oStatLog->GetLabel('stats_nb_obj_created_errors').": ".$oStatLog->Get('stats_nb_obj_created_errors')."</li>\n";
$sStatistics .= "<li>".$oStatLog->GetLabel('stats_nb_obj_updated').": ".$oStatLog->Get('stats_nb_obj_updated')."</li>\n";
$sStatistics .= "<li>".$oStatLog->GetLabel('stats_nb_obj_updated').": ".$oStatLog->Get('stats_nb_obj_updated')." (".$oStatLog->Get('stats_nb_obj_updated_warnings')." warnings)"."</li>\n";
$sStatistics .= "<li>".$oStatLog->GetLabel('stats_nb_obj_updated_errors').": ".$oStatLog->Get('stats_nb_obj_updated_errors')."</li>\n";
$sStatistics .= "<li>".$oStatLog->GetLabel('stats_nb_replica_reconciled_errors').": ".$oStatLog->Get('stats_nb_replica_reconciled_errors')."</li>\n";
$sStatistics .= "<li>".$oStatLog->GetLabel('stats_nb_replica_disappeared_no_action').": ".$oStatLog->Get('stats_nb_replica_disappeared_no_action')."</li>\n";
$sStatistics .= "<li>".$oStatLog->GetLabel('stats_nb_obj_new_updated').": ".$oStatLog->Get('stats_nb_obj_new_updated')."</li>\n";
$sStatistics .= "<li>".$oStatLog->GetLabel('stats_nb_obj_new_unchanged').": ".$oStatLog->Get('stats_nb_obj_new_unchanged')."</li>\n";
$sStatistics .= "<li>".$oStatLog->GetLabel('stats_nb_obj_new_updated').": ".$oStatLog->Get('stats_nb_obj_new_updated')." (".$oStatLog->Get('stats_nb_obj_new_updated_warnings')." warnings)"."</li>\n";
$sStatistics .= "<li>".$oStatLog->GetLabel('stats_nb_obj_new_unchanged').": ".$oStatLog->Get('stats_nb_obj_new_unchanged')." (".$oStatLog->Get('stats_nb_obj_new_unchanged_warnings')." warnings)"."</li>\n";
$sStatistics .= "</ul>\n";
$this->SendNotification("errors ($iErrors)", "<p>The synchronization has been executed, $iErrors errors have been encountered. Click <a href=\"$sIssuesURL\">here</a> to see the records being currently in error.</p>".$sStatistics);
@@ -1188,9 +1232,9 @@ EOF
$oSetSeen = new DBObjectSet(DBObjectSearch::FromOQL($sSelectSeen), array() /* order by*/, array('source_id' => $this->GetKey(), 'last_import' => $sLimitDate));
$oStatLog->Set('stats_nb_replica_seen', $oSetSeen->Count());
// Get all the replicas that are 'new' or modified
// Get all the replicas that are 'new' or modified or synchronized with a warning
//
$sSelectToSync = "SELECT SynchroReplica WHERE (status = 'new' OR status = 'modified') AND sync_source_id = :source_id AND status_last_seen >= :last_import";
$sSelectToSync = "SELECT SynchroReplica WHERE (status = 'new' OR status = 'modified' OR (status = 'synchronized' AND status_last_warning != '')) AND sync_source_id = :source_id AND status_last_seen >= :last_import";
$oSetToSync = new DBObjectSet(DBObjectSearch::FromOQL($sSelectToSync), array() /* order by*/, array('source_id' => $this->GetKey(), 'last_import' => $sLimitDate) /* aArgs */, $aExtDataSpec, 0 /* limitCount */, 0 /* limitStart */);
while($oReplica = $oSetToSync->Fetch())
@@ -1492,15 +1536,20 @@ class SynchroLog extends DBObject
MetaModel::Init_AddAttribute(new AttributeInteger("stats_nb_obj_obsoleted_errors", array("allowed_values"=>null, "sql"=>"stats_nb_obj_obsoleted_errors", "default_value"=>0, "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeInteger("stats_nb_obj_created", array("allowed_values"=>null, "sql"=>"stats_nb_obj_created", "default_value"=>0, "is_null_allowed"=>false, "depends_on"=>array())));
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_created_warnings", array("allowed_values"=>null, "sql"=>"stats_nb_obj_created_warnings", "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_obj_updated_warnings", array("allowed_values"=>null, "sql"=>"stats_nb_obj_updated_warnings", "default_value"=>0, "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeInteger("stats_nb_obj_unchanged_warnings", array("allowed_values"=>null, "sql"=>"stats_nb_obj_unchanged_warnings", "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_replica_disappeared_no_action", array("allowed_values"=>null, "sql"=>"stats_nb_replica_disappeared_no_action", "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_updated_warnings", array("allowed_values"=>null, "sql"=>"stats_nb_obj_new_updated_warnings", "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())));
MetaModel::Init_AddAttribute(new AttributeInteger("stats_nb_obj_new_unchanged_warnings", array("allowed_values"=>null, "sql"=>"stats_nb_obj_new_unchanged_warnings", "default_value"=>0, "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeText("last_error", array("allowed_values"=>null, "sql"=>"last_error", "default_value"=>'', "is_null_allowed"=>true, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeLongText("traces", array("allowed_values"=>null, "sql"=>"traces", "default_value"=>'', "is_null_allowed"=>true, "depends_on"=>array())));
@@ -1604,6 +1653,7 @@ class SynchroLog extends DBObject
class SynchroReplica extends DBObject implements iDisplay
{
static $aSearches = array(); // Cache of OQL queries used for reconciliation (per data source)
protected $aWarnings;
public static function Init()
{
@@ -1632,7 +1682,8 @@ class SynchroReplica extends DBObject implements iDisplay
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())));
MetaModel::Init_AddAttribute(new AttributeBoolean("status_dest_creator", array("allowed_values"=>null, "sql"=>"status_dest_creator", "default_value"=>0, "is_null_allowed"=>true, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeString("status_last_error", array("allowed_values"=>null, "sql"=>"status_last_error", "default_value"=>'', "is_null_allowed"=>true, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeString("status_last_warning", array("allowed_values"=>null, "sql"=>"status_last_warning", "default_value"=>'', "is_null_allowed"=>true, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeDateTime("info_creation_date", array("allowed_values"=>null, "sql"=>"info_creation_date", "default_value"=>"", "is_null_allowed"=>true, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeDateTime("info_last_modified", array("allowed_values"=>null, "sql"=>"info_last_modified", "default_value"=>"", "is_null_allowed"=>true, "depends_on"=>array())));
@@ -1640,17 +1691,65 @@ class SynchroReplica extends DBObject implements iDisplay
MetaModel::Init_SetZListItems('details', array('' .
'col:0'=> array(
'fieldset:SynchroDataSource:Definition' => array('sync_source_id','dest_id','dest_class'),
'fieldset:SynchroDataSource:Status' => array('status','status_last_seen','status_dest_creator','status_last_error'),
'fieldset:SynchroDataSource:Status' => array('status','status_last_seen','status_dest_creator','status_last_error','status_last_warning'),
'fieldset:SynchroDataSource:Information' => array('info_creation_date','info_last_modified'))
)
);
MetaModel::Init_SetZListItems('list', array('sync_source_id', 'dest_id', 'dest_class', 'status_last_seen', 'status', 'status_dest_creator', 'status_last_error')); // Attributes to be displayed for a list
MetaModel::Init_SetZListItems('list', array('sync_source_id', 'dest_id', 'dest_class', 'status_last_seen', 'status', 'status_dest_creator', 'status_last_error', 'status_last_warning')); // Attributes to be displayed for a list
// Search criteria
MetaModel::Init_SetZListItems('standard_search', array('sync_source_id', 'status_last_seen', 'status', 'status_dest_creator', 'dest_class', 'dest_id', 'status_last_error')); // Criteria of the std search form
MetaModel::Init_SetZListItems('standard_search', array('sync_source_id', 'status_last_seen', 'status', 'status_dest_creator', 'dest_class', 'dest_id', 'status_last_error', 'status_last_warning')); // Criteria of the std search form
// MetaModel::Init_SetZListItems('advanced_search', array('name')); // Criteria of the advanced search form
}
public function __construct($aRow = null, $sClassAlias = '', $aAttToLoad = null, $aExtendedDataSpec = null)
{
parent::__construct($aRow, $sClassAlias, $aAttToLoad, $aExtendedDataSpec);
$this->aWarnings = array();
}
public function DBInsert()
protected function AddWarning($sWarningMessage)
{
$this->aWarnings[] = $sWarningMessage;
}
protected function ResetWarnings()
{
$this->aWarnings = array();
}
protected function HasWarnings()
{
return (count($this->aWarnings) > 0);
}
protected function RecordWarnings()
{
$sWarningMessage = '';
$MAX_WARNING_LENGTH = 255;
switch(count($this->aWarnings))
{
case 0:
$sWarningMessage = '';
break;
case 1:
$sWarningMessage = $this->aWarnings[0];
break;
default:
$sWarningMessage = count($this->aWarnings)." warnings: ".implode(' '.$this->aWarnings);
break;
}
if (strlen($sWarningMessage) > $MAX_WARNING_LENGTH)
{
$sWarningMessage = substr($sWarningMessage, 0, $MAX_WARNING_LENGTH - 3).'...';
}
$this->Set('status_last_warning', $sWarningMessage);
}
public function DBInsert()
{
throw new CoreException('A synchronization replica must be created only by the mean of triggers');
}
@@ -1696,6 +1795,7 @@ class SynchroReplica extends DBObject implements iDisplay
public function Synchro($oDataSource, $aReconciliationKeys, $aAttributes, $oChange, &$oStatLog)
{
$this->ResetWarnings();
switch($this->Get('status'))
{
case 'new':
@@ -1722,6 +1822,7 @@ class SynchroReplica extends DBObject implements iDisplay
}
else
{
// TO DO: can we retry this ??
// Reconciliation could not be performed - log and EXIT
$oStatLog->AddTrace("Could not reconcile on null value for attribute '$sFilterCode'", $this);
$this->SetLastError("Could not reconcile on null value for attribute '$sFilterCode'");
@@ -1745,6 +1846,10 @@ class SynchroReplica extends DBObject implements iDisplay
if ($oDataSource->Get('action_on_zero') == 'create')
{
$this->CreateObjectFromReplica($oDataSource->GetTargetClass(), $aAttributes, $oChange, $oStatLog);
if ($this->HasWarnings())
{
$oStatLog->Inc('stats_nb_obj_created_warnings');
}
}
else // assumed to be 'error'
{
@@ -1760,9 +1865,20 @@ class SynchroReplica extends DBObject implements iDisplay
if ($oDataSource->Get('action_on_one') == 'update')
{
$oDestObj = $oDestSet->Fetch();
$this->UpdateObjectFromReplica($oDestObj, $aAttributes, $oChange, $oStatLog, 'stats_nb_obj_new', 'stats_nb_replica_reconciled_errors');
$bModified = $this->UpdateObjectFromReplica($oDestObj, $aAttributes, $oChange, $oStatLog, 'stats_nb_obj_new', 'stats_nb_replica_reconciled_errors');
$this->Set('dest_id', $oDestObj->GetKey());
$this->Set('dest_class', get_class($oDestObj));
if ($this->HasWarnings())
{
if ($bModified)
{
$oStatLog->Inc('stats_nb_obj_new_updated_warnings');
}
else
{
$oStatLog->Inc('stats_nb_obj_new_unchanged_warnings');
}
}
}
else
{
@@ -1786,20 +1902,37 @@ class SynchroReplica extends DBObject implements iDisplay
elseif ($oDataSource->Get('action_on_multiple') == 'create')
{
$this->CreateObjectFromReplica($oDataSource->GetTargetClass(), $aAttributes, $oChange, $oStatLog);
if ($this->HasWarnings())
{
$oStatLog->Inc('stats_nb_obj_created_warnings');
}
}
else
{
// assumed to be 'take_first'
$oDestObj = $oDestSet->Fetch();
$this->UpdateObjectFromReplica($oDestObj, $aAttributes, $oChange, $oStatLog, 'stats_nb_obj_new', 'stats_nb_replica_reconciled_errors');
$bModified = $this->UpdateObjectFromReplica($oDestObj, $aAttributes, $oChange, $oStatLog, 'stats_nb_obj_new', 'stats_nb_replica_reconciled_errors');
$this->Set('dest_id', $oDestObj->GetKey());
$this->Set('dest_class', get_class($oDestObj));
if ($this->HasWarnings())
{
if ($bModified)
{
$oStatLog->Inc('stats_nb_obj_new_updated_warnings');
}
else
{
$oStatLog->Inc('stats_nb_obj_new_unchanged_warnings');
}
}
}
}
$this->RecordWarnings();
break;
case 'synchronized': // try to recover synchronized replicas with warnings
case 'modified':
$oDestObj = MetaModel::GetObject($oDataSource->GetTargetClass(), $this->Get('dest_id'));
$oDestObj = MetaModel::GetObject($oDataSource->GetTargetClass(), $this->Get('dest_id'));
if ($oDestObj == null)
{
$this->Set('status', 'orphan'); // The destination object has been deleted !
@@ -1808,8 +1941,20 @@ class SynchroReplica extends DBObject implements iDisplay
}
else
{
$this->UpdateObjectFromReplica($oDestObj, $aAttributes, $oChange, $oStatLog, 'stats_nb_obj', 'stats_nb_obj_updated_errors');
$bModified = $this->UpdateObjectFromReplica($oDestObj, $aAttributes, $oChange, $oStatLog, 'stats_nb_obj', 'stats_nb_obj_updated_errors');
if ($this->HasWarnings())
{
if ($bModified)
{
$oStatLog->Inc('stats_nb_obj_updated_warnings');
}
else
{
$oStatLog->Inc('stats_nb_obj_unchanged_warnings');
}
}
}
$this->RecordWarnings();
break;
default: // Do nothing in all other cases
@@ -1822,6 +1967,7 @@ class SynchroReplica extends DBObject implements iDisplay
protected function UpdateObjectFromReplica($oDestObj, $aAttributes, $oChange, &$oStatLog, $sStatsCode, $sStatsCodeError)
{
$aValueTrace = array();
$bModified = false;
try
{
foreach($aAttributes as $sAttCode => $oSyncAtt)
@@ -1837,6 +1983,7 @@ class SynchroReplica extends DBObject implements iDisplay
if ($oDestObj->IsModified())
{
$oDestObj->DBUpdateTracked($oChange);
$bModified = true;
$oStatLog->AddTrace('Updated object - Values: {'.implode(', ', $aValueTrace).'}', $this);
if (($sStatsCode != '') &&(MetaModel::IsValidAttCode(get_class($oStatLog), $sStatsCode.'_updated')))
{
@@ -1862,6 +2009,7 @@ class SynchroReplica extends DBObject implements iDisplay
$this->SetLastError('Unable to update destination object: ', $e);
$oStatLog->Inc($sStatsCodeError);
}
return $bModified;
}
/**
@@ -1994,6 +2142,7 @@ class SynchroReplica extends DBObject implements iDisplay
// $sExtAttCode is a valid attribute code
//
$sClass = $this->Get('base_class');
$oAttDef = MetaModel::GetAttributeDef($sClass, $sExtAttCode);
if (!is_null($oSyncAtt) && ($oSyncAtt instanceof SynchroAttExtKey))
@@ -2018,6 +2167,7 @@ class SynchroReplica extends DBObject implements iDisplay
{
// Note: differs from null (in which case the value would be left unchanged)
$oStatLog->AddTrace("Could not find [unique] object for '$sExtAttCode': searched on $sReconcAttCode = '$rawValue'", $this);
$this->AddWarning("Could not find [unique] object for '$sExtAttCode': searched on $sReconcAttCode = '$rawValue'");
$retValue = 0;
}
}
@@ -2119,6 +2269,14 @@ class SynchroReplica extends DBObject implements iDisplay
}
$oPage->Details($aDetails);
$oPage->add('</fieldset>');
$oDestObj = MetaModel::GetObject($this->Get('dest_class'), $this->Get('dest_id'), false);
if (is_object($oDestObj))
{
$oPage->add('<fieldset>');
$oPage->add('<legend>'.Dict::Format('Core:SynchroReplica:TargetObject', $oDestObj->GetHyperlink()).'</legend>');
$oDestObj->DisplayBareProperties($oPage, false, $aExtraParams);
$oPage->add('<fieldset>');
}
$oPage->add('</td><td>');
$oPage->add('<fieldset>');
$oPage->add('<legend>'.Dict::S('Core:SynchroReplica:PublicData').'</legend>');