/** * Specific to the interactive csv import * * @copyright Copyright (C) 2010-2012 Combodo SARL * @license http://opensource.org/licenses/AGPL-3.0 */ require_once('../approot.inc.php'); require_once(APPROOT.'/application/application.inc.php'); require_once(APPROOT.'/application/webpage.class.inc.php'); require_once(APPROOT.'/application/ajaxwebpage.class.inc.php'); require_once(APPROOT.'/application/wizardhelper.class.inc.php'); require_once(APPROOT.'/application/ui.linkswidget.class.inc.php'); require_once(APPROOT.'/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 * @param AttributeDefinition $oExtKeyAttDef Attribute definition of the external key * @param bool $bAdvanced True if advanced mode * @return Ash List of codes=>display name: xxx->yyy where yyy are the reconciliation keys for the object xxx */ function GetMappingsForExtKey($sAttCode, AttributeDefinition $oExtKeyAttDef, $bAdvanced) { $aResult = array(); $sTargetClass = $oExtKeyAttDef->GetTargetClass(); foreach(MetaModel::ListAttributeDefs($sTargetClass) as $sTargetAttCode => $oTargetAttDef) { if (MetaModel::IsReconcKey($sTargetClass, $sTargetAttCode)) { $bExtKey = $oTargetAttDef->IsExternalKey(); $sSuffix = ''; if ($bExtKey) { $sSuffix = '->id'; } if ($bAdvanced || !$bExtKey) { // When not in advanced mode do not allow to use reconciliation keys (on external keys) if they are themselves external keys ! $aResult[$sAttCode.'->'.$sTargetAttCode] = $oExtKeyAttDef->GetLabel().'->'.$oTargetAttDef->GetLabel().$sSuffix; } } } 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 * @param string $sDefaultChoice If set, this will be the item selected by default * @return string The HTML code corresponding to the drop-down list for this field */ function GetMappingForField($sClassName, $sFieldName, $iFieldIndex, $bAdvancedMode, $sDefaultChoice) { $aChoices = array('' => Dict::S('UI:CSVImport:MappingSelectOne')); $aChoices[':none:'] = Dict::S('UI:CSVImport:MappingNotApplicable'); $sFieldCode = ''; // Code of the attribute, if there is a match $aMatches = array(); if (preg_match('/^(.+)\*$/', $sFieldName, $aMatches)) { // Remove any trailing "star" character. // A star character at the end can be used to indicate a mandatory field $sFieldName = $aMatches[1]; } else if (preg_match('/^(.+)\*->(.+)$/', $sFieldName, $aMatches)) { // Remove any trailing "star" character before the arrow (->) // A star character at the end can be used to indicate a mandatory field $sFieldName = $aMatches[1].'->'.$aMatches[2]; } if (($sFieldName == 'id') || ($sFieldName == Dict::S('UI:CSVImport:idField'))) { $sFieldCode = 'id'; } if ($bAdvancedMode) { $aChoices['id'] = Dict::S('UI:CSVImport:idField'); } foreach(MetaModel::ListAttributeDefs($sClassName) as $sAttCode => $oAttDef) { $sStar = ''; if ($oAttDef->IsExternalKey()) { if (($sFieldName == $oAttDef->GetLabel()) || ($sFieldName == $sAttCode)) { $sFieldCode = $sAttCode; } if ($bAdvancedMode) { $aChoices[$sAttCode] = $oAttDef->GetLabel(); } $oExtKeyAttDef = MetaModel::GetAttributeDef($sClassName, $oAttDef->GetKeyAttCode()); if (!$oExtKeyAttDef->IsNullAllowed()) { $sStar = '*'; } // 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)) { $bExtKey = $oTargetAttDef->IsExternalKey(); $aSignatures = array(); $aSignatures[] = $oAttDef->GetLabel().'->'.$oTargetAttDef->GetLabel(); $aSignatures[] = $sAttCode.'->'.$sTargetAttCode; if ($bExtKey) { $aSignatures[] = $oAttDef->GetLabel().'->'.$oTargetAttDef->GetLabel().'->id'; $aSignatures[] = $sAttCode.'->'.$sTargetAttCode.'->id'; } if ($bAdvancedMode || !$bExtKey) { // When not in advanced mode do not allow to use reconciliation keys (on external keys) if they are themselves external keys ! $aChoices[$sAttCode.'->'.$sTargetAttCode] = MetaModel::GetLabel($sClassName, $sAttCode.'->'.$sTargetAttCode, true); foreach ($aSignatures as $sSignature) { if (strcasecmp($sFieldName, $sSignature) == 0) { $sFieldCode = $sAttCode.'->'.$sTargetAttCode; } } } } } } else if ($oAttDef->IsWritable() && (!$oAttDef->IsLinkset() || ($bAdvancedMode && $oAttDef->IsIndirect()))) { $aChoices[$sAttCode] = MetaModel::GetLabel($sClassName, $sAttCode, true); if ( ($sFieldName == $oAttDef->GetLabel()) || ($sFieldName == $sAttCode)) { $sFieldCode = $sAttCode; } } } asort($aChoices); $sHtml = "\n"; return $sHtml; } try { require_once(APPROOT.'/application/startup.inc.php'); require_once(APPROOT.'/application/loginwebpage.class.inc.php'); LoginWebPage::DoLogin(); // Check user rights and prompt if needed $sOperation = utils::ReadParam('operation', ''); switch($sOperation) { case 'parser_preview': $oPage = new ajax_page(""); $oPage->no_cache(); $oPage->SetContentType('text/html'); $sSeparator = utils::ReadParam('separator', ',', false, 'raw_data'); if ($sSeparator == 'tab') $sSeparator = "\t"; $sTextQualifier = utils::ReadParam('qualifier', '"', false, 'raw_data'); $iLinesToSkip = utils::ReadParam('do_skip_lines', 0); $bFirstLineAsHeader = utils::ReadParam('header_line', true); $sEncoding = utils::ReadParam('encoding', 'UTF-8'); $sData = stripslashes(utils::ReadParam('csvdata', true, false, 'raw_data')); $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("
".sprintf($sFormat, $index)." | "); foreach ($aRow as $sCell) { $oPage->add(''.htmlentities($sCell, ENT_QUOTES, 'UTF-8').' | '); } $oPage->add("
---|---|
".sprintf($sFormat, $index)." | "); foreach ($aRow as $sCell) { $oPage->add(''.htmlentities($sCell, ENT_QUOTES, 'UTF-8').' | '); } $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').' | '); $oPage->add('|
---|---|---|---|---|---|
$sField | "); $oPage->add(''.GetMappingForField($sClassName, $sField, $index, $bAdvanced, $sDefaultChoice).' | '); $oPage->add(''); $oPage->add(' | '); $oPage->add(' | '.(isset($aData[$iStartLine][$index-1]) ? htmlentities($aData[$iStartLine][$index-1], ENT_QUOTES, 'UTF-8') : ' ').' | '); $oPage->add(''.(isset($aData[$iStartLine+1][$index-1]) ? htmlentities($aData[$iStartLine+1][$index-1], ENT_QUOTES, 'UTF-8') : ' ').' | '); $oPage->add('
'); $oPage->add('
'); $oPage->add(''); $oPage->add(''); $oPage->add(''); } } else { $oPage = new ajax_page("Class $sClassName is not a valid class !"); } break; } $oPage->output(); } catch (Exception $e) { IssueLog::Error($e->getMessage()); } ?>