From 453dddfa5d8b2bc8c5961466490aa385f57655b2 Mon Sep 17 00:00:00 2001
From: mikran <mikran@1004738.no-reply.drupal.org>
Date: Sun, 1 Nov 2015 11:04:44 +0100
Subject: [PATCH] Issue #1950182 by mikran, MegaChriz, twistor: Only update
 when mapped fields are updated

---
 plugins/FeedsCSVParser.inc      |  7 +++++++
 plugins/FeedsParser.inc         | 15 +++++++++++++++
 plugins/FeedsProcessor.inc      |  9 +++++----
 tests/feeds/users_updated.csv   |  6 ++++++
 tests/feeds_processor_node.test | 33 +++++++++++++++++++++++++++++++++
 5 files changed, 66 insertions(+), 4 deletions(-)
 create mode 100644 tests/feeds/users_updated.csv

diff --git a/plugins/FeedsCSVParser.inc b/plugins/FeedsCSVParser.inc
index 1c078f0e..8fa11b00 100644
--- a/plugins/FeedsCSVParser.inc
+++ b/plugins/FeedsCSVParser.inc
@@ -101,6 +101,13 @@ class FeedsCSVParser extends FeedsParser {
     return parent::getSourceElement($source, $result, drupal_strtolower($element_key));
   }
 
+  /**
+   * Override parent::getMappingSourceList() to use only lower keys.
+   */
+  public function getMappingSourceList() {
+    return array_map('drupal_strtolower', parent::getMappingSourceList());
+  }
+
   /**
    * Define defaults.
    */
diff --git a/plugins/FeedsParser.inc b/plugins/FeedsParser.inc
index 1e1d3290..ad248ee2 100644
--- a/plugins/FeedsParser.inc
+++ b/plugins/FeedsParser.inc
@@ -119,6 +119,21 @@ abstract class FeedsParser extends FeedsPlugin {
     return $sources;
   }
 
+  /**
+   * Get list of mapped sources.
+   *
+   * @return array
+   *   List of mapped source names in an array.
+   */
+  public function getMappingSourceList() {
+    $mappings = feeds_importer($this->id)->processor->config['mappings'];
+    $sources = array();
+    foreach ($mappings as $mapping) {
+      $sources[] = $mapping['source'];
+    }
+    return $sources;
+  }
+
   /**
    * Get an element identified by $element_key of the given item.
    * The element key corresponds to the values in the array returned by
diff --git a/plugins/FeedsProcessor.inc b/plugins/FeedsProcessor.inc
index 4a84c089..385ee0a7 100644
--- a/plugins/FeedsProcessor.inc
+++ b/plugins/FeedsProcessor.inc
@@ -1052,12 +1052,13 @@ abstract class FeedsProcessor extends FeedsPlugin {
    * Include mappings as a change in mappings may have an affect on the item
    * produced.
    *
-   * @return Always returns a hash, even with empty, NULL, FALSE:
-   *  Empty arrays return 40cd750bba9870f18aada2478b24840a
-   *  Empty/NULL/FALSE strings return d41d8cd98f00b204e9800998ecf8427e
+   * @return string
+   *   A hash is always returned, even when the item is empty, NULL or FALSE.
    */
   protected function hash($item) {
-    return hash('md5', serialize($item) . serialize($this->config['mappings']));
+    $sources = feeds_importer($this->id)->parser->getMappingSourceList();
+    $mapped_item = array_intersect_key($item, array_flip($sources));
+    return hash('md5', serialize($mapped_item) . serialize($this->config['mappings']));
   }
 
   /**
diff --git a/tests/feeds/users_updated.csv b/tests/feeds/users_updated.csv
new file mode 100644
index 00000000..fb407b01
--- /dev/null
+++ b/tests/feeds/users_updated.csv
@@ -0,0 +1,6 @@
+name,mail,since,password
+Morticia,morticia@example.com,1363959643,mort
+Fester,fester@example.com,1363959643,fest
+Gomez,gomez@example.com,1363959643,gome
+Wednesday,wednesdayexample.com,1363959643,wedn
+Pugsley,pugsley@example,1363959643,pugs
diff --git a/tests/feeds_processor_node.test b/tests/feeds_processor_node.test
index c5cbd056..c72cff29 100644
--- a/tests/feeds_processor_node.test
+++ b/tests/feeds_processor_node.test
@@ -668,4 +668,37 @@ class FeedsRSStoNodesTest extends FeedsWebTestCase {
     $this->assertEqual(10, db_query("SELECT COUNT(*) FROM {node}")->fetchField());
   }
 
+  /**
+   * Tests if target item is not updated when only non-mapped data on the source changed.
+   */
+  public function testIrrelevantUpdate() {
+    // Include FeedsProcessor.inc so processor related constants are available.
+    module_load_include('inc', 'feeds', 'plugins/FeedsProcessor');
+
+    // Attach to standalone importer and configure.
+    $this->setSettings('syndication', NULL, array('content_type' => ''));
+    $this->setPlugin('syndication', 'FeedsFileFetcher');
+    $this->setPlugin('syndication', 'FeedsCSVParser');
+    $this->removeMappings('syndication', $this->getCurrentMappings('syndication'));
+    $this->addMappings('syndication', array(
+      0 => array(
+        'source' => 'name',
+        'target' => 'title',
+        'unique' => TRUE,
+      ),
+    ));
+
+    // Import file.
+    $this->importFile('syndication', $this->absolutePath() . '/tests/feeds/users.csv');
+    $this->assertText('Created 5 nodes');
+
+    // Ensure that no nodes are updated when only non-mapped columns changed.
+    $this->setSettings('syndication', 'FeedsNodeProcessor', array(
+      'skip_hash_check' => FALSE,
+      'update_existing' => FEEDS_UPDATE_EXISTING,
+    ));
+    $this->importFile('syndication', $this->absolutePath() . '/tests/feeds/users_updated.csv');
+    $this->assertText('There are no new nodes.');
+  }
+
 }
-- 
GitLab