Skip to content
115 changes: 63 additions & 52 deletions core/collector.class.inc.php
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,15 @@ abstract class Collector
* @var string TABLENAME_PATTERN used to validate data synchro table name
*/
const TABLENAME_PATTERN = '/^[A-Za-z0-9_]*$/';
const READONLY_FIELDS = [
Comment thread
odain-cbd marked this conversation as resolved.
'friendlyname',
'user_id_friendlyname',
'user_id_finalclass_recall',
'notify_contact_id_friendlyname',
'notify_contact_id_finalclass_recall',
'notify_contact_id_obsolescence_flag',
'notify_contact_id_archive_flag',
];

protected $sProjectName;
protected $sSynchroDataSourceDefinitionFile;
Expand Down Expand Up @@ -251,6 +260,17 @@ public function GetName()
return get_class($this);
}

public function GetSourceId()
{
return $this->iSourceId;
}

protected function SetSourceId($iSourceId)
{
$this->iSourceId = $iSourceId;
}


public function GetVersion()
{
if ($this->sVersion == null) {
Expand Down Expand Up @@ -508,7 +528,7 @@ public function InitSynchroDataSource($aPlaceholders)
} else {
$iKey = (int)$aData['key'];
}
$this->iSourceId = $iKey;
$this->SetSourceId($iKey);
RestClient::GetFullSynchroDataSource($aCurrentSourceDefinition, $this->iSourceId);
if ($this->DataSourcesAreEquivalent($aExpectedSourceDefinition, $aCurrentSourceDefinition)) {
Utils::Log(LOG_INFO, "Ok, the Synchro Data Source '{$this->sSourceName}' exists in iTop and is up to date");
Expand Down Expand Up @@ -818,18 +838,22 @@ public static function CallItopViaHttp($sUri, $aAdditionalData, $iTimeOut = -1)
return static::$oCallItopService->CallItopViaHttp($sUri, $aAdditionalData, $iTimeOut);
}

protected function CreateSynchroDataSource($aSourceDefinition, $sComment)
protected function CreateSynchroDataSource($aSourceDefinition, $sComment, RestClient $oClient = null)
{
$oClient = new RestClient();
if ($oClient === null)
{
$oClient = new RestClient();
}

$ret = false;

// Ignore read-only fields
unset($aSourceDefinition['friendlyname']);
unset($aSourceDefinition['user_id_friendlyname']);
unset($aSourceDefinition['user_id_finalclass_recall']);
unset($aSourceDefinition['notify_contact_id_friendlyname']);
unset($aSourceDefinition['notify_contact_id_finalclass_recall']);
unset($aSourceDefinition['notify_contact_id_obsolescence_flag']);
foreach (self::READONLY_FIELDS as $sField){
Comment thread
odain-cbd marked this conversation as resolved.
Outdated
if (array_key_exists($sField, $aSourceDefinition)){
unset($aSourceDefinition[$sField]);
}
}

// SynchroAttributes will be processed one by one, below
$aSynchroAttr = $aSourceDefinition['attribute_list'];
unset($aSourceDefinition['attribute_list']);
Expand All @@ -839,7 +863,7 @@ protected function CreateSynchroDataSource($aSourceDefinition, $sComment)
$aCreatedObj = reset($aResult['objects']);
$aExpectedAttrDef = $aCreatedObj['fields']['attribute_list'];
$iKey = (int)$aCreatedObj['key'];
$this->iSourceId = $iKey;
$this->SetSourceId($iKey);

if ($this->UpdateSDSAttributes($aExpectedAttrDef, $aSynchroAttr, $sComment)) {
$ret = $this->iSourceId;
Expand All @@ -851,18 +875,19 @@ protected function CreateSynchroDataSource($aSourceDefinition, $sComment)
return $ret;
}

protected function UpdateSynchroDataSource($aSourceDefinition, $sComment)
protected function UpdateSynchroDataSource($aSourceDefinition, $sComment, RestClient $oClient = null)
{
$bRet = true;
$oClient = new RestClient();

if ($oClient === null)
{
$oClient = new RestClient();
}
// Ignore read-only fields
unset($aSourceDefinition['friendlyname']);
unset($aSourceDefinition['user_id_friendlyname']);
unset($aSourceDefinition['user_id_finalclass_recall']);
unset($aSourceDefinition['notify_contact_id_friendlyname']);
unset($aSourceDefinition['notify_contact_id_finalclass_recall']);
unset($aSourceDefinition['notify_contact_id_obsolescence_flag']);
foreach (Collector::READONLY_FIELDS as $sField){
Comment thread
odain-cbd marked this conversation as resolved.
Outdated
if (array_key_exists($sField, $aSourceDefinition)){
unset($aSourceDefinition[$sField]);
}
}

// SynchroAttributes will be processed one by one, below
$aSynchroAttr = $aSourceDefinition['attribute_list'];
unset($aSourceDefinition['attribute_list']);
Expand Down Expand Up @@ -952,19 +977,14 @@ protected function FindAttr($sAttCode, $aExpectedAttrDef)
protected function DataSourcesAreEquivalent($aDS1, $aDS2)
{
foreach ($aDS1 as $sKey => $value) {
switch ($sKey) {
case 'friendlyname':
case 'user_id_friendlyname':
case 'user_id_finalclass_recall':
case 'notify_contact_id_friendlyname':
case 'notify_contact_id_finalclass_recall':
case 'notify_contact_id_obsolescence_flag':
case 'notify_contact_id_archive_flag':
// Ignore all read-only attributes
break;
if (in_array($sKey, Collector::READONLY_FIELDS)){
Comment thread
odain-cbd marked this conversation as resolved.
Outdated
// Ignore all read-only attributes
continue;
}

switch ($sKey) {
case 'attribute_list':
foreach ($value as $sKey => $aDef) {
foreach ($value as $sKey2 => $aDef) {
Comment thread
odain-cbd marked this conversation as resolved.
Outdated
$sAttCode = $aDef['attcode'];
$aDef2 = $this->FindAttr($sAttCode, $aDS2['attribute_list']);
if ($aDef2 === false) {
Expand All @@ -973,13 +993,13 @@ protected function DataSourcesAreEquivalent($aDS1, $aDS2)
Utils::Log(LOG_DEBUG, "Comparison: ignoring the missing, but optional, attribute: '$sAttCode'.");
$this->aSkippedAttributes[] = $sAttCode;
continue;
} else {
// Missing non-optional attribute
Utils::Log(LOG_DEBUG, "Comparison: The definition of the non-optional attribute '$sAttCode' is missing. Data sources differ.");

return false;
}

// Missing non-optional attribute
Utils::Log(LOG_DEBUG, "Comparison: The definition of the non-optional attribute '$sAttCode' is missing. Data sources differ.");

return false;

} else {
if (($aDef != $aDef2) && (!$this->AttributeIsOptional($sAttCode))) {
// Definitions are different
Expand Down Expand Up @@ -1012,23 +1032,14 @@ protected function DataSourcesAreEquivalent($aDS1, $aDS2)
}
//Check the other way around
foreach ($aDS2 as $sKey => $value) {
switch ($sKey) {
case 'friendlyname':
case 'user_id_friendlyname':
case 'user_id_finalclass_recall':
case 'notify_contact_id_friendlyname':
case 'notify_contact_id_finalclass_recall':
case 'notify_contact_id_obsolescence_flag':
case 'notify_contact_id_archive_flag':
// Ignore all read-only attributes
break;

default:
if (!array_key_exists($sKey, $aDS1)) {
Utils::Log(LOG_DEBUG, "Comparison: Found an extra property '$sKey' in iTop. Data sources differ.");
if (in_array($sKey, Collector::READONLY_FIELDS)){
Comment thread
odain-cbd marked this conversation as resolved.
Outdated
// Ignore all read-only attributes
continue;
}

return false;
}
if (! array_key_exists($sKey, $aDS1)) {
//locally unknown fields can NOT be updated. so it is useless to update datasynchro on itop
Utils::Log(LOG_DEBUG, "Comparison: Found an extra property '$sKey' in iTop. Data sources differ.");
}
}

Expand Down
23 changes: 13 additions & 10 deletions core/restclient.class.inc.php
Original file line number Diff line number Diff line change
Expand Up @@ -153,20 +153,24 @@ public static function GetNewestKnownVersion()
*
* @param hash $aSource The definition of 'fields' the Synchro DataSource, as retrieved by Get
* @param integer $iSourceId The identifier (key) of the Synchro Data Source
* @param RestClient|null $oClient : used for tests only
*/
public static function GetFullSynchroDataSource(&$aSource, $iSourceId)
public static function GetFullSynchroDataSource(&$aSource, $iSourceId, RestClient $oRestClient = null)
{
$bResult = true;
$aAttributes = array();
$aAttributes = [];
// Optimize the calls to the REST API: one call per finalclass
foreach ($aSource['attribute_list'] as $aAttr) {
if (!array_key_exists($aAttr['finalclass'], $aAttributes)) {
$aAttributes[$aAttr['finalclass']] = array();
$aAttributes[$aAttr['finalclass']] = [];
}
$aAttributes[$aAttr['finalclass']][] = $aAttr['attcode'];
}

$oRestClient = new RestClient();
if ($oRestClient === null)
{
$oRestClient = new RestClient();
}
foreach ($aAttributes as $sFinalClass => $aAttCodes) {
Utils::Log(LOG_DEBUG, "RestClient::Get SELECT $sFinalClass WHERE attcode IN ('".implode("','", $aAttCodes)."') AND sync_source_id = $iSourceId");
$aResult = $oRestClient->Get($sFinalClass, "SELECT $sFinalClass WHERE attcode IN ('".implode("','", $aAttCodes)."') AND sync_source_id = $iSourceId");
Expand Down Expand Up @@ -196,12 +200,11 @@ public static function GetFullSynchroDataSource(&$aSource, $iSourceId)
}

// Don't care about these read-only fields
unset($aSource['friendlyname']);
unset($aSource['user_id_friendlyname']);
unset($aSource['user_id_finalclass_recall']);
unset($aSource['notify_contact_id_friendlyname']);
unset($aSource['notify_contact_id_finalclass_recall']);
unset($aSource['notify_contact_id_obsolescence_flag']);
foreach (Collector::READONLY_FIELDS as $sField){
if (array_key_exists($sField, $aSource)){
unset($aSource[$sField]);
}
}

return $bResult;
}
Expand Down
Loading