/**
  * Helper to link objects
  *
  * @param string sLinkAttCode
  * @param string sLinkedClass
  * @param array $aLinkList
  * @param DBObject oTargetObj
  * @param WebServiceResult oRes
  *
  * @return array List of objects that could not be found
  */
 protected function AddLinkedObjects($sLinkAttCode, $sParamName, $sLinkedClass, $aLinkList, &$oTargetObj, &$oRes)
 {
     $oLinkAtt = MetaModel::GetAttributeDef(get_class($oTargetObj), $sLinkAttCode);
     $sLinkClass = $oLinkAtt->GetLinkedClass();
     $sExtKeyToItem = $oLinkAtt->GetExtKeyToRemote();
     $aItemsFound = array();
     $aItemsNotFound = array();
     if (is_null($aLinkList)) {
         return $aItemsNotFound;
     }
     foreach ($aLinkList as $aItemData) {
         if (!array_key_exists('class', $aItemData)) {
             $oRes->LogWarning("Parameter {$sParamName}: missing 'class' specification");
             continue;
             // skip
         }
         $sTargetClass = $aItemData['class'];
         if (!MetaModel::IsValidClass($sTargetClass)) {
             $oRes->LogError("Parameter {$sParamName}: invalid class '{$sTargetClass}'");
             continue;
             // skip
         }
         if (!MetaModel::IsParentClass($sLinkedClass, $sTargetClass)) {
             $oRes->LogError("Parameter {$sParamName}: '{$sTargetClass}' is not a child class of '{$sLinkedClass}'");
             continue;
             // skip
         }
         $oReconFilter = new CMDBSearchFilter($sTargetClass);
         $aCIStringDesc = array();
         foreach ($aItemData['search'] as $sAttCode => $value) {
             if (!MetaModel::IsValidFilterCode($sTargetClass, $sAttCode)) {
                 $aCodes = array_keys(MetaModel::GetClassFilterDefs($sTargetClass));
                 $oRes->LogError("Parameter {$sParamName}: '{$sAttCode}' is not a valid filter code for class '{$sTargetClass}', expecting a value in {" . implode(', ', $aCodes) . "}");
                 continue 2;
                 // skip the entire item
             }
             $aCIStringDesc[] = "{$sAttCode}: {$value}";
             // The attribute is one of our reconciliation key
             $oReconFilter->AddCondition($sAttCode, $value, '=');
         }
         if (count($aCIStringDesc) == 1) {
             // take the last and unique value to describe the object
             $sItemDesc = $value;
         } else {
             // describe the object by the given keys
             $sItemDesc = $sTargetClass . '(' . implode('/', $aCIStringDesc) . ')';
         }
         $oExtObjects = new CMDBObjectSet($oReconFilter);
         switch ($oExtObjects->Count()) {
             case 0:
                 $oRes->LogWarning("Parameter {$sParamName}: object to link {$sLinkedClass} / {$sItemDesc} could not be found (searched: '" . $oReconFilter->ToOQL(true) . "')");
                 $aItemsNotFound[] = $sItemDesc;
                 break;
             case 1:
                 $aItemsFound[] = array('object' => $oExtObjects->Fetch(), 'link_values' => @$aItemData['link_values'], 'desc' => $sItemDesc);
                 break;
             default:
                 $oRes->LogWarning("Parameter {$sParamName}: Found " . $oExtObjects->Count() . " matches for item '{$sItemDesc}' (searched: '" . $oReconFilter->ToOQL(true) . "')");
                 $aItemsNotFound[] = $sItemDesc;
         }
     }
     if (count($aItemsFound) > 0) {
         $aLinks = array();
         foreach ($aItemsFound as $aItemData) {
             $oLink = MetaModel::NewObject($sLinkClass);
             $oLink->Set($sExtKeyToItem, $aItemData['object']->GetKey());
             foreach ($aItemData['link_values'] as $sKey => $value) {
                 if (!MetaModel::IsValidAttCode($sLinkClass, $sKey)) {
                     $oRes->LogWarning("Parameter {$sParamName}: Attaching item '" . $aItemData['desc'] . "', the attribute code '{$sKey}' is not valid ; check the class '{$sLinkClass}'");
                 } else {
                     $oLink->Set($sKey, $value);
                 }
             }
             $aLinks[] = $oLink;
         }
         $oImpactedInfraSet = DBObjectSet::FromArray($sLinkClass, $aLinks);
         $oTargetObj->Set($sLinkAttCode, $oImpactedInfraSet);
     }
     return $aItemsNotFound;
 }
 public function MakeValueFromString($sProposedValue, $bLocalizedValue = false, $sSepItem = null, $sSepAttribute = null, $sSepValue = null, $sAttributeQualifier = null)
 {
     if (is_null($sSepItem) || empty($sSepItem)) {
         $sSepItem = MetaModel::GetConfig()->Get('link_set_item_separator');
     }
     if (is_null($sSepAttribute) || empty($sSepAttribute)) {
         $sSepAttribute = MetaModel::GetConfig()->Get('link_set_attribute_separator');
     }
     if (is_null($sSepValue) || empty($sSepValue)) {
         $sSepValue = MetaModel::GetConfig()->Get('link_set_value_separator');
     }
     if (is_null($sAttributeQualifier) || empty($sAttributeQualifier)) {
         $sAttributeQualifier = MetaModel::GetConfig()->Get('link_set_attribute_qualifier');
     }
     $sTargetClass = $this->Get('linked_class');
     $sInput = str_replace($sSepItem, "\n", $sProposedValue);
     $oCSVParser = new CSVParser($sInput, $sSepAttribute, $sAttributeQualifier);
     $aInput = $oCSVParser->ToArray(0);
     $aLinks = array();
     foreach ($aInput as $aRow) {
         // 1st - get the values, split the extkey->searchkey specs, and eventually get the finalclass value
         $aExtKeys = array();
         $aValues = array();
         foreach ($aRow as $sCell) {
             $iSepPos = strpos($sCell, $sSepValue);
             if ($iSepPos === false) {
                 // Houston...
                 throw new CoreException('Wrong format for link attribute specification', array('value' => $sCell));
             }
             $sAttCode = trim(substr($sCell, 0, $iSepPos));
             $sValue = substr($sCell, $iSepPos + strlen($sSepValue));
             if (preg_match('/^(.+)->(.+)$/', $sAttCode, $aMatches)) {
                 $sKeyAttCode = $aMatches[1];
                 $sRemoteAttCode = $aMatches[2];
                 $aExtKeys[$sKeyAttCode][$sRemoteAttCode] = $sValue;
                 if (!MetaModel::IsValidAttCode($sTargetClass, $sKeyAttCode)) {
                     throw new CoreException('Wrong attribute code for link attribute specification', array('class' => $sTargetClass, 'attcode' => $sKeyAttCode));
                 }
                 $oKeyAttDef = MetaModel::GetAttributeDef($sTargetClass, $sKeyAttCode);
                 $sRemoteClass = $oKeyAttDef->GetTargetClass();
                 if (!MetaModel::IsValidAttCode($sRemoteClass, $sRemoteAttCode)) {
                     throw new CoreException('Wrong attribute code for link attribute specification', array('class' => $sRemoteClass, 'attcode' => $sRemoteAttCode));
                 }
             } else {
                 if (!MetaModel::IsValidAttCode($sTargetClass, $sAttCode)) {
                     throw new CoreException('Wrong attribute code for link attribute specification', array('class' => $sTargetClass, 'attcode' => $sAttCode));
                 }
                 $aValues[$sAttCode] = $sValue;
             }
         }
         // 2nd - Instanciate the object and set the value
         if (isset($aValues['finalclass'])) {
             $sLinkClass = $aValues['finalclass'];
             if (!is_subclass_of($sLinkClass, $sTargetClass)) {
                 throw new CoreException('Wrong class for link attribute specification', array('requested_class' => $sLinkClass, 'expected_class' => $sTargetClass));
             }
         } elseif (MetaModel::IsAbstract($sTargetClass)) {
             throw new CoreException('Missing finalclass for link attribute specification');
         } else {
             $sLinkClass = $sTargetClass;
         }
         $oLink = MetaModel::NewObject($sLinkClass);
         foreach ($aValues as $sAttCode => $sValue) {
             $oLink->Set($sAttCode, $sValue);
         }
         // 3rd - Set external keys from search conditions
         foreach ($aExtKeys as $sKeyAttCode => $aReconciliation) {
             $oKeyAttDef = MetaModel::GetAttributeDef($sTargetClass, $sKeyAttCode);
             $sKeyClass = $oKeyAttDef->GetTargetClass();
             $oExtKeyFilter = new CMDBSearchFilter($sKeyClass);
             $aReconciliationDesc = array();
             foreach ($aReconciliation as $sRemoteAttCode => $sValue) {
                 $oExtKeyFilter->AddCondition($sRemoteAttCode, $sValue, '=');
                 $aReconciliationDesc[] = "{$sRemoteAttCode}={$sValue}";
             }
             $oExtKeySet = new CMDBObjectSet($oExtKeyFilter);
             switch ($oExtKeySet->Count()) {
                 case 0:
                     $sReconciliationDesc = implode(', ', $aReconciliationDesc);
                     throw new CoreException("Found no match", array('ext_key' => $sKeyAttCode, 'reconciliation' => $sReconciliationDesc));
                     break;
                 case 1:
                     $oRemoteObj = $oExtKeySet->Fetch();
                     $oLink->Set($sKeyAttCode, $oRemoteObj->GetKey());
                     break;
                 default:
                     $sReconciliationDesc = implode(', ', $aReconciliationDesc);
                     throw new CoreException("Found several matches", array('ext_key' => $sKeyAttCode, 'reconciliation' => $sReconciliationDesc));
                     // Found several matches, ambiguous
             }
         }
         // Check (roughly) if such a link is valid
         $aErrors = array();
         foreach (MetaModel::ListAttributeDefs($sTargetClass) as $sAttCode => $oAttDef) {
             if ($oAttDef->IsExternalKey()) {
                 if ($oAttDef->GetTargetClass() == $this->GetHostClass() || is_subclass_of($this->GetHostClass(), $oAttDef->GetTargetClass())) {
                     continue;
                     // Don't check the key to self
                 }
             }
             if ($oAttDef->IsWritable() && $oAttDef->IsNull($oLink->Get($sAttCode)) && !$oAttDef->IsNullAllowed()) {
                 $aErrors[] = $sAttCode;
             }
         }
         if (count($aErrors) > 0) {
             throw new CoreException("Missing value for mandatory attribute(s): " . implode(', ', $aErrors));
         }
         $aLinks[] = $oLink;
     }
     $oSet = DBObjectSet::FromArray($sTargetClass, $aLinks);
     return $oSet;
 }
