* @author Romain Quetiez * @author Denis Flaven * @license http://www.opensource.org/licenses/gpl-3.0.html LGPL */ require_once('../application/application.inc.php'); require_once('../application/webpage.class.inc.php'); require_once('../application/ajaxwebpage.class.inc.php'); require_once('../application/wizardhelper.class.inc.php'); require_once('../application/ui.linkswidget.class.inc.php'); require_once('../application/csvpage.class.inc.php'); /** * Determines if the name of the field to be mapped correspond * to the name of an external key or an Id of the given class * @param string $sClassName The name of the class * @param string $sFieldCode The attribute code of the field , or empty if no match * @return bool true if the field corresponds to an id/External key, false otherwise */ function IsIdField($sClassName, $sFieldCode) { $bResult = false; if (!empty($sFieldCode)) { if ($sFieldCode == 'id') { $bResult = true; } else if (strpos($sFieldCode, '->') === false) { $oAttDef = MetaModel::GetAttributeDef($sClassName, $sFieldCode); $bResult = $oAttDef->IsExternalKey(); } } return $bResult; } /** * Get all the fields xxx->yyy based on the field xxx which is an external key * @param string $sExtKeyAttCode Attribute code of the external key * @return Ash List of codes=>display name: xxx->yyy where yyy are the reconciliation keys for the object xxx */ function GetMappingsForExtKey($sAttCode, AttributeDefinition $oExtKeyAttDef) { $aResult = array(); $sTargetClass = $oExtKeyAttDef->GetTargetClass(); foreach(MetaModel::ListAttributeDefs($sTargetClass) as $sTargetAttCode => $oTargetAttDef) { if (MetaModel::IsReconcKey($sTargetClass, $sTargetAttCode)) { $aResult[$sAttCode.'->'.$sTargetAttCode] = $oExtKeyAttDef->GetLabel().'->'.$oTargetAttDef->GetLabel(); } } return $aResult; } /** * Helper function to build the mapping drop-down list for a field * Spec: Possible choices are "writable" fields in this class plus external fields that are listed as reconciliation keys * for any class pointed to by an external key in the current class. * If not in advanced mode, all "id" fields (id and external keys) must be mapped to ":none:" (i.e -- ignore this field --) * External fields that do not correspond to a reconciliation key must be mapped to ":none:" * Otherwise, if a field equals either the 'code' or the 'label' (translated) of a field, then it's mapped automatically * @param string $sClassName Name of the class used for the mapping * @param string $sFieldName Name of the field, as it comes from the data file (header line) * @param integer $iFieldIndex Number of the field in the sequence * @param bool $bAdvancedMode Whether or not advanced mode was chosen * @return string The HTML code corresponding to the drop-down list for this field */ function GetMappingForField($sClassName, $sFieldName, $iFieldIndex, $bAdvancedMode = false) { $aChoices = array('' => Dict::S('UI:CSVImport:MappingSelectOne')); $aChoices[':none:'] = Dict::S('UI:CSVImport:MappingNotApplicable'); $sFieldCode = ''; // Code of the attribute, if there is a match if ($sFieldName == 'id') { $sFieldCode = 'id'; } if ($bAdvancedMode) { $aChoices['id'] = Dict::S('UI:CSVImport:idField'); } foreach(MetaModel::ListAttributeDefs($sClassName) as $sAttCode => $oAttDef) { if ($oAttDef->IsExternalKey()) { if ( ($sFieldName == $oAttDef->GetLabel()) || ($sFieldName == $sAttCode)) { $sFieldCode = $sAttCode; } if ($bAdvancedMode) { $aChoices[$sAttCode] = $oAttDef->GetLabel(); } // Get fields of the external class that are considered as reconciliation keys $sTargetClass = $oAttDef->GetTargetClass(); foreach(MetaModel::ListAttributeDefs($sTargetClass) as $sTargetAttCode => $oTargetAttDef) { if (MetaModel::IsReconcKey($sTargetClass, $sTargetAttCode)) { $aChoices[$sAttCode.'->'.$sTargetAttCode] = $oAttDef->GetLabel().'->'.$oTargetAttDef->GetLabel(); if ((strcasecmp($sFieldName, $aChoices[$sAttCode.'->'.$sTargetAttCode]) == 0) || (strcasecmp($sFieldName, ($sAttCode.'->'.$sTargetAttCode)) == 0) ) { $sFieldCode = $sAttCode.'->'.$sTargetAttCode; } } } } else if ( ($oAttDef->IsWritable()) && (!$oAttDef->IsLinkSet()) ) { $aChoices[$sAttCode] = $oAttDef->GetLabel(); if ( ($sFieldName == $oAttDef->GetLabel()) || ($sFieldName == $sAttCode)) { $sFieldCode = $sAttCode; } } } asort($aChoices); $sHtml = "\n"; return $sHtml; } require_once('../application/startup.inc.php'); session_start(); if (isset($_SESSION['auth_user'])) { $sAuthUser = $_SESSION['auth_user']; $sAuthPwd = $_SESSION['auth_pwd']; // Attempt to login, fails silently UserRights::Login($sAuthUser, $sAuthPwd); } else { // No session information echo "

No session information

