[REF] clean up merge array.
authoreileen <emcnaughton@wikimedia.org>
Wed, 27 Nov 2019 06:56:55 +0000 (19:56 +1300)
committereileen <emcnaughton@wikimedia.org>
Wed, 27 Nov 2019 08:27:30 +0000 (21:27 +1300)
This code has been doing my head in because it is just like 'construct complex array & then another
complex array & iterate them together in nasty ways.

However, after another round of misery I'm pretty sure that this cleanup works. Basically the whole removed
section of code amounts to 'the array built in the first pass takes precedence over the one in the
second pass'. By using a property & only setting the array values when not-yet-set we can
allow the second pass to not clobber the first while populating it rather than as follow up wrangling

CRM/Export/BAO/ExportProcessor.php

index 5fda71b013b9d24b3cb81c0eb1a731ba2e500a4e..2cb0f6a7b61abd9f87c5b06a70b75b854928d35c 100644 (file)
@@ -206,6 +206,13 @@ class CRM_Export_BAO_ExportProcessor {
    */
   protected $exportedHouseholds = [];
 
+  /**
+   * Contacts to be merged by virtue of their shared address.
+   *
+   * @var array
+   */
+  protected $contactsToMerge = [];
+
   /**
    * Households to skip during export as they will be exported via their relationships anyway.
    *
@@ -1919,14 +1926,12 @@ class CRM_Export_BAO_ExportProcessor {
   /**
    * Build array for merging same addresses.
    *
-   * @param $sql
+   * @param string $sql
    * @param bool $sharedAddress
-   *
-   * @return array
    */
   public function buildMasterCopyArray($sql, $sharedAddress = FALSE) {
 
-    $merge = $parents = [];
+    $parents = [];
     $dao = CRM_Core_DAO::executeQuery($sql);
 
     while ($dao->fetch()) {
@@ -1936,7 +1941,7 @@ class CRM_Export_BAO_ExportProcessor {
       $this->cacheContactGreetings((int) $dao->master_contact_id);
       $this->cacheContactGreetings((int) $dao->copy_contact_id);
 
-      if (!isset($merge[$masterID])) {
+      if (!isset($this->contactsToMerge[$masterID])) {
         // check if this is an intermediate child
         // this happens if there are 3 or more matches a,b, c
         // the above query will return a, b / a, c / b, c
@@ -1946,33 +1951,34 @@ class CRM_Export_BAO_ExportProcessor {
           $masterID = $parents[$masterID];
         }
         else {
-          $merge[$masterID] = [
+          $this->contactsToMerge[$masterID] = [
             'addressee' => $this->getContactGreeting((int) $dao->master_contact_id, 'addressee', $dao->master_addressee),
             'copy' => [],
             'postalGreeting' => $this->getContactGreeting((int) $dao->master_contact_id, 'postal_greeting', $dao->master_postal_greeting),
           ];
-          $merge[$masterID]['emailGreeting'] = &$merge[$masterID]['postalGreeting'];
+          $this->contactsToMerge[$masterID]['emailGreeting'] = &$this->contactsToMerge[$masterID]['postalGreeting'];
         }
       }
       $parents[$copyID] = $masterID;
 
-      if (!$sharedAddress && !array_key_exists($copyID, $merge[$masterID]['copy'])) {
+      if (!$sharedAddress && !array_key_exists($copyID, $this->contactsToMerge[$masterID]['copy'])) {
         $copyPostalGreeting = $this->getContactPortionOfGreeting((int) $dao->copy_contact_id, (int) $dao->copy_postal_greeting_id, 'postal_greeting', $dao->copy_postal_greeting);
         if ($copyPostalGreeting) {
-          $merge[$masterID]['postalGreeting'] = "{$merge[$masterID]['postalGreeting']}, {$copyPostalGreeting}";
+          $this->contactsToMerge[$masterID]['postalGreeting'] = "{$this->contactsToMerge[$masterID]['postalGreeting']}, {$copyPostalGreeting}";
           // if there happens to be a duplicate, remove it
-          $merge[$masterID]['postalGreeting'] = str_replace(" {$copyPostalGreeting},", "", $merge[$masterID]['postalGreeting']);
+          $this->contactsToMerge[$masterID]['postalGreeting'] = str_replace(" {$copyPostalGreeting},", "", $this->contactsToMerge[$masterID]['postalGreeting']);
         }
 
         $copyAddressee = $this->getContactPortionOfGreeting((int) $dao->copy_contact_id, (int) $dao->copy_addressee_id, 'addressee', $dao->copy_addressee);
         if ($copyAddressee) {
-          $merge[$masterID]['addressee'] = "{$merge[$masterID]['addressee']}, " . trim($copyAddressee);
+          $this->contactsToMerge[$masterID]['addressee'] = "{$this->contactsToMerge[$masterID]['addressee']}, " . trim($copyAddressee);
         }
       }
-      $merge[$masterID]['copy'][$copyID] = $copyAddressee ?? $dao->copy_addressee;
+      if (!isset($this->contactsToMerge[$masterID]['copy'][$copyID])) {
+        // If it was set in the first run through - share routine, don't subsequently clobber.
+        $this->contactsToMerge[$masterID]['copy'][$copyID] = $copyAddressee ?? $dao->copy_addressee;
+      }
     }
-
-    return $merge;
   }
 
   /**
@@ -2000,7 +2006,7 @@ FROM      $tableName r1
 INNER JOIN civicrm_address adr ON r1.master_id   = adr.id
 INNER JOIN $tableName      r2  ON adr.contact_id = r2.civicrm_primary_id
 ORDER BY  r1.id";
-    $linkedMerge = $this->buildMasterCopyArray($sql, TRUE);
+    $this->buildMasterCopyArray($sql, TRUE);
 
     // find all the records that have the same street address BUT not in a household
     // require match on city and state as well
@@ -2027,28 +2033,9 @@ AND       ( r1.street_address != '' )
 AND       r2.id > r1.id
 ORDER BY  r1.id
 ";
-    $merge = $this->buildMasterCopyArray($sql);
-
-    // unset ids from $merge already present in $linkedMerge
-    foreach ($linkedMerge as $masterID => $values) {
-      $keys = [$masterID];
-      $keys = array_merge($keys, array_keys($values['copy']));
-      foreach ($merge as $mid => $vals) {
-        if (in_array($mid, $keys)) {
-          unset($merge[$mid]);
-        }
-        else {
-          foreach ($values['copy'] as $copyId) {
-            if (in_array($copyId, $keys)) {
-              unset($merge[$mid]['copy'][$copyId]);
-            }
-          }
-        }
-      }
-    }
-    $merge = $merge + $linkedMerge;
+    $this->buildMasterCopyArray($sql);
 
-    foreach ($merge as $masterID => $values) {
+    foreach ($this->contactsToMerge as $masterID => $values) {
       $sql = "
 UPDATE $tableName
 SET    addressee = %1, postal_greeting = %2, email_greeting = %3