예제 #3
0
     $oPage->add('</textarea>');
     $oPage->add("</div>");
     $oPage->add("</div>");
     break;
 case 'history':
     $oPage->SetContentType('text/html');
     $id = (int) utils::ReadParam('id', 0);
     $iStart = (int) utils::ReadParam('start', 0);
     $iCount = (int) utils::ReadParam('count', MetaModel::GetConfig()->Get('max_history_length', '50'));
     $oObj = MetaModel::GetObject($sClass, $id);
     $oObj->DisplayBareHistory($oPage, false, $iCount, $iStart);
     $oPage->add_ready_script("\$('#history table.listResults').tableHover(); \$('#history table.listResults').tablesorter( { widgets: ['myZebra', 'truncatedList']} );");
     break;
 case 'history_from_filter':
     $oPage->SetContentType('text/html');
     $oHistoryFilter = CMDBSearchFilter::unserialize($sFilter);
     $iStart = (int) utils::ReadParam('start', 0);
     $iCount = (int) utils::ReadParam('count', MetaModel::GetConfig()->Get('max_history_length', '50'));
     $oBlock = new HistoryBlock($oHistoryFilter, 'table', false);
     $oBlock->SetLimit($iCount, $iStart);
     $oBlock->Display($oPage, 'history');
     $oPage->add_ready_script("\$('#history table.listResults').tableHover(); \$('#history table.listResults').tablesorter( { widgets: ['myZebra', 'truncatedList']} );");
     break;
 case 'full_text_search':
     $aFullTextNeedles = utils::ReadParam('needles', array(), false, 'raw_data');
     $sFullText = trim(implode(' ', $aFullTextNeedles));
     $sClassName = utils::ReadParam('class', '');
     $iCount = utils::ReadParam('count', 0);
     $iCurrentPos = utils::ReadParam('position', 0);
     $iTune = utils::ReadParam('tune', 0);
     if (empty($sFullText)) {
예제 #4
0
             ReloadAndDisplay($oP, $oObj, 'update', $sMessage, $sSeverity);
         }
     }
     break;
     ///////////////////////////////////////////////////////////////////////////////////////////
 ///////////////////////////////////////////////////////////////////////////////////////////
 case 'select_for_deletion':
     // Select multiple objects for deletion
     $sFilter = utils::ReadParam('filter', '', false, 'raw_data');
     if (empty($sFilter)) {
         throw new ApplicationException(Dict::Format('UI:Error:1ParametersMissing', 'filter'));
     }
     $oP->set_title(Dict::S('UI:BulkDeletePageTitle'));
     $oP->add("<h1>" . Dict::S('UI:BulkDeleteTitle') . "</h1>\n");
     // TO DO: limit the search filter by the user context
     $oFilter = CMDBSearchFilter::unserialize($sFilter);
     // TO DO : check that the filter is valid
     $oChecker = new ActionChecker($oFilter, UR_ACTION_BULK_DELETE);
     DisplayMultipleSelectionForm($oP, $oFilter, 'bulk_delete', $oChecker);
     break;
     ///////////////////////////////////////////////////////////////////////////////////////////
 ///////////////////////////////////////////////////////////////////////////////////////////
 case 'bulk_delete_confirmed':
     // Confirm bulk deletion of objects
     $sTransactionId = utils::ReadPostedParam('transaction_id', '');
     if (!utils::IsTransactionValid($sTransactionId)) {
         throw new ApplicationException(Dict::S('UI:Error:ObjectsAlreadyDeleted'));
     }
     // Fall through
     ///////////////////////////////////////////////////////////////////////////////////////////
 // Fall through
 /**
  * Constructs a DisplayBlock object from an XML template
  * @param $sTemplate string The XML template
  * @return DisplayBlock The DisplayBlock object, or null if the template is invalid
  */
 public static function FromTemplate($sTemplate)
 {
     $iStartPos = stripos($sTemplate, '<' . self::TAG_BLOCK . ' ', 0);
     $iEndPos = stripos($sTemplate, '</' . self::TAG_BLOCK . '>', $iStartPos);
     $iEndTag = stripos($sTemplate, '>', $iStartPos);
     $aParams = array();
     if ($iStartPos === false || $iEndPos === false) {
         return null;
     }
     // invalid template
     $sITopBlock = substr($sTemplate, $iStartPos, $iEndPos - $iStartPos + strlen('</' . self::TAG_BLOCK . '>'));
     $sITopData = substr($sTemplate, 1 + $iEndTag, $iEndPos - $iEndTag - 1);
     $sITopTag = substr($sTemplate, $iStartPos + strlen('<' . self::TAG_BLOCK), $iEndTag - $iStartPos - strlen('<' . self::TAG_BLOCK));
     $aMatches = array();
     $sBlockClass = "DisplayBlock";
     $bAsynchronous = false;
     $sBlockType = 'list';
     $sEncoding = 'text/serialize';
     if (preg_match('/ type="(.*)"/U', $sITopTag, $aMatches)) {
         $sBlockType = strtolower($aMatches[1]);
     }
     if (preg_match('/ asynchronous="(.*)"/U', $sITopTag, $aMatches)) {
         $bAsynchronous = strtolower($aMatches[1]) == 'true';
     }
     if (preg_match('/ blockclass="(.*)"/U', $sITopTag, $aMatches)) {
         $sBlockClass = $aMatches[1];
     }
     if (preg_match('/ objectclass="(.*)"/U', $sITopTag, $aMatches)) {
         $sObjectClass = $aMatches[1];
     }
     if (preg_match('/ encoding="(.*)"/U', $sITopTag, $aMatches)) {
         $sEncoding = strtolower($aMatches[1]);
     }
     if (preg_match('/ link_attr="(.*)"/U', $sITopTag, $aMatches)) {
         // The list to display is a list of links to the specified object
         $aParams['link_attr'] = $aMatches[1];
         // Name of the Ext. Key that makes this linkage
     }
     if (preg_match('/ target_attr="(.*)"/U', $sITopTag, $aMatches)) {
         // The list to display is a list of links to the specified object
         $aParams['target_attr'] = $aMatches[1];
         // Name of the Ext. Key that make this linkage
     }
     if (preg_match('/ object_id="(.*)"/U', $sITopTag, $aMatches)) {
         // The list to display is a list of links to the specified object
         $aParams['object_id'] = $aMatches[1];
         // Id of the object to be linked to
     }
     // Parameters contains a list of extra parameters for the block
     // the syntax is param_name1:value1;param_name2:value2;...
     if (preg_match('/ parameters="(.*)"/U', $sITopTag, $aMatches)) {
         $sParameters = $aMatches[1];
         $aPairs = explode(';', $sParameters);
         foreach ($aPairs as $sPair) {
             if (preg_match('/(.*)\\:(.*)/', $sPair, $aMatches)) {
                 $aParams[trim($aMatches[1])] = trim($aMatches[2]);
             }
         }
     }
     if (!empty($aParams['link_attr'])) {
         // Check that all mandatory parameters are present:
         if (empty($aParams['object_id'])) {
             // if 'links' mode is requested the d of the object to link to must be specified
             throw new ApplicationException(Dict::S('UI:Error:MandatoryTemplateParameter_object_id'));
         }
         if (empty($aParams['target_attr'])) {
             // if 'links' mode is requested the id of the object to link to must be specified
             throw new ApplicationException(Dict::S('UI:Error:MandatoryTemplateParameter_target_attr'));
         }
     }
     switch ($sEncoding) {
         case 'text/serialize':
             $oFilter = CMDBSearchFilter::unserialize($sITopData);
             break;
         case 'text/oql':
             $oFilter = CMDBSearchFilter::FromOQL($sITopData);
             break;
     }
     return new $sBlockClass($oFilter, $sBlockType, $bAsynchronous, $aParams);
 }
