- Uploading a new file to a definition fully clears mapping - should fix some of the mapping confusion

- Add new / edit definition links in import dialog now open in new window, at the correct step
- Reworked import file checking
This commit is contained in:
Nathan Gray 2012-09-06 21:50:58 +00:00
parent c50a83a9a4
commit b38775db65
4 changed files with 183 additions and 63 deletions

View File

@ -425,11 +425,37 @@ class importexport_definitions_ui
return $bodefinitions->get_rows($query, $rows, $readonlys);
}
/**
* Edit a definition
*
* To jump to a certain step, pass the previous step in the URL step=wizard_stepXX
* The wizard will validate that step, then display the _next_ step..
*/
function edit()
{
if(!$_definition = $_GET['definition'])
{
//close window
$content = array(
'edit' => true,
'application' => $_GET['application'],
'plugin' => $_GET['plugin']
);
// Jump to a step
if($_GET['step'])
{
$content['edit'] = false;
// Wizard will process previous step, then advance
$content['step'] = $this->get_step($_GET['step'],-1);
$content['button']['next'] = 'pressed';
$this->wizard($content);
}
else
{
// Initial form
$this->wizard($content);
}
return;
}
if(is_numeric($_GET['definition']))
{
@ -442,6 +468,14 @@ class importexport_definitions_ui
$bodefinitions = new importexport_definitions_bo();
$definition = $bodefinitions->read($definition);
$definition['edit'] = true;
// Jump to a step
if($_GET['step'])
{
$definition['edit'] = false;
// Wizard will process previous step, then advance
$definition['step'] = $_GET['step'];;
$definition['button'] = array('next' => 'pressed');
}
$this->wizard($definition);
}
@ -572,7 +606,7 @@ class importexport_definitions_ui
if ($content['closewindow'])
{
$this->response->addScript("window.close();");
$this->response->addScript("opener.location = '" . egw::link('/index.php', array('menuaction' => 'importexport.importexport_definitions_ui.index')) . "';");
//$this->response->addScript("opener.location = '" . egw::link('/index.php', array('menuaction' => 'importexport.importexport_definitions_ui.index')) . "';");
// If Browser can't close window we display a "close" buuton and
// need to disable normal buttons
$this->response->addAssign('exec[button][previous]','style.display', 'none');

View File

@ -230,13 +230,6 @@ class importexport_import_csv implements importexport_iface_import_record { //,
protected function do_fieldmapping( ) {
$record = $this->record;
$this->record = array();
if(count($this->mapping) !== count($record))
{
throw new egw_exception_wrong_userinput(lang("Column mismatch. Expected %1 columns, your file has %2.",
count($this->mapping),
count($record)
));
}
foreach ($this->mapping as $cvs_idx => $new_idx)
{
if( $new_idx == '' ) continue;

View File

@ -78,26 +78,34 @@
$GLOBALS['egw_info']['flags']['currentapp'] = $appname;
// Destination if we need to hold the file
$cachefile = new egw_cache_files(array());
$dst_file = $cachefile->filename(egw_cache::keys(egw_cache::INSTANCE, 'importexport',
'import_'.md5($content['file']['name'].$GLOBALS['egw_info']['user']['account_id']), true),true);
if($content['dry-run'])
if($file)
{
echo $this->preview($file, $definition_obj);
$cachefile = new egw_cache_files(array());
$dst_file = $cachefile->filename(egw_cache::keys(egw_cache::INSTANCE, 'importexport',
'import_'.md5($content['file']['name'].$GLOBALS['egw_info']['user']['account_id']), true),true);
// Keep file
if($dst_file)
{
if(copy($content['file']['tmp_name'],$dst_file)) {
if($content['file']['name'] && copy($content['file']['tmp_name'],$dst_file)) {
$preserve['file']['tmp_name'] = $dst_file;
}
}
} elseif ($dst_file && $content['file']['tmp_name'] == $dst_file) {
// Remove file
$cachefile->delete(egw_cache::keys(egw_cache::INSTANCE, 'importexport',
'import_'.md5($content['file']['name'].$GLOBALS['egw_info']['user']['account_id'])));
// Check on matching columns
$check_message = array();
if(!self::check_file($file, $definition_obj, $check_message, $dst_file))
{
// Set this so plugin doesn't do any data changes
$content['dry-run'] = true;
$definition_obj->plugin_options = (array)$definition_obj->plugin_options + array('dry_run' => true);
}
$this->message .= implode($check_message, "<br />\n") . "<br />\n";
if($content['dry-run'])
{
echo $this->preview($file, $definition_obj);
}
$count = $plugin->import($file, $definition_obj);
}
$count = $plugin->import($file, $definition_obj);
$this->message .= lang('%1 records processed', $count);
@ -121,31 +129,15 @@
}
if($count != $total_processed) $this->message .= "<br />\n".lang('Some records may not have been imported');
}
} catch (Exception $e) {
$this->message = $e->getMessage();
// Add links for new / edit definition
$config = config::read('importexport');
if($GLOBALS['egw_info']['user']['apps']['admin'] || $config['users_create_definitions'])
{
// New definition
$add_link = egw::link('/index.php',array(
'menuaction' => 'importexport.importexport_definitions_ui.edit'
));
$this->message .= "<br />\n" . lang('Create a <a href="%1">new definition</a> for this file.', $add_link);
// Edit selected definition, if allowed
if($definition_obj->owner == $GLOBALS['egw_info']['user']['account_id'] ||
!$definition_obj->owner && $GLOBALS['egw_info']['user']['apps']['admin'])
{
$edit_link = egw::link('/index.php',array(
'menuaction' => 'importexport.importexport_definitions_ui.edit',
'definition' => $definition
));
$this->message .= "<br />\n" . lang('<a href="%1">Edit definition %2</a>',
$edit_link, $definition_obj->name );
}
if ($dst_file && $content['file']['tmp_name'] == $dst_file) {
// Remove file
$cachefile->delete(egw_cache::keys(egw_cache::INSTANCE, 'importexport',
'import_'.md5($content['file']['name'].$GLOBALS['egw_info']['user']['account_id'])));
unset($dst_file);
}
} catch (Exception $e) {
$this->message .= $e->getMessage();
}
}
elseif($content['cancel'])
@ -161,6 +153,11 @@
);
}
if(!array_key_exists('dry-run',$content))
{
$data['dry-run'] = true;
}
$data['appname'] = $preserve['appname'] = $appname ? $appname : ($definition_obj ? $definition_obj->application : '');
$data['definition'] = $definition;
$data['delimiter'] = $definition_obj->plugin_options['delimiter'];
@ -264,7 +261,91 @@
// Rewind
rewind($_stream);
return html::table($rows);
return '<h2>' . lang('Preview') . '</h2>' . html::table($rows);
}
/**
* Simple check to see if the file at least matches the definition
*
* Checks that column headers match
*/
public static function check_file(&$file, &$definition, &$message = array(), $dst_file = false)
{
$options =& $definition->plugin_options;
$data = fgetcsv($file, 8000, $options['fieldsep']);
rewind($file);
$data = translation::convert($data,$options['charset']);
$ok = true;
if(max(array_keys($data)) != max(array_keys($options['csv_fields'])))
{
$message[] = lang("Column mismatch. Expected %1 columns, your file has %2.",
max(array_keys($options['csv_fields'])),
max(array_keys($data))
);
$ok = false;
}
foreach($data as $index => $header)
{
if($index < count($options['csv_fields']) && !$options['field_mapping'][$index])
{
// Skipped column in definition
continue;
}
elseif($index < count($options['csv_fields']) && $options['csv_fields'][$index] != $header)
{
// Problem
$message[] = lang("Column mismatch: %1 should be %2, not %3",
$index,$options['csv_fields'][$index], $header);
// But can still continue
// $ok = false;
}
}
if(!$ok)
{
// Add links for new / edit definition
$config = config::read('importexport');
if($GLOBALS['egw_info']['user']['apps']['admin'] || $config['users_create_definitions'])
{
$actions = '';
// New definition
$add_link = egw::link('/index.php',array(
'menuaction' => 'importexport.importexport_definitions_ui.edit',
'application' => $definition->application,
'plugin' => $definition->plugin,
// Jump to name step
'step' => 'wizard_step21'
));
$add_link = "javascript:egw_openWindowCentered2('$add_link','_blank',500,500,'yes')";
$actions[] = lang('Create a <a href="%1">new definition</a> for this file', $add_link);
// Edit selected definition, if allowed
if($definition->owner == $GLOBALS['egw_info']['user']['account_id'] ||
!$definition->owner && $GLOBALS['egw_info']['user']['apps']['admin'])
{
$edit_link = array(
'menuaction' => 'importexport.importexport_definitions_ui.edit',
'definition' => $definition->name,
// Jump to file step
'step' => 'wizard_step21'
);
if($dst_file)
{
// Still have uploaded file, jump there
$GLOBALS['egw']->session->appsession('csvfile','',$dst_file);
$edit_link['step'] = 'wizard_step30';
}
$edit_link = egw::link('/index.php',$edit_link);
$edit_link = "javascript:egw_openWindowCentered2('$edit_link','_blank',500,500,'yes')";
$actions[] = lang('Edit definition <a href="%1">%2</a> to match your file',
$edit_link, $definition->name );
}
$actions[] = lang('Edit your file to match the definition: ')
. implode(array_intersect_key($options['csv_fields'],$options['field_mapping']),', ');
$message[] = "\n<li>".implode($actions,"\n<li>");
}
}
return $ok;
}
}
?>

