/** * 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; }
$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)) {
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); }
$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);
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; }
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; }