예제 #6
0
 $oP->add("<th><img src=\"../images/minus.gif\"></th><th class=\"alignLeft\">" . Dict::S('UI:Audit:HeaderAuditRule') . "</th><th>" . Dict::S('UI:Audit:HeaderNbObjects') . "</th><th>" . Dict::S('UI:Audit:HeaderNbErrors') . "</th><th>" . Dict::S('UI:Audit:PercentageOk') . "</th>\n");
 $oP->add("</tr>\n");
 while ($oAuditCategory = $oCategoriesSet->fetch()) {
     try {
         $oDefinitionFilter = DBObjectSearch::FromOQL($oAuditCategory->Get('definition_set'));
         FilterByContext($oDefinitionFilter, $oAppContext);
         $aObjectsWithErrors = array();
         if (!empty($currentOrganization)) {
             if (MetaModel::IsValidFilterCode($oDefinitionFilter->GetClass(), 'org_id')) {
                 $oDefinitionFilter->AddCondition('org_id', $currentOrganization, '=');
             }
         }
         $aResults = array();
         $oDefinitionSet = new CMDBObjectSet($oDefinitionFilter);
         $iCount = $oDefinitionSet->Count();
         $oRulesFilter = new CMDBSearchFilter('AuditRule');
         $oRulesFilter->AddCondition('category_id', $oAuditCategory->GetKey(), '=');
         $oRulesSet = new DBObjectSet($oRulesFilter);
         while ($oAuditRule = $oRulesSet->fetch()) {
             $aRow = array();
             $aRow['description'] = $oAuditRule->GetName();
             if ($iCount == 0) {
                 // nothing to check, really !
                 $aRow['nb_errors'] = "<a href=\"audit.php?operation=errors&category=" . $oAuditCategory->GetKey() . "&rule=" . $oAuditRule->GetKey() . "\">0</a>";
                 $aRow['percent_ok'] = '100.00';
                 $aRow['class'] = GetReportColor($iCount, 0);
             } else {
                 try {
                     $oFilter = GetRuleResultFilter($oAuditRule->GetKey(), $oDefinitionFilter, $oAppContext);
                     $aErrors = $oFilter->ToDataArray(array('id'));
                     $iErrorsCount = count($aErrors);
예제 #7
0
try {
    if ($sOperation == 'search_form') {
        $sOQL = "SELECT {$sClass} {$sOQLClause}";
        $oFilter = DBObjectSearch::FromOQL($sOQL);
    } else {
        // Second part: advanced search form:
        if (!empty($sFilter)) {
            $oFilter = CMDBSearchFilter::unserialize($sFilter);
        } else {
            if (!empty($sClass)) {
                $oFilter = new CMDBSearchFilter($sClass);
            }
        }
    }
} catch (CoreException $e) {
    $oFilter = new CMDBSearchFilter($sClass);
    $oP->P("<b>" . Dict::Format('UI:UniversalSearch:Error', $e->getHtmlDesc()) . "</b>");
}
if ($oFilter != null) {
    $oSet = new CMDBObjectSet($oFilter);
    $oBlock = new DisplayBlock($oFilter, 'search', false);
    $aExtraParams = $oAppContext->GetAsHash();
    $aExtraParams['open'] = true;
    $aExtraParams['baseClass'] = $sBaseClass;
    $aExtraParams['action'] = utils::GetAbsoluteUrlAppRoot() . 'pages/UniversalSearch.php';
    //$aExtraParams['class'] = $sClassName;
    $oBlock->Display($oP, 0, $aExtraParams);
    // Search results
    $oResultBlock = new DisplayBlock($oFilter, 'list', false);
    $oResultBlock->Display($oP, 1);
    // Menu node
 /**
  * Search for an organization with the given code in the database
  *
  * @param string $Id The organization Id to look for
  * @return cmdbOrganization the organization if it exists, null otherwise
  */
 protected function GetOrganization($sId)
 {
     $oOrg = null;
     $oFilter = new CMDBSearchFilter('bizOrganization');
     $oFilter->AddCondition('id', $sId, '=');
     $oSet = new CMDBObjectSet($oFilter);
     if ($oSet->Count() > 0) {
         $oOrg = $oSet->Fetch();
         // Let's take the first one found
     }
     return $oOrg;
 }
 public static function FromScratch($sClass)
 {
     $oFilter = new CMDBSearchFilter($sClass);
     $oFilter->AddConditionExpression(new FalseExpression());
     $oRetSet = new self($oFilter);
     // NOTE: THIS DOES NOT WORK IF m_bLoaded is private in the base class (and you will not get any error message)
     $oRetSet->m_bLoaded = true;
     // no DB load
     return $oRetSet;
 }
예제 #10
0
 public function Process(CMDBChange $oChange = null)
 {
     // Note: $oChange can be null, in which case the aim is to check what would be done
     // Debug...
     //
     if (false) {
         echo "<pre>\n";
         echo "Attributes:\n";
         print_r($this->m_aAttList);
         echo "ExtKeys:\n";
         print_r($this->m_aExtKeys);
         echo "Reconciliation:\n";
         print_r($this->m_aReconcilKeys);
         echo "Synchro scope:\n";
         print_r($this->m_sSynchroScope);
         echo "Synchro changes:\n";
         print_r($this->m_aOnDisappear);
         //echo "Data:\n";
         //print_r($this->m_aData);
         echo "</pre>\n";
         exit;
     }
     $aResult = array();
     if (!is_null($this->m_sDateFormat) && strlen($this->m_sDateFormat) > 0) {
         // Translate dates from the source data
         //
         foreach ($this->m_aAttList as $sAttCode => $iCol) {
             $oAttDef = MetaModel::GetAttributeDef($this->m_sClass, $sAttCode);
             if ($oAttDef instanceof AttributeDateTime) {
                 foreach ($this->m_aData as $iRow => $aRowData) {
                     $sNewDate = utils::StringToTime($this->m_aData[$iRow][$iCol], $this->m_sDateFormat);
                     if ($sNewDate !== false) {
                         // Todo - improve the reporting
                         $this->m_aData[$iRow][$iCol] = $sNewDate;
                     } else {
                         // Leave the cell unchanged
                         $aResult[$iRow]["__STATUS__"] = new RowStatus_Issue(Dict::S('UI:CSVReport-Row-Issue-DateFormat'));
                         $aResult[$iRow][$sAttCode] = new CellStatus_Issue(null, $this->m_aData[$iRow][$iCol], Dict::S('UI:CSVReport-Row-Issue-DateFormat'));
                     }
                 }
             }
         }
     }
     // Compute the results
     //
     if (!is_null($this->m_sSynchroScope)) {
         $aVisited = array();
     }
     $iPreviousTimeLimit = ini_get('max_execution_time');
     $iLoopTimeLimit = MetaModel::GetConfig()->Get('max_execution_time_per_loop');
     foreach ($this->m_aData as $iRow => $aRowData) {
         set_time_limit($iLoopTimeLimit);
         if (isset($aResult[$iRow]["__STATUS__"])) {
             // An issue at the earlier steps - skip the rest
             continue;
         }
         try {
             $oReconciliationFilter = new CMDBSearchFilter($this->m_sClass);
             $bSkipQuery = false;
             foreach ($this->m_aReconcilKeys as $sAttCode) {
                 $valuecondition = null;
                 if (array_key_exists($sAttCode, $this->m_aExtKeys)) {
                     if ($this->IsNullExternalKeySpec($aRowData, $sAttCode)) {
                         $oExtKey = MetaModel::GetAttributeDef($this->m_sClass, $sAttCode);
                         if ($oExtKey->IsNullAllowed()) {
                             $valuecondition = $oExtKey->GetNullValue();
                             $aResult[$iRow][$sAttCode] = new CellStatus_Void($oExtKey->GetNullValue());
                         } else {
                             $aResult[$iRow][$sAttCode] = new CellStatus_NullIssue();
                         }
                     } else {
                         // The value has to be found or verified
                         list($sQuery, $aMatches) = $this->ResolveExternalKey($aRowData, $sAttCode, $aResult[$iRow]);
                         if (count($aMatches) == 1) {
                             $oRemoteObj = reset($aMatches);
                             // first item
                             $valuecondition = $oRemoteObj->GetKey();
                             $aResult[$iRow][$sAttCode] = new CellStatus_Void($oRemoteObj->GetKey());
                         } elseif (count($aMatches) == 0) {
                             $aResult[$iRow][$sAttCode] = new CellStatus_SearchIssue();
                         } else {
                             $aResult[$iRow][$sAttCode] = new CellStatus_Ambiguous(null, count($aMatches), $sQuery);
                         }
                     }
                 } else {
                     // The value is given in the data row
                     $iCol = $this->m_aAttList[$sAttCode];
                     if ($sAttCode == 'id') {
                         $valuecondition = $aRowData[$iCol];
                     } else {
                         $oAttDef = MetaModel::GetAttributeDef($this->m_sClass, $sAttCode);
                         $valuecondition = $oAttDef->MakeValueFromString($aRowData[$iCol], $this->m_bLocalizedValues);
                     }
                 }
                 if (is_null($valuecondition)) {
                     $bSkipQuery = true;
                 } else {
                     $oReconciliationFilter->AddCondition($sAttCode, $valuecondition, '=');
                 }
             }
             if ($bSkipQuery) {
                 $aResult[$iRow]["__STATUS__"] = new RowStatus_Issue(Dict::S('UI:CSVReport-Row-Issue-Reconciliation'));
             } else {
                 $oReconciliationSet = new CMDBObjectSet($oReconciliationFilter);
                 switch ($oReconciliationSet->Count()) {
                     case 0:
                         $oTargetObj = $this->CreateObject($aResult, $iRow, $aRowData, $oChange);
                         // $aResult[$iRow]["__STATUS__"]=> set in CreateObject
                         $aVisited[] = $oTargetObj->GetKey();
                         break;
                     case 1:
                         $oTargetObj = $oReconciliationSet->Fetch();
                         $this->UpdateObject($aResult, $iRow, $oTargetObj, $aRowData, $oChange);
                         // $aResult[$iRow]["__STATUS__"]=> set in UpdateObject
                         if (!is_null($this->m_sSynchroScope)) {
                             $aVisited[] = $oTargetObj->GetKey();
                         }
                         break;
                     default:
                         // Found several matches, ambiguous
                         $aResult[$iRow]["__STATUS__"] = new RowStatus_Issue(Dict::S('UI:CSVReport-Row-Issue-Ambiguous'));
                         $aResult[$iRow]["id"] = new CellStatus_Ambiguous(0, $oReconciliationSet->Count(), $oReconciliationFilter->ToOql());
                         $aResult[$iRow]["finalclass"] = 'n/a';
                 }
             }
         } catch (Exception $e) {
             $aResult[$iRow]["__STATUS__"] = new RowStatus_Issue(Dict::Format('UI:CSVReport-Row-Issue-Internal', get_class($e), $e->getMessage()));
         }
     }
     if (!is_null($this->m_sSynchroScope)) {
         // Compute the delta between the scope and visited objects
         $oScopeSearch = DBObjectSearch::FromOQL($this->m_sSynchroScope);
         $oScopeSet = new DBObjectSet($oScopeSearch);
         while ($oObj = $oScopeSet->Fetch()) {
             $iObj = $oObj->GetKey();
             if (!in_array($iObj, $aVisited)) {
                 set_time_limit($iLoopTimeLimit);
                 $iRow++;
                 $this->UpdateMissingObject($aResult, $iRow, $oObj, $oChange);
             }
         }
     }
     set_time_limit($iPreviousTimeLimit);
     // Fill in the blanks - the result matrix is expected to be 100% complete
     //
     foreach ($this->m_aData as $iRow => $aRowData) {
         foreach ($this->m_aAttList as $iCol) {
             if (!array_key_exists($iCol, $aResult[$iRow])) {
                 $aResult[$iRow][$iCol] = new CellStatus_Void($aRowData[$iCol]);
             }
         }
         foreach ($this->m_aExtKeys as $sAttCode => $aForeignAtts) {
             if (!array_key_exists($sAttCode, $aResult[$iRow])) {
                 $aResult[$iRow][$sAttCode] = new CellStatus_Void('n/a');
             }
             foreach ($aForeignAtts as $sForeignAttCode => $iCol) {
                 if (!array_key_exists($iCol, $aResult[$iRow])) {
                     // The foreign attribute is one of our reconciliation key
                     $aResult[$iRow][$iCol] = new CellStatus_Void($aRowData[$iCol]);
                 }
             }
         }
     }
     return $aResult;
 }