View File

@ -1,12 +1,12 @@
<?php
/**
* eGroupWare - A basic implementation of a wizard to go with the basic CSV plugin.
*
*
* To add or remove steps, change $this->steps appropriately. The key is the function, the value is the title.
* Don't go past 80, as that's where the wizard picks it back up again to finish it off.
*
*
* For the mapping to work properly, you will have to fill $mapping_fields with the target fields for your application.
*
*
* NB: Your wizard class must be in <appname>/inc/class.appname_wizard_<plugin_name>.inc.php
*
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
@ -15,7 +15,7 @@
* @author Nathan Gray
*/
class importexport_wizard_basic_import_csv
class importexport_wizard_basic_import_csv
{
const TEMPLATE_MARKER = '-eTemplate-';
@ -81,7 +81,7 @@ class importexport_wizard_basic_import_csv
if($content['file']['tmp_name']) {
$csvfile = tempnam($GLOBALS['egw_info']['server']['temp_dir'],$content['plugin']."_");
move_uploaded_file($content['file']['tmp_name'], $csvfile);
$GLOBALS['egw']->session->appsession('csvfile','',$csvfile);
$GLOBALS['egw']->session->appsession('csvfile',$content['application'],$csvfile);
}
unset($content['file']);
return $GLOBALS['egw']->importexport_definitions_ui->get_step($content['step'],1);
@ -124,20 +124,22 @@ class importexport_wizard_basic_import_csv
{
case 'next':
// Process sample file for fields
if (($handle = fopen($GLOBALS['egw']->session->appsession('csvfile'), "rb")) !== FALSE) {
if (($handle = fopen($GLOBALS['egw']->session->appsession('csvfile',$content['application']), "rb")) !== FALSE) {
$data = fgetcsv($handle, 8000, $content['fieldsep']);
fclose($handle);
unlink($GLOBALS['egw']->session->appsession('csvfile'));
// Remove & forget file
unlink($GLOBALS['egw']->session->appsession('csvfile',$content['application']));
egw_cache::setSession($content['application'], 'csvfile', '');
$content['csv_fields'] = translation::convert($data,$content['charset']);
// Reset field mapping for new file
$content['field_mapping'] = array();
// Try to match automatically
$english = array();
foreach($content['csv_fields'] as $index => $field) {
if($content['field_mapping'][$index]) continue;
if(is_array($content['plugin_options']['field_mapping']) && $content['plugin_options']['field_mapping'][$index]) {
# Copy already set, but allow new file to update
$content['field_mapping'][$index] = $content['plugin_options']['field_mapping'][$index];
}
$best_match = '';
$best_match_value = 0;
foreach($this->mapping_fields as $key => $field_name) {
@ -162,7 +164,7 @@ class importexport_wizard_basic_import_csv
// Check for similar but slightly different
$match = 0;
if(similar_text(strtolower($field), strtolower($field_name), $match) &&
if(similar_text(strtolower($field), strtolower($field_name), $match) &&
$match > 85 &&
$match > $best_match_value
) {
@ -208,12 +210,22 @@ class importexport_wizard_basic_import_csv
if(!$content['num_header_lines'] && $content['plugin_options']['num_header_lines']) {
$content['num_header_lines'] = $content['plugin_options']['num_header_lines'];
}
else
{
// Default to 1 line
$content['num_header_lines'] = 1;
}
if(!$content['update_cats'] && $content['plugin_options']['update_cats']) {
$content['update_cats'] = $content['plugin_options']['update_cats'];
}
if(!array_key_exists('convert', $content) && array_key_exists('convert', $content['plugin_options'])) {
$content['convert'] = $content['plugin_options']['convert'];
}
else
{
// Default to human
$content['convert'] = 1;
}
$sel_options['charset'] = $GLOBALS['egw']->translation->get_installed_charsets()+
array(
@ -247,10 +259,10 @@ class importexport_wizard_basic_import_csv
}
/**
* Process the sample file, get the fields out of it, then allow them to be mapped onto
* Process the sample file, get the fields out of it, then allow them to be mapped onto
* the fields the destination understands. Also, set any translations to be done to the field.
*
* You can use the eTemplate
*
* You can use the eTemplate
*/
function wizard_step50(&$content, &$sel_options, &$readonlys, &$preserv)
{
@ -328,7 +340,7 @@ class importexport_wizard_basic_import_csv
$content[++$i]['index'] = $i - 1;
if(strstr($field,'no_csv_')) $j++;
}
while ($j <= 3)
while ($j <= 3)
{
$content['csv_fields'][] = 'no_csv_'.$j;
$content['field_mapping'][] = $content['field_conversion'][] = '';
@ -395,7 +407,7 @@ class importexport_wizard_basic_import_csv
// Make at least 1 (empty) conditions
$j = count($content['conditions']);
while ($j < 1)
while ($j < 1)
{
$content['conditions'][] = array(
'string' => '',