'); /////////////////////////////////////////////////////////////////////////////// // External key/field naming conventions (sharing the naming space with std attributes /////////////////////////////////////////////////////////////////////////////// function IsExtKeyField($sColDesc) { return ($iPos = strpos($sColDesc, EXTKEY_SEP)); } function GetExtKeyFieldCodes($sColDesc) { $iPos = strpos($sColDesc, EXTKEY_SEP); return array( substr($sColDesc, 0, $iPos), substr($sColDesc, $iPos + strlen(EXTKEY_SEP)) ); } function MakeExtFieldLabel($sClass, $sExtKeyAttCode, $sForeignAttCode) { $oExtKeyAtt = MetaModel::GetAttributeDef($sClass, $sExtKeyAttCode); if ($sForeignAttCode == 'id') { $sForeignAttLabel = 'id'; } else { $oForeignAtt = MetaModel::GetAttributeDef($oExtKeyAtt->GetTargetClass(), $sForeignAttCode); $sForeignAttLabel = $oForeignAtt->GetLabel(); } return $oExtKeyAtt->GetLabel().EXTKEY_LABELSEP.$sForeignAttLabel; } function MakeExtFieldSelectValue($sAttCode, $sExtAttCode) { return $sAttCode.EXTKEY_SEP.$sExtAttCode; } /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// function ShowTableForm($oPage, $oCSVParser, $sClass) { $aData = $oCSVParser->ToArray(null, 3); $aColToRow = array(); foreach($aData as $aRow) { foreach ($aRow as $sFieldId=>$sValue) { $aColToRow[$sFieldId][] = $sValue; } } $aFields = array(); foreach($oCSVParser->ListFields() as $iFieldIndex=>$sFieldName) { $aOptions = array(); $aOptions['id'] = array( 'LabelHtml' => "Private key", 'LabelRef' => "Private key", 'IsReconcKey' => false, 'Tip' => '', ); $sFoundAttCode = ""; // quick and dirty way to remind if a match has been found and suggest a reconciliation key if possible foreach(MetaModel::ListAttributeDefs($sClass) as $sAttCode=>$oAtt) { if ($oAtt->IsExternalField()) continue; $bIsThatField = (strcasecmp($sFieldName, $oAtt->GetLabel()) == 0); $sFoundAttCode = (MetaModel::IsValidFilterCode($sClass, $sAttCode) && $bIsThatField) ? $sAttCode : $sFoundAttCode; if ($oAtt->IsExternalKey()) { // An external key might be loaded by // the pkey or a reconciliation key // $aOptions[MakeExtFieldSelectValue($sAttCode, 'id')] = array( 'LabelHtml' => "".$oAtt->GetLabel()." (id)", 'LabelRef' => $oAtt->GetLabel()." (id)", 'IsReconcKey' => MetaModel::IsReconcKey($sClass, $sAttCode), 'Tip' => '', ); $sRemoteClass = $oAtt->GetTargetClass(); foreach(MetaModel::GetReconcKeys($sRemoteClass) as $sExtAttCode) { $sValue = MakeExtFieldSelectValue($sAttCode, $sExtAttCode); // Create two entries: // - generic syntax (ext key label -> remote field label) // - if an ext field exists that corresponds to it, allow its label $sLabel1 = MakeExtFieldLabel($sClass, $sAttCode, $sExtAttCode); $bFoundTwin = false; foreach (MetaModel::GetExternalFields($sClass, $sAttCode) as $oExtFieldAtt) { if ($oExtFieldAtt->GetExtAttCode() == $sExtAttCode) { $aOptions[$sValue] = array( 'LabelHtml' => htmlentities($oExtFieldAtt->GetLabel()), 'LabelRef' => $oExtFieldAtt->GetLabel(), 'IsReconcKey' => false, 'Tip' => "equivalent to '".htmlentities($sLabel1)."'", ); $bFoundTwin = true; $sLabel2 = $oExtFieldAtt->GetLabel(); break; } } $aOptions[$sValue] = array( 'LabelHtml' => htmlentities($sLabel1), 'LabelRef' => $sLabel1, 'IsReconcKey' => false, 'Tip' => $bFoundTwin ? "equivalent to '".htmlentities($sLabel2)."'" : "", ); } } else { $aOptions[$sAttCode] = array( 'LabelHtml' => htmlentities($oAtt->GetLabel()), 'LabelRef' => $oAtt->GetLabel(), 'IsReconcKey' => MetaModel::IsReconcKey($sClass, $sAttCode), 'Tip' => '', ); } } // Find the best match $iMin = strlen($sFieldName); $sBestValue = null; foreach ($aOptions as $sValue => $aData) { $iDist = levenshtein(strtolower($sFieldName), strtolower($aData['LabelRef'])); if (($iDist != -1) && ($iDist < $iMin)) { $iMin = $iDist; $sBestValue = $sValue; } } $sSelField = ""; $aFields["field$iFieldIndex"]["label"] = $sSelField; $sCHECKED = ($sFieldName == "id" || MetaModel::IsReconcKey($sClass, $sFoundAttCode)) ? " CHECKED" : ""; $aFields["field$iFieldIndex"]["label"] .= ""; if (array_key_exists($iFieldIndex, $aColToRow)) { $aFields["field$iFieldIndex"]["value"] = $aColToRow[$iFieldIndex]; } } $oPage->details($aFields); } function ProcessData($oPage, $sClass, $oCSVParser, $aFieldMap, $aIsReconcKey, CMDBChange $oChange = null) { // Note: $oChange can be null, in which case the aim is to check what would be done // Setup field mapping: sort out between values and other specific columns // $iPKeyId = null; $aReconcilKeys = array(); $aAttList = array(); $aExtKeys = array(); foreach($aFieldMap as $sFieldId=>$sColDesc) { $iFieldId = (int) substr($sFieldId, strlen("field")); if ($sColDesc == "id") { // Skip ! $iPKeyId = $iFieldId; } elseif ($sColDesc == "__none__") { // Skip ! } elseif (IsExtKeyField($sColDesc)) { // This field is value to search on, to find a value for an external key list($sExtKeyAttCode, $sExtReconcKeyAttCode) = GetExtKeyFieldCodes($sColDesc); $aExtKeys[$sExtKeyAttCode][$sExtReconcKeyAttCode] = $iFieldId; } elseif (array_key_exists($sFieldId, $aIsReconcKey)) { // This value is a reconciliation key $aReconcilKeys[$sColDesc] = $iFieldId; $aAttList[$sColDesc] = $iFieldId; // A reconciliation key is also a field } else { // $sColDesc is an attribute code $aAttList[$sColDesc] = $iFieldId; } } // Setup result presentation // $aDisplayConfig = array(); $aDisplayConfig["__RECONCILIATION__"] = array("label"=>"Reconciliation", "description"=>""); $aDisplayConfig["__STATUS__"] = array("label"=>"Import status", "description"=>""); if (isset($iPKeyId)) { $aDisplayConfig["col$iPKeyId"] = array("label"=>"id", "description"=>""); } foreach($aReconcilKeys as $sAttCode => $iCol) { $sLabel = MetaModel::GetAttributeDef($sClass, $sAttCode)->GetLabel(); $aDisplayConfig["col$iCol"] = array("label"=>"$sLabel", "description"=>""); } foreach($aExtKeys as $sAttCode=>$aKeyConfig) { $oExtKeyAtt = MetaModel::GetAttributeDef($sClass, $sAttCode); $sLabel = $oExtKeyAtt->GetLabel(); $aDisplayConfig[$sAttCode] = array("label"=>"$sLabel", "description"=>""); foreach ($aKeyConfig as $sForeignAttCode => $iCol) { // The foreign attribute is one of our reconciliation key $sLabel = MakeExtFieldLabel($sClass, $sAttCode, $sForeignAttCode); $aDisplayConfig["col$iCol"] = array("label"=>"$sLabel", "description"=>""); } } foreach ($aAttList as $sAttCode => $iCol) { $sLabel = MetaModel::GetAttributeDef($sClass, $sAttCode)->GetLabel(); $aDisplayConfig["col$iCol"] = array("label"=>"$sLabel", "description"=>""); } // Compute the results // $aData = $oCSVParser->ToArray(); $oBulk = new BulkChange( $sClass, $aData, $aAttList, array_keys($aReconcilKeys), $aExtKeys ); $aRes = $oBulk->Process($oChange); $aResultDisp = array(); // to be displayed foreach($aRes as $iRow => $aRowData) { $aRowDisp = array(); $aRowDisp["__RECONCILIATION__"] = $aRowData["__RECONCILIATION__"]; $aRowDisp["__STATUS__"] = $aRowData["__STATUS__"]->GetDescription(true); foreach($aRowData as $sKey => $value) { if ($sKey == '__RECONCILIATION__') continue; if ($sKey == '__STATUS__') continue; switch (get_class($value)) { case 'CellChangeSpec_Void': $sClass = ''; break; case 'CellChangeSpec_Unchanged': $sClass = ''; break; case 'CellChangeSpec_Modify': $sClass = 'csvimport_ok'; break; case 'CellChangeSpec_Init': $sClass = 'csvimport_init'; break; case 'CellChangeSpec_Issue': $sClass = 'csvimport_error'; break; } if (empty($sClass)) { $aRowDisp[$sKey] = $value->GetDescription(true); } else { $aRowDisp[$sKey] = "