diff --git a/core/bulkchange.class.inc.php b/core/bulkchange.class.inc.php index 8b568b8e7..4c8ec0081 100644 --- a/core/bulkchange.class.inc.php +++ b/core/bulkchange.class.inc.php @@ -368,6 +368,7 @@ class BulkChange { // Check for additional rules $oReconFilter = $oExtKey->GetAllowedValuesAsFilter(array('this' => $oTargetObj)); + //$oReconFilter = new DBObjectSearch($oExtKey->GetTargetClass()); $aCacheKeys = array(); foreach ($aKeyConfig as $sForeignAttCode => $iCol) @@ -413,12 +414,13 @@ class BulkChange $oForeignObj = $oExtObjects->Fetch(); $iForeignKey = $oForeignObj->GetKey(); } - $this->m_aExtKeysMappingCache[$sAttCode][$sCacheKey] = array( - 'c' => $iCount, - 'k' => $iForeignKey, - 'oql' => $oReconFilter->ToOql(), - 'h' => 0, // number of hits on this cache entry - ); + // Cannot cache the entry in this case as the conditions can change... + //$this->m_aExtKeysMappingCache[$sAttCode][$sCacheKey] = array( + // 'c' => $iCount, + // 'k' => $iForeignKey, + // 'oql' => $oReconFilter->ToOql(), + // 'h' => 0, // number of hits on this cache entry + //); } switch($iCount) { @@ -648,6 +650,43 @@ class BulkChange protected function CreateObject(&$aResult, $iRow, $aRowData, CMDBChange $oChange = null) { $oTargetObj = MetaModel::NewObject($this->m_sClass); + + + // Populate the cache for hierarchical keys (only if in verify mode) + if (is_null($oChange)) + { + // 1. determine if a hierarchical key exists + foreach($this->m_aExtKeys as $sAttCode => $aKeyConfig) + { + $oExtKey = MetaModel::GetAttributeDef(get_class($oTargetObj), $sAttCode); + if (!$this->IsNullExternalKeySpec($aRowData, $sAttCode) && $oExtKey->IsHierarchicalKey()) + { + // 2. Populate the cache for further checks + $aCacheKeys = array(); + foreach ($aKeyConfig as $sForeignAttCode => $iCol) + { + // The foreign attribute is one of our reconciliation key + if ($sForeignAttCode == 'id') + { + $value = $aRowData[$iCol]; + } + else + { + $value = $aRowData[$this->m_aAttList[$sForeignAttCode]]; + } + $aCacheKeys[] = $value; + } + $sCacheKey = implode('_|_', $aCacheKeys); // Unique key for this query... + $this->m_aExtKeysMappingCache[$sAttCode][$sCacheKey] = array( + 'c' => 1, + 'k' => -1, + 'oql' => '', + 'h' => 0, // number of hits on this cache entry + ); + } + } + } + $aResult[$iRow] = $this->PrepareObject($oTargetObj, $aRowData, $aErrors); if (count($aErrors) > 0) diff --git a/core/dbobject.class.php b/core/dbobject.class.php index 466a74cd1..c1c060ead 100644 --- a/core/dbobject.class.php +++ b/core/dbobject.class.php @@ -1199,24 +1199,16 @@ abstract class DBObject implements iDisplay } elseif ($oAtt->IsExternalKey()) { - if (!MetaModel::SkipCheckExtKeys()) + // Hierachical keys are always tested because an infinite loop can be created. + if (!MetaModel::SkipCheckExtKeys() || $oAtt->IsHierarchicalKey()) { - $sTargetClass = $oAtt->GetTargetClass(); - $oTargetObj = MetaModel::GetObject($sTargetClass, $toCheck, false /*must be found*/, true /*allow all data*/); - if (is_null($oTargetObj)) - { - return "Target object not found ($sTargetClass::$toCheck)"; - } // Check allowed values $aValues = $oAtt->GetAllowedValues($this->ToArgsForQuery()); - if (count($aValues) > 0) + if (!array_key_exists($toCheck, $aValues)) { - if (!array_key_exists($toCheck, $aValues)) - { - return "Value not allowed [$toCheck]"; - } + return "Value not allowed [$toCheck]"; } - } + } } elseif ($oAtt->IsScalar()) {