From 721ca8c652ea8553e0b067b8bbbdc95037cace5d Mon Sep 17 00:00:00 2001 From: Denis Flaven Date: Wed, 16 Feb 2011 17:31:32 +0000 Subject: [PATCH] Continuing the implementation of the DataExchange SVN:trunk[1085] --- application/cmdbabstract.class.inc.php | 2 +- images/synchro.png | Bin 0 -> 4174 bytes pages/UI.php | 99 +--------------- synchro/synchrodatasource.class.inc.php | 151 +++++++++++++++++++++++- 4 files changed, 151 insertions(+), 101 deletions(-) create mode 100644 images/synchro.png diff --git a/application/cmdbabstract.class.inc.php b/application/cmdbabstract.class.inc.php index f9ed61f5a..05bf0833b 100644 --- a/application/cmdbabstract.class.inc.php +++ b/application/cmdbabstract.class.inc.php @@ -1693,7 +1693,7 @@ EOF /** * Updates the object from the POSTed parameters */ - function UpdateObject($sFormPrefix = '') + public function UpdateObject($sFormPrefix = '') { foreach(MetaModel::ListAttributeDefs(get_class($this)) as $sAttCode=>$oAttDef) { diff --git a/images/synchro.png b/images/synchro.png new file mode 100644 index 0000000000000000000000000000000000000000..c627cceb93b3d852eca24343b879e19280709af0 GIT binary patch literal 4174 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 - { - if ($oAttDef->IsLinkSet() && $oAttDef->IsIndirect()) - { - $aLinks = utils::ReadPostedParam("attr_$sAttCode", ''); - $sLinkedClass = $oAttDef->GetLinkedClass(); - $sExtKeyToRemote = $oAttDef->GetExtKeyToRemote(); - $sExtKeyToMe = $oAttDef->GetExtKeyToMe(); - $oLinkedSet = DBObjectSet::FromScratch($sLinkedClass); - if (is_array($aLinks)) - { - foreach($aLinks as $id => $aData) - { - if (is_numeric($id)) - { - if ($id < 0) - { - // New link to be created, the opposite of the id (-$id) is the ID of the remote object - $oLink = MetaModel::NewObject($sLinkedClass); - $oLink->Set($sExtKeyToRemote, -$id); - $oLink->Set($sExtKeyToMe, $oObj->GetKey()); - } - else - { - // Existing link, potentially to be updated... - $oLink = MetaModel::GetObject($sLinkedClass, $id); - } - // Now populate the attributes - foreach($aData as $sName => $value) - { - if (MetaModel::IsValidAttCode($sLinkedClass, $sName)) - { - $oLinkAttDef = MetaModel::GetAttributeDef($sLinkedClass, $sName); - if ($oLinkAttDef->IsWritable()) - { - $oLink->Set($sName, $value); - } - } - } - $oLinkedSet->AddObject($oLink); - } - } - } - $oObj->Set($sAttCode, $oLinkedSet); - } - else if ($oAttDef->IsWritable()) - { - $iFlags = $oObj->GetAttributeFlags($sAttCode); - if ($iFlags & (OPT_ATT_HIDDEN | OPT_ATT_READONLY)) - { - // Non-visible, or read-only attribute, do nothing - } - elseif ($oAttDef->GetEditClass() == 'Document') - { - // There should be an uploaded file with the named attr_ - $oDocument = utils::ReadPostedDocument('file_'.$sAttCode); - if (!$oDocument->IsEmpty()) - { - // A new file has been uploaded - $oObj->Set($sAttCode, $oDocument); - } - } - elseif ($oAttDef->GetEditClass() == 'One Way Password') - { - // Check if the password was typed/changed - $bChanged = utils::ReadPostedParam("attr_{$sAttCode}_changed", false); - if ($bChanged) - { - // The password has been changed or set - $rawValue = utils::ReadPostedParam("attr_$sAttCode", null); - $oObj->Set($sAttCode, $rawValue); - } - } - else - { - $rawValue = utils::ReadPostedParam("attr_$sAttCode", null); - if (!is_null($rawValue)) - { - $aAttributes[$sAttCode] = trim($rawValue); - $previousValue = $oObj->Get($sAttCode); - if ($previousValue !== $aAttributes[$sAttCode]) - { - $oObj->Set($sAttCode, $aAttributes[$sAttCode]); - } - } - } - } - } -} - /** * Displays a popup welcome message, once per session at maximum * until the user unchecks the "Display welcome at startup" @@ -901,7 +806,7 @@ try } else { - UpdateObject($oObj); + $oObj->UpdateObject(); if (!$oObj->IsModified()) { @@ -1036,7 +941,7 @@ try else { $oObj = MetaModel::NewObject($sClass); - UpdateObject($oObj); + $oObj->UpdateObject(); } if (isset($oObj) && is_object($oObj)) { diff --git a/synchro/synchrodatasource.class.inc.php b/synchro/synchrodatasource.class.inc.php index a4c23e8aa..e847562a7 100644 --- a/synchro/synchrodatasource.class.inc.php +++ b/synchro/synchrodatasource.class.inc.php @@ -38,6 +38,7 @@ class SynchroDataSource extends cmdbAbstractObject "db_key_field" => "id", "db_finalclass_field" => "realclass", "display_template" => "", + "icon" => "../images/synchro.png", ); MetaModel::Init_Params($aParams); //MetaModel::Init_InheritAttributes(); @@ -68,13 +69,129 @@ class SynchroDataSource extends cmdbAbstractObject MetaModel::Init_AddAttribute(new AttributeLinkedSet("attribute_list", array("linked_class"=>"SynchroAttribute", "ext_key_to_me"=>"sync_source_id", "allowed_values"=>null, "count_min"=>0, "count_max"=>0, "depends_on"=>array()))); // Display lists - MetaModel::Init_SetZListItems('details', array('name', 'description', 'status', 'user_id', 'scope_class', 'scope_restriction', 'full_load_periodicity', 'reconciliation_policy', 'action_on_zero', 'action_on_one', 'action_on_multiple', 'delete_policy', 'delete_policy_update', 'delete_policy_retention', 'attribute_list')); // Attributes to be displayed for the complete details - MetaModel::Init_SetZListItems('list', array('name', 'status', 'scope_class', 'user_id')); // Attributes to be displayed for a list + MetaModel::Init_SetZListItems('details', array('name', 'description', 'scope_class', 'scope_restriction', 'status', 'user_id', 'full_load_periodicity', 'reconciliation_policy', 'action_on_zero', 'action_on_one', 'action_on_multiple', 'delete_policy', 'delete_policy_update', 'delete_policy_retention', /*'attribute_list'*/)); // Attributes to be displayed for the complete details + MetaModel::Init_SetZListItems('list', array('scope_class', 'status', 'user_id', 'full_load_periodicity')); // Attributes to be displayed for a list // Search criteria MetaModel::Init_SetZListItems('standard_search', array('name', 'status', 'scope_class', 'user_id')); // Criteria of the std search form // MetaModel::Init_SetZListItems('advanced_search', array('name')); // Criteria of the advanced search form } + public function DisplayBareRelations(WebPage $oPage, $bEditMode = false) + { + if (!$this->IsNew()) + { + $oPage->SetCurrentTab(Dict::S('Core:SynchroAttributes')); + $oAttributeSet = $this->Get('attribute_list'); + $aAttributes = array(); + while($oAttribute = $oAttributeSet->Fetch()) + { + $aAttributes[$oAttribute->Get('attcode')] = $oAttribute; + } + $aAttribs = array( + 'attcode' => array('label'=>'Attribute', 'description' => 'Field of the object'), + 'reconciliation' => array('label'=>'Reconciliation ?', 'description' => 'Used for searching'), + 'update' => array('label'=>'Update ?', 'description' => 'Used to update the object'), + 'update_policy' => array('label'=>'Update Policy', 'description' => 'Behavior of the updated field'), + ); + $aValues = array(); + foreach(MetaModel::ListAttributeDefs($this->GetTargetClass()) as $sAttCode=>$oAttDef) + { + if ($oAttDef->IsScalar() && $oAttDef->IsWritable()) + { + if (isset($aAttributes[$sAttCode])) + { + $oAttribute = $aAttributes[$sAttCode]; + } + else + { + $oAttribute = new SynchroAttribute(); + $oAttribute->Set('sync_source_id', $this->GetKey()); + $oAttribute->Set('attcode', $sAttCode); + $oAttribute->Set('reconcile', MetaModel::IsReconcKey($this->GetTargetClass(), $sAttCode) ? 1 : 0); + $oAttribute->Set('update', 1); + $oAttribute->Set('update_policy', 'master_locked'); + } + if (!$bEditMode) + { + // Read-only mode + $aRow['reconciliation'] = $oAttribute->Get('reconcile') == 1 ? Dict::S('UI:Synchro:Yes') : Dict::S('UI:Synchro:No'); + $aRow['update'] = $oAttribute->Get('update') == 1 ? Dict::S('UI:Synchro:Yes') : Dict::S('UI:Synchro:No'); + $aRow['attcode'] = MetaModel::GetLabel($this->GetTargetClass(), $oAttribute->Get('attcode')); + $aRow['update_policy'] = $oAttribute->GetAsHTML('update_policy'); + } + else + { + // Read-only mode + $sAttCode = $oAttribute->Get('attcode'); + $sChecked = $oAttribute->Get('reconcile') == 1 ? 'checked' : ''; + $aRow['reconciliation'] = ""; + $sChecked = $oAttribute->Get('update') == 1 ? 'checked' : ''; + $aRow['update'] = ""; + $aRow['attcode'] = MetaModel::GetLabel($this->GetTargetClass(), $oAttribute->Get('attcode')); + $oAttDef = MetaModel::GetAttributeDef(get_class($oAttribute), 'update_policy'); + $aRow['update_policy'] = cmdbAbstractObject::GetFormElementForField($oPage, get_class($oAttribute), 'update_policy', $oAttDef, $oAttribute->Get('update_policy'), '', 'update_policy_'.$sAttCode, "[$sAttCode]"); + } + $aValues[] = $aRow; + } + } + $oPage->Table($aAttribs, $aValues); + } + parent::DisplayBareRelations($oPage, $bEditMode); + } + + public function GetAttributeFlags($sAttCode) + { + if (($sAttCode == 'scope_class') && (!$this->IsNew())) + { + return OPT_ATT_READONLY; + } + return parent::GetAttributeFlags($sAttCode); + } + + public function UpdateObject($sFormPrefix = '') + { + parent::UpdateObject($sFormPrefix); + // And now read the other post parameters... + $oAttributeSet = $this->Get('attribute_list'); + $aAttributes = array(); + while($oAttribute = $oAttributeSet->Fetch()) + { + $aAttributes[$oAttribute->Get('attcode')] = $oAttribute; + } + $aReconcile = utils::ReadPostedParam('reconciliation', array()); + $aUpdate = utils::ReadPostedParam('update', array()); + $aUpdatePolicy = utils::ReadPostedParam('attr_update_policy', array()); + // update_policy cannot be empty, so there is one entry per attribute, use this to iterate + // through all the writable attributes + foreach($aUpdatePolicy as $sAttCode => $sValue) + { + if(!isset($aAttributes[$sAttCode])) + { + $oAttribute = new SynchroAttribute(); + $oAttribute->Set('sync_source_id', $this->GetKey()); + $oAttribute->Set('attcode', $sAttCode); + } + else + { + $oAttribute = $aAttributes[$sAttCode]; + } + $bReconcile = 0; + if (isset($aReconcile[$sAttCode])) + { + $bReconcile = $aReconcile[$sAttCode] == 'on' ? 1 : 0; + } + $bUpdate = 0 ; // Default / initial value + if (isset($aUpdate[$sAttCode])) + { + $bUpdate = $aUpdate[$sAttCode] == 'on' ? 1 : 0; + } + $oAttribute->Set('reconcile', $bReconcile); + $oAttribute->Set('update', $bUpdate); + $oAttribute->Set('update_policy', $sValue); + $oAttributeSet->AddObject($oAttribute); + } + $this->Set('attribute_list', $oAttributeSet); + } public function GetTargetClass() { return $this->Get('scope_class'); @@ -89,6 +206,34 @@ class SynchroDataSource extends cmdbAbstractObject return $sTable; } + /** + * When inserting a new datasource object, also create the SynchroAttribute objects + * for each field of the target class + */ + protected function OnInsert() + { + // Create all the SynchroAttribute records + $oAttributeSet = $this->Get('attribute_list'); + foreach(MetaModel::ListAttributeDefs($this->GetTargetClass()) as $sAttCode=>$oAttDef) + { + if ($oAttDef->IsScalar() && $oAttDef->IsWritable()) + { + $oAttribute = new SynchroAttribute(); + $oAttribute->Set('sync_source_id', $this->GetKey()); + $oAttribute->Set('attcode', $sAttCode); + $oAttribute->Set('reconcile', MetaModel::IsReconcKey($this->GetTargetClass(), $sAttCode) ? 1 : 0); + $oAttribute->Set('update', 1); + $oAttribute->Set('update_policy', 'master_locked'); + $oAttributeSet->AddObject($oAttribute); + } + } + $this->Set('attribute_list', $oAttributeSet); + } + /** + * When the new datasource has been created, let's create the synchro_data table + * that will hold the data records and the correspoding triggers which will maintain + * both tables in sync + */ protected function AfterInsert() { parent::AfterInsert(); @@ -154,7 +299,7 @@ class SynchroDataSource extends cmdbAbstractObject protected function AfterDelete() { - parent::AfterInsert(); + parent::AfterDelete(); $sTable = $this->GetDataTable();