\n"; } $oContext = new UserContext(); $sOperation = utils::ReadParam('operation', ''); switch($sOperation) { case 'parser_preview': $oPage = new ajax_page(""); $oPage->no_cache(); $sSeparator = utils::ReadParam('separator', ','); if ($sSeparator == 'tab') $sSeparator = "\t"; $sTextQualifier = utils::ReadParam('qualifier', '"'); $iLinesToSkip = utils::ReadParam('nb_lines_skipped', 0); $bFirstLineAsHeader = utils::ReadParam('header_line', true); $sData = stripslashes(utils::ReadParam('csvdata', true)); $oCSVParser = new CSVParser($sData, $sSeparator, $sTextQualifier); $aData = $oCSVParser->ToArray($iLinesToSkip); $iTarget = count($aData); if ($iTarget == 0) { $oPage->p(Dict::S('UI:CSVImport:NoData')); } else { $sMaxLen = (strlen(''.$iTarget) < 3) ? 3 : strlen(''.$iTarget); // Pad line numbers to the appropriate number of chars, but at least 3 $sFormat = '%0'.$sMaxLen.'d'; $oPage->p("

".Dict::S('UI:Title:DataPreview')."

\n"); $oPage->p("
\n"); $oPage->add(""); $iMaxIndex= 10; // Display maximum 10 lines for the preview $index = 1; foreach($aData as $aRow) { $sCSSClass = 'csv_row'.($index % 2); if ( ($bFirstLineAsHeader) && ($index == 1)) { $oPage->add("\n"); $iNbCols = count($aRow); } else { if ($index == 1) $iNbCols = count($aRow); $oPage->add("\n"); } $index++; if ($index > $iMaxIndex) break; } $oPage->add("
".sprintf($sFormat, $index).""); $oPage->add(implode('', $aRow)); $oPage->add("
".sprintf($sFormat, $index).""); $oPage->add(implode('', $aRow)); $oPage->add("
\n"); $oPage->add("
\n"); if($iNbCols == 1) { $oPage->p(' '.Dict::S('UI:CSVImport:ErrorOnlyOneColumn')); } else { $oPage->p(' '); } } break; case 'display_mapping_form': $oPage = new ajax_page(""); $oPage->no_cache(); $sSeparator = utils::ReadParam('separator', ','); $sTextQualifier = utils::ReadParam('qualifier', '"'); $iLinesToSkip = utils::ReadParam('nb_lines_skipped', 0); $bFirstLineAsHeader = utils::ReadParam('header_line', true); $sData = stripslashes(utils::ReadParam('csvdata', true)); $sClassName = utils::ReadParam('class_name', ''); $bAdvanced = utils::ReadParam('advanced', false); $oCSVParser = new CSVParser($sData, $sSeparator, $sTextQualifier); $aData = $oCSVParser->ToArray($iLinesToSkip); $iTarget = count($aData); if ($iTarget == 0) { $oPage->p(Dict::S('UI:CSVImport:NoData')); } else { $oPage->add(""); $index = 1; $aFirstLine = $aData[0]; // Use the first row to determine the number of columns $iStartLine = 0; $iNbColumns = count($aFirstLine); if ($bFirstLineAsHeader) { $iStartLine = 1; foreach($aFirstLine as $sField) { $aHeader[] = $sField; } } else { // Build some conventional name for the fields: field1...fieldn $index= 1; foreach($aFirstLine as $sField) { $aHeader[] = Dict::Format('UI:CSVImport:FieldName', $index); $index++; } } $oPage->add("
\n"); $oPage->add(''); $oPage->add(''); $oPage->add(''); foreach($aHeader as $sField) { $oPage->add(''); $oPage->add(""); $oPage->add(''); $oPage->add(''); $oPage->add(''); $oPage->add(''); $oPage->add(''); $oPage->add(''); $index++; } $oPage->add("
'.Dict::S('UI:CSVImport:HeaderFields').''.Dict::S('UI:CSVImport:HeaderMappings').' '.Dict::S('UI:CSVImport:HeaderSearch').''.Dict::S('UI:CSVImport:DataLine1').''.Dict::S('UI:CSVImport:DataLine2').'
$sField'.GetMappingForField($sClassName, $sField, $index, $bAdvanced).' '.(isset($aData[$iStartLine][$index-1]) ? htmlentities($aData[$iStartLine][$index-1], ENT_QUOTES, 'UTF-8') : ' ').''.(isset($aData[$iStartLine+1][$index-1]) ? htmlentities($aData[$iStartLine+1][$index-1], ENT_QUOTES, 'UTF-8') : ' ').'
\n"); $aReconciliationKeys = MetaModel::GetReconcKeys($sClassName); $aMoreReconciliationKeys = array(); foreach($aReconciliationKeys as $sAttCode) { $oAttDef = MetaModel::GetAttributeDef($sClassName, $sAttCode); if ($oAttDef->IsExternalKey()) { $aMoreReconciliationKeys = array_keys(GetMappingsForExtKey($sAttCode, $oAttDef)); } } $sDefaultKeys = '"'.implode('", "',array_merge($aReconciliationKeys,$aMoreReconciliationKeys)).'"'; $oPage->add_ready_script( <<AddCondition('id', 0, '='); // Make sure we create an empty set $oSet = new CMDBObjectSet($oSearch); $sResult = cmdbAbstractObject::GetSetAsCSV($oSet); //$aCSV = explode("\n", $sCSV); // If there are more than one line, let's assume that the first line is a comment and skip it. //if (count($aCSV) > 1) //{ // $sResult = $aCSV[0]; //} //else //{ // $sResult = $sCSV; //} $sClassDisplayName = MetaModel::GetName($sClassName); $sDisposition = utils::ReadParam('disposition', 'inline'); if ($sDisposition == 'attachment') { $oPage = new CSVPage(""); $oPage->add_header("Content-disposition: attachment; filename=\"{$sClassDisplayName}.csv\""); $oPage->no_cache(); $oPage->add($sResult); } else { $oPage = new ajax_page(""); $oPage->no_cache(); $oPage->add('


'.$sClassDisplayName.'.csv

'); $oPage->add('

'); } break; } $oPage->output(); ?>