? 651478-33_mapping_on_import.patch ? 651478-34_mapping_on_import.patch ? feeds.651478.33.patch ? libraries/simplepie.inc Index: feeds.module =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/feeds/feeds.module,v retrieving revision 1.47 diff -u -p -r1.47 feeds.module --- feeds.module 19 Jun 2010 20:34:31 -0000 1.47 +++ feeds.module 8 Jul 2010 18:41:48 -0000 @@ -65,10 +65,10 @@ function feeds_perm() { */ function feeds_forms() { $forms = array(); - $forms['FeedsImporter_feeds_config_form']['callback'] = 'feeds_config_form'; + $forms['FeedsImporter_feeds_form']['callback'] = 'feeds_form'; $plugins = feeds_get_plugins(); foreach ($plugins as $plugin) { - $forms[$plugin['handler']['class'] .'_feeds_config_form']['callback'] = 'feeds_config_form'; + $forms[$plugin['handler']['class'] .'_feeds_form']['callback'] = 'feeds_form'; } return $forms; } @@ -103,6 +103,15 @@ function feeds_menu() { 'file' => 'feeds.pages.inc', 'type' => MENU_LOCAL_TASK, ); + $items['import/'. $importer->id . '/mapping'] = array( + 'title' => t('Mapping'), + 'page callback' => 'drupal_get_form', + 'page arguments' => array('feeds_import_mapping_form', 1), + 'access callback' => 'feeds_access', + 'access arguments' => array('import', $importer->id), + 'file' => 'feeds.pages.inc', + 'type' => MENU_LOCAL_TASK, + ); } else { $items['node/%node/import'] = array( @@ -125,7 +134,18 @@ function feeds_menu() { 'type' => MENU_LOCAL_TASK, 'weight' => 11, ); + $items['node/%node/mapping'] = array( + 'title' => t('Mapping'), + 'page callback' => 'drupal_get_form', + 'page arguments' => array('feeds_import_mapping_form', NULL, 1), + 'access callback' => 'feeds_access', + 'access arguments' => array('import', 1), + 'file' => 'feeds.pages.inc', + 'type' => MENU_LOCAL_TASK, + 'weight' => 12, + ); } + $items += $importer->fetcher->menuItem(); } if (count($items)) { @@ -154,6 +174,9 @@ function feeds_theme() { 'feeds_info' => array( 'file' => 'feeds.pages.inc', ), + 'feeds_mapping_form' => array( + 'file' => 'feeds.pages.inc' + ), ); } @@ -301,17 +324,22 @@ function feeds_nodeapi(&$node, $op, $for $source->addConfig($node_feeds); $source->save(); - // Refresh feed if import on create is selected and suppress_import is - // not set. - if ($op == 'insert' && feeds_importer($importer_id)->config['import_on_create'] && !isset($node_feeds['suppress_import'])) { - feeds_batch_set(t('Importing'), 'import', $importer_id, $node->nid); + if ($source->importer->processor->config['mapping_on_import']) { + $_REQUEST['destination'] = 'node/' . $node->nid . '/mapping/' . $source->importer->id; + } + else { + // Refresh feed if import on create is selected and suppress_import is + // not set. + if ($op == 'insert' && feeds_importer($importer_id)->config['import_on_create'] && !isset($node_feeds['suppress_import'])) { + feeds_batch_set(t('Importing'), 'import', $importer_id, $node->nid); + } + // Add import to scheduler. + feeds_scheduler()->add($importer_id, 'import', $node->nid); + // Add expiry to schedule, in case this is the first feed of this + // configuration. + feeds_scheduler()->add($importer_id, 'expire'); + $node_feeds = NULL; } - // Add import to scheduler. - feeds_scheduler()->add($importer_id, 'import', $node->nid); - // Add expiry to schedule, in case this is the first feed of this - // configuration. - feeds_scheduler()->add($importer_id, 'expire'); - $node_feeds = NULL; break; case 'delete': // Remove feed from scheduler and delete source. Index: feeds.pages.inc =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/feeds/feeds.pages.inc,v retrieving revision 1.18 diff -u -p -r1.18 feeds.pages.inc --- feeds.pages.inc 4 May 2010 21:24:58 -0000 1.18 +++ feeds.pages.inc 8 Jul 2010 18:41:48 -0000 @@ -59,6 +59,12 @@ function feeds_import_form(&$form_state, '#type' => 'submit', '#value' => t('Import'), ); + + // If mapping on import is selected, redirect to feeds_import_mapping_form + if ($source->importer->processor->config['mapping_on_import']) { + $form['#redirect'] = 'import/' . $importer_id . '/mapping'; + } + return $form; } @@ -74,20 +80,25 @@ function feeds_import_form_validate($for * Submit handler for feeds_import_form(). */ function feeds_import_form_submit($form, &$form_state) { - // Save source and import. $source = feeds_source($form['#importer_id']); $source->addConfig($form_state['values']['feeds']); $source->save(); - // Refresh feed if import on create is selected. - if ($source->importer->config['import_on_create']) { - feeds_batch_set(t('Importing'), 'import', $form['#importer_id']); + if ($source->importer->processor->config['mapping_on_import']) { + // Handle the redirection to mapping form + $form_state['redirect'] = $form['#redirect']; + } + else { + // Refresh feed if import on create is selected. + if ($source->importer->config['import_on_create']) { + feeds_batch_set(t('Importing'), 'import', $form['#importer_id']); + } + + // Add importer to schedule. + feeds_scheduler()->add($form['#importer_id'], 'import'); + feeds_scheduler()->add($form['#importer_id'], 'expire'); } - - // Add importer to schedule. - feeds_scheduler()->add($form['#importer_id'], 'import'); - feeds_scheduler()->add($form['#importer_id'], 'expire'); } /** @@ -152,3 +163,143 @@ function feeds_fetcher_callback($importe } drupal_access_denied(); } + +/** + * Declare Feeds mapping on import form + */ +function feeds_import_mapping_form(&$form_state, $importer_id, $node = NULL) { + if (empty($node)) { + $feed_nid = 0; + } + else { + $importer_id = feeds_get_importer_id($node->type); + $feed_nid = empty($node) ? 0 : $node->nid; + } + + $source = feeds_source($importer_id, $feed_nid); + + // Fetch and parse the source to enable batch to provide mapping sources + $batch = $source->importer->fetcher->fetch($source); + $source->importer->parser->parse($batch, $source); + + $form = $source->importer->processor->mappingForm($form, 'mapping', $batch); + $form['#configurable'] = $source->importer->processor; + $form['#importer_id'] = $importer_id; + $form['#feed_nid'] = $feed_nid; + + $form['submit'] = array( + '#type' => 'submit', + '#value' => t('Import'), + '#submit' => array('feeds_import_mapping_form_import_submit'), + ); + return $form; +} + +/** + * Default submit handler for mapping on import form + */ +function feeds_import_mapping_form_submit($form, &$form_state) { + $form['#configurable']->addConfig($form_state['values']); + $form['#configurable']->save(); + drupal_set_message(t('Your changes have been saved.')); + feeds_cache_clear(FALSE); +} + +/** + * Import submit handler for mapping on import form + */ +function feeds_import_mapping_form_import_submit($form, &$form_state) { + // Handle the redirections + if (!$form['#feed_nid']) { + $form_state['redirect'] = 'import/' . $form['#importer_id']; + } + else { + $form_state['redirect'] = 'node/' . $form['#feed_nid']; + } + + $source = feeds_source($form['#importer_id'], $form['#feed_nid']); + + // Refresh feed if import on create is selected. + if ($source->importer->config['import_on_create']) { + feeds_batch_set(t('Importing'), 'import', $form['#importer_id'], $form['#feed_nid']); + } + + // Add importer to schedule. + feeds_scheduler()->add($form['#importer_id'], 'import', $form['#feed_nid']); + feeds_scheduler()->add($form['#importer_id'], 'expire', $form['#feed_nid']); +} + +/** + * Theme function for feeds_mapping_form(). + */ +function theme_feeds_mapping_form($form) { + // Build the actual mapping table. + $header = array( + t('Source'), + t('Target'), + t('Unique target'), + ' ', + ); + $rows = array(); + if (is_array($form['#mappings'])) { + foreach ($form['#mappings'] as $i => $mapping) { + $rows[] = array( + $mapping['source'], + $mapping['target'], + drupal_render($form['unique_flags'][$i]), + drupal_render($form['remove_flags'][$i]), + ); + } + } + if (!count($rows)) { + $rows[] = array( + array( + 'colspan' => 4, + 'data' => t('No mappings defined.'), + ), + ); + } + $rows[] = array( + drupal_render($form['source']), + drupal_render($form['target']), + '', + drupal_render($form['add']), + ); + $output = '
'; + $output .= theme('table', $header, $rows); + + // Build the help table that explains available sources. + $legend = ''; + $rows = array(); + foreach (element_children($form['legendset']['legend']['sources']) as $k) { + $rows[] = array( + drupal_render($form['legendset']['legend']['sources'][$k]['name']), + drupal_render($form['legendset']['legend']['sources'][$k]['description']), + ); + } + if (count($rows)) { + $legend .= '

'. t('Sources') .'

'; + $legend .= theme('table', array(t('Name'), t('Description')), $rows); + } + + // Build the help table that explains available targets. + $rows = array(); + foreach (element_children($form['legendset']['legend']['targets']) as $k) { + $rows[] = array( + drupal_render($form['legendset']['legend']['targets'][$k]['name']), + drupal_render($form['legendset']['legend']['targets'][$k]['description']), + ); + } + $legend .= '

'. t('Targets') .'

'; + $legend .= theme('table', array(t('Name'), t('Description')), $rows); + + // Stick tables into collapsible fieldset. + $form['legendset']['legend'] = array( + '#value' => '
'. $legend .'
', + ); + + $output .= drupal_render($form['legendset']); + + $output .= drupal_render($form); + return $output; +} Index: feeds_ui/feeds_ui.admin.inc =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/feeds/feeds_ui/feeds_ui.admin.inc,v retrieving revision 1.31 diff -u -p -r1.31 feeds_ui.admin.inc --- feeds_ui/feeds_ui.admin.inc 6 Jul 2010 15:16:33 -0000 1.31 +++ feeds_ui/feeds_ui.admin.inc 8 Jul 2010 18:41:48 -0000 @@ -36,17 +36,6 @@ function feeds_ui_edit_help() { } /** - * Help text for mapping. - */ -function feeds_ui_mapping_help() { - return t(' -

- Define which elements of a single item of a feed (= Sources) map to which content pieces in Drupal (= Targets). Make sure that at least one definition has a Unique target. A unique target means that a value for a target can only occur once. E. g. only one item with the URL http://example.com/story/1 can exist. -

- '); -} - -/** * Build overview of available configurations. */ function feeds_ui_overview_form(&$form_status) { @@ -300,18 +289,20 @@ function feeds_ui_edit_page($importer, $ ctools_include('dependent'); if (empty($plugin_key)) { $active_container['title'] = t('Basic settings'); - $active_container['body'] = feeds_get_config_form($importer); + $active_container['body'] = feeds_get_form($importer, 'configForm'); } // feeds_plugin_instance() returns a correct result because feed has been // instantiated previously. elseif (in_array($plugin_key, array_keys($plugins)) && $plugin = feeds_plugin_instance($plugin_key, $importer->id)) { $active_container['title'] = t('Settings for !plugin', array('!plugin' => $plugins[$plugin_key]['name'])); - $active_container['body'] = feeds_get_config_form($plugin); + $active_container['body'] = feeds_get_form($plugin, 'configForm'); } break; case 'mapping': - $active_container['title'] = t('Mapping for !processor', array('!processor' => $plugins[$config['processor']['plugin_key']]['name'])); - $active_container['body'] = drupal_get_form('feeds_ui_mapping_form', $importer); + if (in_array($plugin_key, array_keys($plugins)) && $plugin = feeds_plugin_instance($plugin_key, $importer->id)) { + $active_container['title'] = t('Mapping for !processor', array('!processor' => $plugins[$config['processor']['plugin_key']]['name'])); + $active_container['body'] = feeds_get_form($plugin, 'mappingForm'); + } break; } @@ -346,7 +337,7 @@ function feeds_ui_edit_page($importer, $ // Fetcher. $fetcher = $plugins[$config['fetcher']['plugin_key']]; $actions = array(); - if (feeds_get_config_form($importer->fetcher)) { + if (feeds_get_form($importer->fetcher, 'configForm')) { $actions = array(l(t('Settings'), $path .'/settings/'. $config['fetcher']['plugin_key'])); } $info['title'] = t('Fetcher'); @@ -363,7 +354,7 @@ function feeds_ui_edit_page($importer, $ // Parser. $parser = $plugins[$config['parser']['plugin_key']]; $actions = array(); - if (feeds_get_config_form($importer->parser)) { + if (feeds_get_form($importer->parser, 'configForm')) { $actions = array(l(t('Settings'), $path .'/settings/'. $config['parser']['plugin_key'])); } $info['title'] = t('Parser'); @@ -380,10 +371,10 @@ function feeds_ui_edit_page($importer, $ // Processor. $processor = $plugins[$config['processor']['plugin_key']]; $actions = array(); - if (feeds_get_config_form($importer->processor)) { + if (feeds_get_form($importer->processor, 'configForm')) { $actions[] = l(t('Settings'), $path .'/settings/'. $config['processor']['plugin_key']); + $actions[] = l(t('Mapping'), $path .'/mapping/'. $config['processor']['plugin_key']); } - $actions[] = l(t('Mapping'), $path .'/mapping'); $info['title'] = t('Processor'); $info['body'] = array( array( @@ -749,79 +740,3 @@ function theme_feeds_ui_container($conta $output .= '
'; return $output; } - -/** - * Theme function for feeds_ui_mapping_form(). - */ -function theme_feeds_ui_mapping_form($form) { - - // Build the actual mapping table. - $header = array( - t('Source'), - t('Target'), - t('Unique target'), - ' ', - ); - $rows = array(); - if (is_array($form['#mappings'])) { - foreach ($form['#mappings'] as $i => $mapping) { - $rows[] = array( - $mapping['source'], - $mapping['target'], - drupal_render($form['unique_flags'][$i]), - drupal_render($form['remove_flags'][$i]), - ); - } - } - if (!count($rows)) { - $rows[] = array( - array( - 'colspan' => 4, - 'data' => t('No mappings defined.'), - ), - ); - } - $rows[] = array( - drupal_render($form['source']), - drupal_render($form['target']), - '', - drupal_render($form['add']), - ); - $output = '
'; - $output .= theme('table', $header, $rows); - - // Build the help table that explains available sources. - $legend = ''; - $rows = array(); - foreach (element_children($form['legendset']['legend']['sources']) as $k) { - $rows[] = array( - drupal_render($form['legendset']['legend']['sources'][$k]['name']), - drupal_render($form['legendset']['legend']['sources'][$k]['description']), - ); - } - if (count($rows)) { - $legend .= '

'. t('Sources') .'

'; - $legend .= theme('table', array(t('Name'), t('Description')), $rows); - } - - // Build the help table that explains available targets. - $rows = array(); - foreach (element_children($form['legendset']['legend']['targets']) as $k) { - $rows[] = array( - drupal_render($form['legendset']['legend']['targets'][$k]['name']), - drupal_render($form['legendset']['legend']['targets'][$k]['description']), - ); - } - $legend .= '

'. t('Targets') .'

'; - $legend .= theme('table', array(t('Name'), t('Description')), $rows); - - // Stick tables into collapsible fieldset. - $form['legendset']['legend'] = array( - '#value' => '
'. $legend .'
', - ); - - $output .= drupal_render($form['legendset']); - - $output .= drupal_render($form); - return $output; -} Index: includes/FeedsBatch.inc =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/feeds/includes/FeedsBatch.inc,v retrieving revision 1.12 diff -u -p -r1.12 FeedsBatch.inc --- includes/FeedsBatch.inc 20 Jun 2010 01:10:29 -0000 1.12 +++ includes/FeedsBatch.inc 8 Jul 2010 18:41:48 -0000 @@ -180,4 +180,20 @@ class FeedsImportBatch extends FeedsBatc $this->items[] = $item; $this->total = count($this->items); } + + /** + * Get mapping sources after the items has been populated + */ + public function getMappingSources() { + $sources = array(); + if ($this->total > 0) { + foreach ($this->items[0] as $k => $v) { + $sources[$k] = array( + 'title' => $k, + 'description' => '', + ); + } + } + return $sources; + } } Index: includes/FeedsConfigurable.inc =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/feeds/includes/FeedsConfigurable.inc,v retrieving revision 1.12 diff -u -p -r1.12 FeedsConfigurable.inc --- includes/FeedsConfigurable.inc 28 Feb 2010 17:16:25 -0000 1.12 +++ includes/FeedsConfigurable.inc 8 Jul 2010 18:41:48 -0000 @@ -178,31 +178,43 @@ abstract class FeedsConfigurable { */ public function configFormValidate(&$values) { } + + /** + * Submission handler for configForm(). + * + * @param $values + */ + public function configFormSubmit(&$values) { + $this->addConfig($values); + $this->save(); + drupal_set_message(t('Your changes have been saved.')); + feeds_cache_clear(FALSE); + } } /** * Config form wrapper. Use to render the configuration form of * a FeedsConfigurable object. * - * @param + * @param $configurable * FeedsConfigurable object. - * @param - * The parent object to perform the save on. + * @param $form_method + * The form method that should be rendered. * * @return * Rendered config form, if available. Empty string otherwise. */ -function feeds_get_config_form($configurable) { +function feeds_get_form($configurable, $form_method) { $form_state = array(); - if ($configurable->configForm($form_state)) { - return drupal_get_form(get_class($configurable) .'_feeds_config_form', $configurable); + if (method_exists($configurable, $form_method)) { + return drupal_get_form(get_class($configurable) .'_feeds_form', $configurable, $form_method); } return ''; } /** * Config form callback. Don't call directly, but use - * feeds_get_config_form($configurable) instead. + * feeds_get_form($configurable, 'method') instead. * * @param * FormAPI $form_state. @@ -210,12 +222,15 @@ function feeds_get_config_form($configur * FeedsConfigurable object. * @param * The object to perform the save() operation on. + * @param $form_method + * The $form_method that should be rendered. */ -function feeds_config_form(&$form_state, $configurable) { - $form = $configurable->configForm($form_state); +function feeds_form(&$form_state, $configurable, $form_method) { + $form = $configurable->$form_method($form_state); $form['#configurable'] = $configurable; - $form['#validate'] = array('feeds_config_form_validate'); - $form['#submit'] = array('feeds_config_form_submit'); + $form['#feeds_form_method'] = $form_method; + $form['#validate'] = array('feeds_form_validate'); + $form['#submit'] = array('feeds_form_submit'); $form['submit'] = array( '#type' => 'submit', '#value' => t('Save'), @@ -225,18 +240,21 @@ function feeds_config_form(&$form_state, } /** - * Validation handler for feeds_config_form(). + * Validation handler for feeds_form(). */ -function feeds_config_form_validate($form, &$form_state) { - $form['#configurable']->configFormValidate($form_state['values']); +function feeds_form_validate($form, &$form_state) { + $validate_method = $form['#feeds_form_method'] .'Validate'; + if (method_exists($form['#configurable'], $validate_method)) { + $form['#configurable']->$validate_method($form_state['values']); + } } /** - * Submit handler for feeds_config_form(). + * Submit handler for feeds_form(). */ -function feeds_config_form_submit($form, &$form_state) { - $form['#configurable']->addConfig($form_state['values']); - $form['#configurable']->save(); - drupal_set_message(t('Your changes have been saved.')); - feeds_cache_clear(FALSE); +function feeds_form_submit($form, &$form_state) { + $submit_method = $form['#feeds_form_method'] .'Submit'; + if (method_exists($form['#configurable'], $submit_method)) { + $form['#configurable']->$submit_method($form_state['values']); + } } Index: plugins/FeedsDataProcessor.inc =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/feeds/plugins/FeedsDataProcessor.inc,v retrieving revision 1.14 diff -u -p -r1.14 FeedsDataProcessor.inc --- plugins/FeedsDataProcessor.inc 8 Jul 2010 17:19:16 -0000 1.14 +++ plugins/FeedsDataProcessor.inc 8 Jul 2010 18:41:48 -0000 @@ -257,6 +257,7 @@ class FeedsDataProcessor extends FeedsPr 'update_existing' => 0, 'expire' => FEEDS_EXPIRE_NEVER, // Don't expire items by default. 'mappings' => array(), + 'mapping_on_import' => 0, ); } Index: plugins/FeedsFeedNodeProcessor.inc =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/feeds/plugins/FeedsFeedNodeProcessor.inc,v retrieving revision 1.12 diff -u -p -r1.12 FeedsFeedNodeProcessor.inc --- plugins/FeedsFeedNodeProcessor.inc 28 Apr 2010 22:18:30 -0000 1.12 +++ plugins/FeedsFeedNodeProcessor.inc 8 Jul 2010 18:41:48 -0000 @@ -107,6 +107,7 @@ class FeedsFeedNodeProcessor extends Fee 'content_type' => '', 'update_existing' => 0, 'mappings' => array(), + 'mapping_on_import' => 0, ); } Index: plugins/FeedsNodeProcessor.inc =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/feeds/plugins/FeedsNodeProcessor.inc,v retrieving revision 1.40 diff -u -p -r1.40 FeedsNodeProcessor.inc --- plugins/FeedsNodeProcessor.inc 8 Jul 2010 17:39:27 -0000 1.40 +++ plugins/FeedsNodeProcessor.inc 8 Jul 2010 18:41:48 -0000 @@ -151,6 +151,7 @@ class FeedsNodeProcessor extends FeedsPr 'expire' => FEEDS_EXPIRE_NEVER, 'mappings' => array(), 'author' => 0, + 'mapping_on_import' => 0, ); } Index: plugins/FeedsProcessor.inc =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/feeds/plugins/FeedsProcessor.inc,v retrieving revision 1.12 diff -u -p -r1.12 FeedsProcessor.inc --- plugins/FeedsProcessor.inc 8 Jul 2010 17:19:16 -0000 1.12 +++ plugins/FeedsProcessor.inc 8 Jul 2010 18:41:48 -0000 @@ -149,7 +149,10 @@ abstract class FeedsProcessor extends Fe * Declare default configuration. */ public function configDefaults() { - return array('mappings' => array()); + return array( + 'mappings' => array(), + 'mapping_on_import' => 0, + ); } /** @@ -292,4 +295,222 @@ abstract class FeedsProcessor extends Fe } $loaded = TRUE; } + + /** + * Overwrite parent::addConfig() + * This is to handle config submission in mappingForm + */ + public function addConfig($config) { + parent::addConfig($config); + + $mappings = $this->config['mappings']; + // We may set some unique flags to mappings that we remove in the subsequent + // step, that's fine. + if (isset($config['unique_flags'])) { + foreach ($config['unique_flags'] as $k => $v) { + $this->setUnique($mappings[$k]['source'], $mappings[$k]['target'], $v); + } + } + + if (isset($config['remove_flags'])) { + foreach ($config['remove_flags'] as $k => $v) { + if ($v) { + $this->removeMapping($mappings[$k]['source'], $mappings[$k]['target']); + } + } + } + } + + /** + * Render the mapping form. + * This function should NOT be overwritten. + * @param + * The form object. + * @param + * The location from where this function is called. For now, it will be passed either + * 'import' or 'config' + * @param + * The batch object that contains populated items that has been fetched and parsed. + * This will only be handled if the first parameter is NOT 'config' + */ + public function mappingForm($form, $loc_id = 'config', $batch = NULL) { + drupal_add_js(drupal_get_path('module', 'feeds_ui') .'/feeds_ui.js'); + + // Get the FeedsImporter object + $importer = feeds_importer($this->id); + + $form = array(); + if ($loc_id == 'config') { + // Mapping on import checkbox + $form['mapping_on_import'] = array( + '#type' => 'checkbox', + '#title' => t('Define mapping on import'), + '#description' => t('If this is checked, the mapping form here will be disabled and instead user will be asked for the mapping configuration after the first import.'), + '#attributes' => array('class' => 'feeds-ui-trigger-submit'), + '#weight' => -100, + '#default_value' => $importer->processor->config['mapping_on_import'], + ); + } + + if ($loc_id != 'config' || !$importer->processor->config['mapping_on_import']) { + $form['#theme'] = 'feeds_mapping_form'; + $form['help']['#value'] = feeds_mapping_form_help(); + + // Get mapping sources from parsers or batch and targets from processor, format them + // for output. + // Some parsers do not define mapping sources but let them define on the fly. + if ($loc_id == 'config' || empty($batch)) { + $sources = $importer->parser->getMappingSources(); + } + else { + $sources = $batch->getMappingSources(); + } + + if ($sources) { + $source_options = _feeds_mapping_form_format_options($sources); + foreach ($sources as $k => $source) { + $legend['sources'][$k]['name']['#value'] = empty($source['name']) ? $k : $source['name']; + $legend['sources'][$k]['description']['#value'] = empty($source['description']) ? '' : $source['description']; + } + } + else { + $legend['sources']['#value'] = t('This parser supports free source definitions. Enter the name of the source field in lower case into the Source text field above.'); + } + $targets = $importer->processor->getMappingTargets(); + $target_options = _feeds_mapping_form_format_options($targets); + foreach ($targets as $k => $target) { + $legend['targets'][$k]['name']['#value'] = empty($target['name']) ? $k : $target['name']; + $legend['targets'][$k]['description']['#value'] = empty($target['description']) ? '' : $target['description']; + } + + $form['legendset'] = array( + '#type' => 'fieldset', + '#title' => t('Legend'), + '#collapsible' => TRUE, + '#collapsed' => TRUE, + '#tree' => TRUE, + ); + $form['legendset']['legend'] = $legend; + + // Add unique and remove forms to mappings. + $mappings = $importer->processor->getMappings(); + $form['unique_flags'] = $form['remove_flags'] = array( + '#tree' => TRUE, + ); + + if (is_array($mappings)) { + foreach ($mappings as $i => $mapping) { + + $mappings[$i]['source'] = isset($source_options) ? $source_options[$mappings[$i]['source']] : $mappings[$i]['source']; + $mappings[$i]['target'] = $target_options[$mappings[$i]['target']]; + $param = array( + 'processor' => $importer->processor, + 'mapping' => $mapping, + ); + + if (isset($targets[$mapping['target']]['optional_unique']) && $targets[$mapping['target']]['optional_unique'] === TRUE) { + + $form['unique_flags'][$i] = array( + '#type' => 'checkbox', + '#default_value' => !empty($mapping['unique']), + '#attributes' => array('class' => 'feeds-ui-trigger-submit'), + ); + } + $form['remove_flags'][$i] = array( + '#type' => 'checkbox', + '#title' => t('Remove'), + '#prefix' => '', + ); + } + } + + $form['#mappings'] = $mappings; + $form['#targets'] = $targets; + if ($sources) { + $form['source'] = array( + '#type' => 'select', + '#options' => array('' => t('Select a source')) + $source_options, + ); + } + else { + $form['source'] = array( + '#type' => 'textfield', + '#size' => 20, + '#default_value' => t('Name of source field'), + '#attributes' => array('class' => 'hide-text-on-focus'), + ); + } + $form['target'] = array( + '#type' => 'select', + '#options' => array('' => t('Select a target')) + _feeds_mapping_form_format_options($targets), + ); + $form['add'] = array( + '#type' => 'submit', + '#value' => t('Add'), + '#submit' => array('feeds_mapping_form_add_submit'), + ); + } + + $form['save'] = array( + '#type' => 'submit', + '#value' => t('Save'), + '#attributes' => array('class' => 'feeds-ui-hidden-submit'), + ); + + return $form; + } +} + +/** + * Submit handler for add button on feeds_mapping_form(). + */ +function feeds_mapping_form_add_submit($form, &$form_state) { + try { + $form['#configurable']->addMapping($form_state['values']['source'], $form_state['values']['target']); + $form['#configurable']->save(); + drupal_set_message(t('Mapping has been added.')); + } + catch (Exception $e) { + drupal_set_message($e->getMessage(), 'error'); + } +} + +/** + * Walk the result of FeedsParser::getMappingSources() or + * FeedsProcessor::getMappingTargets() and format them into + * a Form API options array. + */ +function _feeds_mapping_form_format_options($options) { + $result = array(); + foreach ($options as $k => $v) { + if (is_array($v) && !empty($v['name'])) { + $result[$k] = $v['name']; + } + elseif (is_array($v)) { + $result[$k] = $k; + } + else { + $result[$k] = $v; + } + } + return $result; +} + +/** + * Help text for mapping. + */ +function feeds_mapping_form_help() { + return + '

' . + t('Define which elements of a single item of a feed') . + '(= ' . t('Sources') . ') ' . + t('map to which content pieces in Drupal') . + ' (= ' . t('Targets') . '). ' . + t('Make sure that at least one definition has a') . + ' ' . t('Unique target') . '. ' . + t('A unique target means that a value for a target can only occur once. E. g. only one item with the URL ') . + 'http://example.com/story/1 ' . + t('can exist.') . + '

'; } Index: plugins/FeedsTermProcessor.inc =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/feeds/plugins/FeedsTermProcessor.inc,v retrieving revision 1.9 diff -u -p -r1.9 FeedsTermProcessor.inc --- plugins/FeedsTermProcessor.inc 28 Apr 2010 22:18:30 -0000 1.9 +++ plugins/FeedsTermProcessor.inc 8 Jul 2010 18:41:48 -0000 @@ -126,6 +126,7 @@ class FeedsTermProcessor extends FeedsPr 'vocabulary' => 0, 'update_existing' => 0, 'mappings' => array(), + 'mapping_on_import' => 0, ); } Index: plugins/FeedsUserProcessor.inc =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/feeds/plugins/FeedsUserProcessor.inc,v retrieving revision 1.12 diff -u -p -r1.12 FeedsUserProcessor.inc --- plugins/FeedsUserProcessor.inc 19 Jun 2010 15:57:13 -0000 1.12 +++ plugins/FeedsUserProcessor.inc 8 Jul 2010 18:41:48 -0000 @@ -117,6 +117,7 @@ class FeedsUserProcessor extends FeedsPr 'update_existing' => FALSE, 'status' => 1, 'mappings' => array(), + 'mapping_on_import' => 0, ); }