diff --git feeds.module feeds.module
index 4ddac1c..377ee81 100644
--- feeds.module
+++ feeds.module
@@ -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,6 +134,16 @@ 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();
}
@@ -154,6 +173,9 @@ function feeds_theme() {
'feeds_upload' => array(
'file' => 'feeds.pages.inc',
),
+ 'feeds_mapping_form' => array(
+ 'file' => 'feeds.pages.inc'
+ ),
);
}
@@ -298,10 +320,21 @@ function feeds_nodeapi(&$node, $op, $form) {
$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);
diff --git feeds.pages.inc feeds.pages.inc
index ae54403..a531479 100644
--- feeds.pages.inc
+++ feeds.pages.inc
@@ -59,6 +59,12 @@ function feeds_import_form(&$form_state, $importer_id) {
'#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($form, &$form_state) {
* 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');
+ }
}
/**
@@ -181,3 +192,147 @@ function theme_feeds_upload($element) {
$output .= '';
return theme('form_element', $element, $output);
}
+
+/**
+ * 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_state, 'import', $batch);
+
+ // Declare the appropriate configurable and forms method for appropriate submit handler
+ $form['#feeds_form_method'] = 'mappingForm';
+ $form['#configurable'] = $source->importer->processor;
+
+ $form['#importer_id'] = $importer_id;
+ $form['#feed_nid'] = $feed_nid;
+
+ $form['import'] = 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;
+}
\ No newline at end of file
diff --git feeds_ui/feeds_ui.admin.inc feeds_ui/feeds_ui.admin.inc
index 15bfd08..6ed4acc 100644
--- feeds_ui/feeds_ui.admin.inc
+++ feeds_ui/feeds_ui.admin.inc
@@ -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) {
@@ -280,7 +269,6 @@ function feeds_ui_export_form(&$form_state, $importer) {
* Edit feed configuration.
*/
function feeds_ui_edit_page($importer, $active = 'help', $plugin_key = '') {
-
// Get plugins and configuration.
$plugins = feeds_get_plugins();
$config = $importer->config;
@@ -314,12 +302,14 @@ function feeds_ui_edit_page($importer, $active = 'help', $plugin_key = '') {
// 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_form($plugin, 'mappingForm');
+ $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;
}
@@ -390,8 +380,8 @@ function feeds_ui_edit_page($importer, $active = 'help', $plugin_key = '') {
$actions = array();
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(
@@ -481,182 +471,6 @@ function theme_feeds_ui_plugin_form($form) {
}
/**
- * Edit mapping.
- *
- * @todo Completely merge this into config form handling. This is just a
- * shared form of configuration, most of the common functionality can live in
- * FeedsProcessor, a flag can tell whether mapping is supported or not.
- */
-function feeds_ui_mapping_form(&$form_state, $importer) {
- drupal_add_js(drupal_get_path('module', 'feeds_ui') .'/feeds_ui.js');
-
- $form = array();
- $form['#importer'] = $importer;
- $form['help']['#value'] = feeds_ui_mapping_help();
-
- // Get mapping sources from parsers and targets from processor, format them
- // for output.
- // Some parsers do not define mapping sources but let them define on the fly.
- if ($sources = $importer->parser->getMappingSources()) {
- $source_options = _feeds_ui_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_ui_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)) {
- $form['mappings']['#tree'] = TRUE;
- foreach ($mappings as $i => $mapping) {
-
- $mappings[$i]['source'] = isset($source_options) ? $source_options[$mappings[$i]['source']] : $mappings[$i]['source'];
- $mappings[$i]['target'] = isset($target_options[$mappings[$i]['target']]) ? $target_options[$mappings[$i]['target']] : $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' => '
',
- '#suffix' => '
',
- );
-
- // Declare the mappings data in the hidden field, so later
- // the full mapping data will be submitted in $form_state['values']['mappings'].
- foreach($mapping as $k => $v) {
- $form['mappings'][$i][$k] = array (
- '#type' => 'hidden',
- '#value' => $v,
- );
- }
- }
- }
-
- $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_ui_format_options($targets),
- );
- $form['add'] = array(
- '#type' => 'submit',
- '#value' => t('Add'),
- '#submit' => array('feeds_ui_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_ui_mapping_form().
- */
-function feeds_ui_mapping_form_add_submit($form, &$form_state) {
- $importer = $form['#importer'];
- try {
- // addMapping method is now used for custom FeedsProcessor
- // to declare what they want to do when mapping is added
- // e.g. FeedsDataProcessor
- if (method_exists($importer->processor, 'addMapping')) {
- $importer->processor->addMapping($form_state['values']['source'], $form_state['values']['target']);
- }
-
- $form_state['values']['mappings'][] = array(
- 'source' => $form_state['values']['source'],
- 'target' => $form_state['values']['target'],
- 'unique' => FALSE,
- );
- $importer->processor->addConfig($form_state['values']);
- $importer->processor->save();
- drupal_set_message(t('Mapping has been added.'));
- }
- catch (Exception $e) {
- drupal_set_message($e->getMessage(), 'error');
- }
-}
-
-/**
- * Submit handler for save button on feeds_ui_mapping_form().
- */
-function feeds_ui_mapping_form_submit($form, &$form_state) {
- $processor = $form['#importer']->processor;
- $mappings = $processor->config['mappings'];
- // We may set some unique flags to mappings that we remove in the subsequent
- // step, that's fine.
- if (isset($form_state['values']['unique_flags'])) {
- foreach ($form_state['values']['unique_flags'] as $k => $v) {
- $form_state['values']['mappings'][$k]['unique'] = $v;
- }
- }
-
- foreach ($form_state['values']['remove_flags'] as $k => $v) {
- if ($v) {
- unset($form_state['values']['mappings'][$k]);
- // Keep or keys clean.
- $form_state['values']['mappings'] = array_values($form_state['values']['mappings']);
- }
- }
- drupal_set_message(t('Your changes have been saved.'));
-
- // Because now full mapping is submitted, so no further validation for
- // out of sync mappings is needed (i.e. the mapping is modified by other people while
- // we are at it). Simply replace it.
- $processor->addConfig($form_state['values']);
- $processor->save();
-}
-
-/**
* Walk the result of FeedsParser::getMappingSources() or
* FeedsProcessor::getMappingTargets() and format them into
* a Form API options array.
@@ -789,80 +603,4 @@ function theme_feeds_ui_container($container) {
$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;
-}
+}
\ No newline at end of file
diff --git feeds_ui/feeds_ui.module feeds_ui/feeds_ui.module
index 6df8623..9a1f90d 100644
--- feeds_ui/feeds_ui.module
+++ feeds_ui/feeds_ui.module
@@ -90,9 +90,6 @@ function feeds_ui_theme() {
'feeds_ui_overview_form' => array(
'file' => 'feeds_ui.admin.inc',
),
- 'feeds_ui_mapping_form' => array(
- 'file' => 'feeds_ui.admin.inc',
- ),
'feeds_ui_edit_page' => array(
'file' => 'feeds_ui.admin.inc',
),
diff --git includes/FeedsBatch.inc includes/FeedsBatch.inc
index a7f9aec..4c872b8 100644
--- includes/FeedsBatch.inc
+++ includes/FeedsBatch.inc
@@ -302,6 +302,22 @@ class FeedsImportBatch extends FeedsBatch {
public function getItemCount() {
return count($this->items);
}
+
+ /**
+ * Get mapping sources after the batch 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;
+ }
}
/**
diff --git plugins/FeedsCSVParser.inc plugins/FeedsCSVParser.inc
index fe82032..fe3aba8 100644
--- plugins/FeedsCSVParser.inc
+++ plugins/FeedsCSVParser.inc
@@ -72,7 +72,7 @@ class FeedsCSVParser extends FeedsParser {
$form = array();
$form['#weight'] = -10;
- $mappings = feeds_importer($this->id)->processor->config['mappings'];
+ $mappings = feeds_importer($this->id)->processor->getMappings();
$sources = $uniques = array();
foreach ($mappings as $mapping) {
$sources[] = $mapping['source'];
diff --git plugins/FeedsDataProcessor.inc plugins/FeedsDataProcessor.inc
index cbdb6af..baedc44 100644
--- plugins/FeedsDataProcessor.inc
+++ plugins/FeedsDataProcessor.inc
@@ -230,6 +230,7 @@ class FeedsDataProcessor extends FeedsProcessor {
'update_existing' => FEEDS_SKIP_EXISTING,
'expire' => FEEDS_EXPIRE_NEVER, // Don't expire items by default.
'mappings' => array(),
+ 'mapping_on_import' => 0,
);
}
diff --git plugins/FeedsDataProcessor.inc.orig plugins/FeedsDataProcessor.inc.orig
deleted file mode 100644
index 88cd283..0000000
--- plugins/FeedsDataProcessor.inc.orig
+++ /dev/null
@@ -1,365 +0,0 @@
-expiryTime();
-
- while ($item = $batch->shiftItem()) {
- $id = $this->existingItemId($batch, $source);
-
- if ($id === FALSE || $this->config['update_existing']) {
- // Map item to a data record, feed_nid and timestamp are mandatory.
- $data = array();
- $data['feed_nid'] = $source->feed_nid;
- $data = $this->map($batch, $data);
- if (!isset($data['timestamp'])) {
- $data['timestamp'] = FEEDS_REQUEST_TIME;
- }
-
- // Only save if this item is not expired.
- if ($expiry_time != FEEDS_EXPIRE_NEVER && $data['timestamp'] < (FEEDS_REQUEST_TIME - $expiry_time)) {
- continue;
- }
-
- // Save data.
- if ($id !== FALSE) {
- $data['id'] = $id;
- $this->handler()->update($data, 'id');
- $updated++;
- }
- else {
- $this->handler()->insert($data);
- $inserted++;
- }
- }
- }
-
- // Set messages.
- if ($inserted) {
- drupal_set_message(format_plural($inserted, 'Created @number item.', 'Created @number items.', array('@number' => $inserted)));
- }
- elseif ($updated) {
- drupal_set_message(format_plural($updated, 'Updated @number item.', 'Updated @number items.', array('@number' => $updated)));
- }
- else {
- drupal_set_message(t('There are no new items.'));
- }
- }
-
- /**
- * Implementation of FeedsProcessor::clear().
- *
- * Delete all data records for feed_nid in this table.
- */
- public function clear(FeedsBatch $batch, FeedsSource $source) {
- $clause = array(
- 'feed_nid' => $source->feed_nid,
- );
- $num = $this->handler()->delete($clause);
- drupal_set_message('All items of this feed have been deleted.');
- }
-
- /**
- * Implement expire().
- */
- public function expire($time = NULL) {
- if ($time === NULL) {
- $time = $this->expiryTime();
- }
- if ($time == FEEDS_EXPIRE_NEVER) {
- return FEEDS_BATCH_COMPLETE;
- }
- $clause = array(
- 'timestamp' => array(
- '<',
- FEEDS_REQUEST_TIME - $time,
- ),
- );
- $num = $this->handler()->delete($clause);
- drupal_set_message(format_plural($num, 'Expired @number record from @table.', 'Expired @number records from @table.', array('@number' => $num, '@table' => $this->tableName())));
- return FEEDS_BATCH_COMPLETE;
- }
-
- /**
- * Return expiry time.
- */
- public function expiryTime() {
- return $this->config['expire'];
- }
-
- /**
- * Override parent::addMapping() and create a new field for new mapping
- * targets.
- *
- * @see getMappingTargets().
- */
- public function addMapping($source, $target, $unique = FALSE) {
- if (empty($source) || empty($target)) {
- return;
- }
-
- // Create a new field with targets that start with "new:"
- @list($new, $type) = explode(':', $target);
-
- if ($new == 'new') {
- // Build a field name from the source key.
- $field_name = data_safe_name($source);
- // Get the full schema spec from data.
- $type = data_get_field_definition($type);
- // Add the field to the table.
- $schema = $this->table()->get('table_schema');
- if (!isset($schema['fields'][$field_name])) {
- $target = $this->table()->addField($field_name, $type);
- // Let the user know.
- drupal_set_message(t('Created new field "!name".', array('!name' => $field_name)));
- }
- else {
- throw new Exception(t('Field !field_name already exists as a mapping target. Remove it from mapping if you would like to map another source to it. Remove it from !data_table table if you would like to change its definition.', array('!field_name' => $field_name, '!data_table' => l($this->table()->get('name'), 'admin/content/data'))));
- }
- }
-
- // Let parent populate the mapping configuration.
- parent::addMapping($source, $target, $unique);
- }
-
- /**
- * Return available mapping targets.
- */
- public function getMappingTargets() {
- $schema = $this->table()->get('table_schema');
- $meta = $this->table()->get('meta');
-
- // Collect all existing fields except id and field_nid and offer them as
- // mapping targets.
- $existing_fields = $new_fields = array();
- if (isset($schema['fields'])) {
- foreach ($schema['fields'] as $field_name => $field) {
- if (!in_array($field_name, array('id', 'feed_nid'))) {
- // Any existing field can be optionally unique.
- // @todo Push this reverse mapping of spec to short name into data
- // module.
- $type = $field['type'];
- if ($type == 'int' && $field['unsigned']) {
- $type = 'unsigned int';
- }
- $existing_fields[$field_name] = array(
- 'name' => empty($meta['fields'][$field_name]['label']) ? $field_name : $meta['fields'][$field_name]['label'],
- 'description' => t('Field of type !type.', array('!type' => $type)),
- 'optional_unique' => TRUE,
- );
- }
- }
- }
-
- // Do the same for every joined table.
- foreach ($this->handler()->joined_tables as $table) {
- $schema = data_get_table($table)->get('table_schema');
- if (isset($schema['fields'])) {
- foreach ($schema['fields'] as $field_name => $field) {
- if (!in_array($field_name, array('id', 'feed_nid'))) {
- // Fields in joined tables can't be unique.
- $type = $field['type'];
- if ($type == 'int' && $field['unsigned']) {
- $type = 'unsigned int';
- }
- $existing_fields["$table.$field_name"] = array(
- 'name' => $table .'.'. (empty($meta['fields'][$field_name]['label']) ? $field_name : $meta['fields'][$field_name]['label']),
- 'description' => t('Joined field of type !type.', array('!type' => $type)),
- 'optional_unique' => FALSE,
- );
- }
- }
- }
- }
-
- // Now add data field types as mapping targets.
- $field_types = drupal_map_assoc(array_keys(data_get_field_definitions()));
- foreach ($field_types as $k => $v) {
- $new_fields['new:'. $k] = array(
- 'name' => t('[new] !type', array('!type' => $v)),
- 'description' => t('Creates a new column of type !type.', array('!type' => $v)),
- );
- }
- $fields = $new_fields + $existing_fields;
- drupal_alter('feeds_data_processor_targets', $fields, $this->table()->get('name'));
- return $fields;
- }
-
- /**
- * Set target element, bring element in a FeedsDataHandler format.
- */
- public function setTargetElement(&$target_item, $target_element, $value) {
- if (empty($value)) {
- return;
- }
- if (strpos($target_element, '.')) {
- /**
- Add field in FeedsDataHandler format.
-
- This is the tricky part, FeedsDataHandler expects an *array* of records
- at #[joined_table_name]. We need to iterate over the $value that has
- been mapped to this element and create a record array from each of
- them.
- */
- list($table, $field) = explode('.', $target_element);
-
- $values = array();
- $value = is_array($value) ? $value : array($value);
- foreach ($value as $v) {
- // Create a record array.
- $values[] = array(
- $field => $v,
- );
- }
- if (is_array($target_item["#$table"])) {
- $target_item["#$table"] = array_merge($target_item["#$table"], $values);
- }
- else {
- $target_item["#$table"] = $values;
- }
- }
- else {
- if (is_array($target_item[$target_element]) && is_array($value)) {
- $target_item[$target_element] = array_merge($target_item[$target_element], $value);
- }
- else {
- $target_item[$target_element] = $value;
- }
- }
- }
-
- /**
- * Iterate through unique targets and try to load existing records.
- * Return id for the first match.
- */
- protected function existingItemId(FeedsImportBatch $batch, FeedsSource $source) {
- foreach ($this->uniqueTargets($batch) as $target => $value) {
- if ($records = $this->handler()->load(array('feed_nid' => $source->feed_nid, $target => $value))) {
- return $records[0]['id'];
- }
- }
- return FALSE;
- }
-
- /**
- * Override parent::configDefaults().
- */
- public function configDefaults() {
- return array(
- 'update_existing' => FEEDS_SKIP_EXISTING,
- 'expire' => FEEDS_EXPIRE_NEVER, // Don't expire items by default.
- 'mappings' => array(),
- );
- }
-
- /**
- * Override parent::configForm().
- */
- public function configForm(&$form_state) {
- $period = drupal_map_assoc(array(FEEDS_EXPIRE_NEVER, 3600, 10800, 21600, 43200, 86400, 259200, 604800, 604800 * 4, 604800 * 12, 604800 * 24, 31536000), 'feeds_format_expire');
- $form['expire'] = array(
- '#type' => 'select',
- '#title' => t('Expire items'),
- '#options' => $period,
- '#description' => t('Select after how much time data records should be deleted. The timestamp target value will be used for determining the item\'s age, see Mapping settings.'),
- '#default_value' => $this->config['expire'],
- );
- $form['update_existing'] = array(
- '#type' => 'checkbox',
- '#title' => t('Replace existing records'),
- '#description' => t('If an existing record is found for an imported record, replace it. Existing records will be determined using mappings that are a "unique target".'),
- '#default_value' => $this->config['update_existing'],
- );
- return $form;
- }
-
- /**
- * Return the data table name for this feed.
- */
- protected function tableName() {
- return variable_get('feeds_data_'. $this->id, 'feeds_data_'. $this->id);
- }
-
- /**
- * Return the data table for this feed.
- *
- * @throws Exception $e
- * Throws this exception if a table cannot be found and cannot be created.
- *
- * @todo Make *Data module* throw exception when table can't be found or
- * can't be created.
- */
- protected function table() {
- if ($table = data_get_table($this->tableName())) {
- return $table;
- }
- else {
- if ($table = data_create_table($this->tableName(), $this->baseSchema(), feeds_importer($this->id)->config['name'])) {
- return $table;
- }
- }
- throw new Exception(t('Could not create data table.'));
- }
-
- /**
- * Return a data handler for this table.
- *
- * Avoids a call to table() to not unnecessarily instantiate DataTable.
- */
- protected function handler() {
- data_include('DataHandler');
- feeds_include('FeedsDataHandler');
- return FeedsDataHandler::instance($this->tableName(), 'id');
- }
-
- /**
- * Every Feeds data table must have these elements.
- */
- protected function baseSchema() {
- return array(
- 'fields' => array(
- 'feed_nid' => array(
- 'type' => 'int',
- 'unsigned' => TRUE,
- 'not null' => TRUE,
- ),
- 'id' => array(
- 'type' => 'serial',
- 'size' => 'normal',
- 'unsigned' => TRUE,
- 'not null' => TRUE,
- ),
- 'timestamp' => array(
- 'description' => 'The Unix timestamp for the data.',
- 'type' => 'int',
- 'unsigned' => TRUE,
- 'not null' => FALSE,
- ),
- ),
- 'indexes' => array(
- 'feed_nid' => array('feed_nid'),
- 'id' => array('id'),
- 'timestamp' => array('timestamp'),
- ),
- 'primary key' => array(
- '0' => 'id',
- ),
- );
- }
-}
diff --git plugins/FeedsFeedNodeProcessor.inc plugins/FeedsFeedNodeProcessor.inc
index 06430dd..1152b46 100644
--- plugins/FeedsFeedNodeProcessor.inc
+++ plugins/FeedsFeedNodeProcessor.inc
@@ -105,6 +105,7 @@ class FeedsFeedNodeProcessor extends FeedsProcessor {
'content_type' => '',
'update_existing' => 0,
'mappings' => array(),
+ 'mapping_on_import' => 0,
);
}
diff --git plugins/FeedsNodeProcessor.inc plugins/FeedsNodeProcessor.inc
index 5b4e13f..881e784 100644
--- plugins/FeedsNodeProcessor.inc
+++ plugins/FeedsNodeProcessor.inc
@@ -150,6 +150,7 @@ class FeedsNodeProcessor extends FeedsProcessor {
'expire' => FEEDS_EXPIRE_NEVER,
'mappings' => array(),
'author' => 0,
+ 'mapping_on_import' => 0,
);
}
@@ -403,7 +404,6 @@ class FeedsNodeProcessor extends FeedsProcessor {
* Used for batch deletion.
*/
function _feeds_node_delete($nid) {
-
$node = node_load($nid);
db_query("DELETE FROM {node} WHERE nid = %d", $node->nid);
diff --git plugins/FeedsProcessor.inc plugins/FeedsProcessor.inc
index 26d17da..24b29fd 100644
--- plugins/FeedsProcessor.inc
+++ plugins/FeedsProcessor.inc
@@ -105,7 +105,10 @@ abstract class FeedsProcessor extends FeedsPlugin {
$target_item = (object)$target_item;
$convert_to_array = TRUE;
}
- foreach ($this->config['mappings'] as $mapping) {
+
+ $mappings = $this->getMappings();
+
+ foreach ($mappings as $mapping) {
if (isset($targets[$mapping['target']]['real_target'])) {
unset($target_item->{$targets[$mapping['target']]['real_target']});
}
@@ -165,14 +168,27 @@ abstract class FeedsProcessor extends FeedsPlugin {
* Declare default configuration.
*/
public function configDefaults() {
- return array('mappings' => array());
+ return array('mappings' => array(),
+ 'mapping_on_import' => 0,
+ );
}
/**
* Get mappings.
+ *
+ * Mappings must not be got directly by using $this->config['mappings'] but instead via
+ * this function.
*/
public function getMappings() {
- return isset($this->config['mappings']) ? $this->config['mappings'] : array();
+ // If the source is not empty, use the source instead.
+ if (isset($this->source)) {
+ $config = $this->source->getConfigFor($this);
+ $mappings = isset($config['mappings']) ? $config['mappings'] : $this->config['mappings'];
+ }
+ else {
+ $mappings = $this->config['mappings'];
+ }
+ return $mappings;
}
/**
@@ -226,7 +242,7 @@ abstract class FeedsProcessor extends FeedsPlugin {
protected function uniqueTargets(FeedsImportBatch $batch) {
$parser = feeds_importer($this->id)->parser;
$targets = array();
- foreach ($this->config['mappings'] as $mapping) {
+ foreach ($this->getMappings() as $mapping) {
if ($mapping['unique']) {
// Invoke the parser's getSourceElement to retrieve the value for this
// mapping's source.
@@ -235,4 +251,262 @@ abstract class FeedsProcessor extends FeedsPlugin {
}
return $targets;
}
+
+ /**
+ * configDefaults for FeedsSource
+ */
+ function sourceDefaults() {
+ return array ('mappings' => $this->config['mappings']);
+ }
+
+ /**
+ * FeedsProcessor has source config
+ * default: mappings
+ */
+ function hasSourceConfig() {
+ return TRUE;
+ }
+
+ /**
+ * Render the mapping form.
+ * This function should NOT be overwritten.
+ * @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_state, $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 only act as a default mapping. User can further specify the preferred mapping in the import page.'),
+ '#weight' => -100,
+ '#default_value' => $this->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;
+
+ $mappings = $this->getMappings();
+
+ // Add unique and remove forms to mappings.
+ $form['unique_flags'] = $form['remove_flags'] = array(
+ '#tree' => TRUE,
+ );
+
+ if (is_array($mappings)) {
+ $form['mappings']['#tree'] = TRUE;
+
+ 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' => '
',
+ '#suffix' => '
',
+ );
+
+ // Declare the mappings data in the hidden field, so later
+ // the full mapping data will be submitted.
+ foreach($mapping as $k => $v) {
+ $form['mappings'][$i][$k] = array (
+ '#type' => 'hidden',
+ '#value' => $v,
+ );
+ }
+ }
+
+ $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_form_submit'),
+ );
+ }
+
+ $form['save'] = array(
+ '#type' => 'submit',
+ '#value' => t('Save'),
+ '#attributes' => array('class' => 'feeds-ui-hidden-submit'),
+ '#submit' => array('feeds_form_submit'),
+ );
+ return $form;
+ }
+
+ /**
+ * Submit handler for FeedsProcessor::mappingForm()
+ */
+ function mappingFormSubmit(&$values) {
+ // If add new mappings submit is invoked.
+ if ($values['op'] == 'Add') {
+ if (!empty($values['source']) && !empty($values['target'])) {
+ if (method_exists($this, 'addMapping')) {
+ $this->addMapping($values['source'], $values['target']);
+ }
+ $values['mappings'][] = array(
+ 'source' => $values['source'],
+ 'target' => $values['target'],
+ 'unique' => FALSE,
+ );
+ }
+ }
+ // If other submit is invoked.
+ else {
+ // We may set some unique flags to mappings that we remove in the subsequent
+ // step, that's fine.
+ if (isset($values['unique_flags'])) {
+ foreach ($values['unique_flags'] as $k => $v) {
+ $values['mappings'][$k]['unique'] = $v;
+ }
+ }
+
+ if (isset($values['remove_flags'])) {
+ foreach ($values['remove_flags'] as $k => $v) {
+ if ($v) {
+ unset($values['mappings'][$k]);
+ // Keep or keys clean.
+ $values['mappings'] = array_values($values['mappings']);
+ }
+ }
+ }
+ }
+
+ if ($this->config['mapping_on_import'] && !empty($this->source)) {
+ $source_values[get_class($this)] = $values;
+ $this->source->addConfig($source_values);
+ $this->source->save();
+ }
+ else {
+ $this->addConfig($values);
+ $this->save();
+ }
+
+ drupal_set_message(t('Your changes have been saved.'));
+ feeds_cache_clear(FALSE);
+ }
+
+ /**
+ * Validation handler for mappingForm()
+ */
+ function mappingFormValidate(&$values) {
+ }
+}
+
+/**
+ * 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.') .
+ '
';
+}
\ No newline at end of file
diff --git plugins/FeedsProcessor.inc.orig plugins/FeedsProcessor.inc.orig
deleted file mode 100644
index 77072ef..0000000
--- plugins/FeedsProcessor.inc.orig
+++ /dev/null
@@ -1,286 +0,0 @@
-feed_nid. It is the
- * processor's responsibility to store the feed_nid of an imported item in
- * the processing stage.
- */
- public abstract function clear(FeedsBatch $batch, FeedsSource $source);
-
- /**
- * Delete feed items younger than now - $time. Do not invoke expire on a
- * processor directly, but use FeedsImporter::expire() instead.
- *
- * @see FeedsImporter::expire().
- * @see FeedsDataProcessor::expire().
- *
- * @param $time
- * If implemented, all items produced by this configuration that are older
- * than FEEDS_REQUEST_TIME - $time should be deleted.
- * If $time === NULL processor should use internal configuration.
- *
- * @return
- * FEEDS_BATCH_COMPLETE if all items have been processed, a float between 0
- * and 0.99* indicating progress otherwise.
- */
- public function expire($time = NULL) {
- return FEEDS_BATCH_COMPLETE;
- }
-
- /**
- * Execute mapping on an item.
- *
- * This method encapsulates the central mapping functionality. When an item is
- * processed, it is passed through map() where the properties of $source_item
- * are mapped onto $target_item following the processor's mapping
- * configuration.
- *
- * For each mapping FeedsParser::getSourceElement() is executed to retrieve
- * the source element, then FeedsProcessor::setTargetElement() is invoked
- * to populate the target item properly. Alternatively a
- * hook_x_targets_alter() may have specified a callback for a mapping target
- * in which case the callback is asked to populate the target item instead of
- * FeedsProcessor::setTargetElement().
- *
- * @ingroup mappingapi
- *
- * @see hook_feeds_parser_sources_alter()
- * @see hook_feeds_data_processor_targets_alter()
- * @see hook_feeds_node_processor_targets_alter()
- * @see hook_feeds_term_processor_targets_alter()
- * @see hook_feeds_user_processor_targets_alter()
- */
- protected function map(FeedsImportBatch $batch, $target_item = NULL) {
-
- // Static cache $targets as getMappingTargets() may be an expensive method.
- static $sources;
- if (!isset($sources[$this->id])) {
- $sources[$this->id] = feeds_importer($this->id)->parser->getMappingSources();
- }
- static $targets;
- if (!isset($targets[$this->id])) {
- $targets[$this->id] = $this->getMappingTargets();
- }
- $parser = feeds_importer($this->id)->parser;
- if (empty($target_item)) {
- $target_item = array();
- }
-
- // Many mappers add to existing fields rather than replacing them. Hence we
- // need to clear target elements of each item before mapping in case we are
- // mapping on a prepopulated item such as an existing node.
- if (is_array($target_item)) {
- $target_item = (object)$target_item;
- $convert_to_array = TRUE;
- }
- foreach ($this->config['mappings'] as $mapping) {
- if (isset($targets[$mapping['target']]['real_target'])) {
- unset($target_item->{$targets[$mapping['target']]['real_target']});
- }
- elseif (isset($target_item->{$mapping['target']})) {
- unset($target_item->{$mapping['target']});
- }
- }
- if ($convert_to_array) {
- $target_item = (array)$target_item;
- }
-
- /*
- This is where the actual mapping happens: For every mapping we envoke
- the parser's getSourceElement() method to retrieve the value of the source
- element and pass it to the processor's setTargetElement() to stick it
- on the right place of the target item.
-
- If the mapping specifies a callback method, use the callback instead of
- setTargetElement().
- */
- self::loadMappers();
- foreach ($this->config['mappings'] as $mapping) {
- // Retrieve source element's value from parser.
- if (is_array($sources[$this->id][$mapping['source']]) &&
- isset($sources[$this->id][$mapping['source']]['callback']) &&
- function_exists($sources[$this->id][$mapping['source']]['callback'])) {
- $callback = $sources[$this->id][$mapping['source']]['callback'];
- $value = $callback($batch, $mapping['source']);
- }
- else {
- $value = $parser->getSourceElement($batch, $mapping['source']);
- }
-
- // Map the source element's value to the target.
- if (is_array($targets[$this->id][$mapping['target']]) &&
- isset($targets[$this->id][$mapping['target']]['callback']) &&
- function_exists($targets[$this->id][$mapping['target']]['callback'])) {
- $callback = $targets[$this->id][$mapping['target']]['callback'];
- $callback($target_item, $mapping['target'], $value);
- }
- else {
- $this->setTargetElement($target_item, $mapping['target'], $value);
- }
- }
- return $target_item;
- }
-
- /**
- * Per default, don't support expiry. If processor supports expiry of imported
- * items, return the time after which items should be removed.
- */
- public function expiryTime() {
- return FEEDS_EXPIRE_NEVER;
- }
-
- /**
- * Declare default configuration.
- */
- public function configDefaults() {
- return array('mappings' => array());
- }
-
- /**
- * Add a mapping to existing mappings.
- *
- * @param $source
- * A string that identifies a source element.
- * @param $target
- * A string that identifies a target element.
- * @param $unique
- * A boolean that defines whether the target value should be unique. If
- * TRUE only one item with a given target value can exist on the local
- * system. Compare with existingItemId() and uniqueTargets().
- */
- public function addMapping($source, $target, $unique = FALSE) {
- if (!empty($source) && !empty($target)) {
- $this->config['mappings'][] = array(
- 'source' => $source,
- 'target' => $target,
- 'unique' => $unique,
- );
- }
- }
-
- /**
- * Set unique state of a mapping target.
- */
- public function setUnique($source, $target, $unique) {
- if (!empty($source) && !empty($target)) {
- foreach ($this->config['mappings'] as $k => $mapping) {
- if ($mapping['source'] == $source && $mapping['target'] == $target) {
- $this->config['mappings'][$k]['unique'] = $unique;
- }
- }
- }
- }
-
- /**
- * Remove a mapping.
- */
- public function removeMapping($source, $target) {
- foreach ($this->config['mappings'] as $k => $mapping) {
- if ($mapping['source'] == $source && $mapping['target'] == $target) {
- unset($this->config['mappings'][$k]);
- }
- }
- // Keep or keys clean.
- $this->config['mappings'] = array_values($this->config['mappings']);
- }
-
- /**
- * Get mappings.
- */
- public function getMappings() {
- return isset($this->config['mappings']) ? $this->config['mappings'] : array();
- }
-
- /**
- * Declare possible mapping targets that this processor exposes.
- *
- * @ingroup mappingapi
- *
- * @return
- * An array of mapping targets. Keys are paths to targets
- * separated by ->, values are TRUE if target can be unique,
- * FALSE otherwise.
- */
- public function getMappingTargets() {
- return array();
- }
-
- /**
- * Set a concrete target element. Invoked from FeedsProcessor::map().
- *
- * @ingroup mappingapi
- */
- public function setTargetElement(&$target_item, $target_element, $value) {
- $target_item[$target_element] = $value;
- }
-
- /**
- * Retrieve the target item's existing id if available. Otherwise return 0.
- *
- * @ingroup mappingapi
- *
- * @param $batch
- * A FeedsImportBatch object.
- * @param FeedsSource $source
- * The source information about this import.
- */
- protected function existingItemId(FeedsImportBatch $batch, FeedsSource $source) {
- return 0;
- }
-
- /**
- * Utility function that iterates over a target array and retrieves all
- * sources that are unique.
- *
- * @param $batch
- * A FeedsImportBatch.
- *
- * @return
- * An array where the keys are target field names and the values are the
- * elements from the source item mapped to these targets.
- */
- protected function uniqueTargets(FeedsImportBatch $batch) {
- $parser = feeds_importer($this->id)->parser;
- $targets = array();
- foreach ($this->config['mappings'] as $mapping) {
- if ($mapping['unique']) {
- // Invoke the parser's getSourceElement to retrieve the value for this
- // mapping's source.
- $targets[$mapping['target']] = $parser->getSourceElement($batch, $mapping['source']);
- }
- }
- return $targets;
- }
-}
diff --git plugins/FeedsTermProcessor.inc plugins/FeedsTermProcessor.inc
index af50d6f..c5ab5ff 100644
--- plugins/FeedsTermProcessor.inc
+++ plugins/FeedsTermProcessor.inc
@@ -131,6 +131,7 @@ class FeedsTermProcessor extends FeedsProcessor {
'vocabulary' => 0,
'update_existing' => FEEDS_SKIP_EXISTING,
'mappings' => array(),
+ 'mapping_on_import' => 0,
);
}
diff --git plugins/FeedsUserProcessor.inc plugins/FeedsUserProcessor.inc
index b320916..99ff850 100644
--- plugins/FeedsUserProcessor.inc
+++ plugins/FeedsUserProcessor.inc
@@ -114,6 +114,7 @@ class FeedsUserProcessor extends FeedsProcessor {
'update_existing' => FALSE,
'status' => 1,
'mappings' => array(),
+ 'mapping_on_import' => 0,
);
}
diff --git tests/feeds.test.inc tests/feeds.test.inc
index 96c470c..552e219 100644
--- tests/feeds.test.inc
+++ tests/feeds.test.inc
@@ -57,7 +57,7 @@ class FeedsWebTestCase extends DrupalWebTestCase {
-
+
@@ -299,7 +299,6 @@ class FeedsWebTestCase extends DrupalWebTestCase {
$unique = !empty($mapping['unique']);
unset($mapping['unique']);
$this->drupalPost($path, $mapping, t('Add'));
-
// If unique was set, set the last mapping's unique flag.
if ($unique) {
$edit = array(