Merge pull request #13181 from eileenmcnaughton/financial_type_id_default
[civicrm-core.git] / CRM / Dedupe / Merger.php
index 86b3ff03120dd0122c12b9548a029cecdb924213..afb53df5f545cf88b5a0fc4ec3b46c6f7d9b71c0 100644 (file)
@@ -203,35 +203,23 @@ class CRM_Dedupe_Merger {
   /**
    * Get array tables and fields that reference civicrm_contact.id.
    *
-   * This includes core tables, custom group tables, tables added by the merge
-   * hook and (somewhat randomly) the entity_tag table.
+   * This function calls the merge hook and only exists to wrap the DAO function to support that deprecated call.
+   * The entityTypes hook is the recommended way to add tables to this result.
    *
-   * Refer to CRM-17454 for information on the danger of querying the information
-   * schema to derive this.
-   *
-   * This function calls the merge hook but the entityTypes hook is the recommended
-   * way to add tables to this result.
+   * I thought about adding another hook to alter tableReferences but decided it was unclear if there
+   * are use cases not covered by entityTables and instead we should wait & see.
    */
   public static function cidRefs() {
     if (isset(\Civi::$statics[__CLASS__]) && isset(\Civi::$statics[__CLASS__]['contact_references'])) {
       return \Civi::$statics[__CLASS__]['contact_references'];
     }
-    $contactReferences = array();
-    $coreReferences = CRM_Core_DAO::getReferencesToTable('civicrm_contact');
-    foreach ($coreReferences as $coreReference) {
-      if (!is_a($coreReference, 'CRM_Core_Reference_Dynamic')) {
-        $contactReferences[$coreReference->getReferenceTable()][] = $coreReference->getReferenceKey();
-      }
-    }
-    self::addCustomTablesExtendingContactsToCidRefs($contactReferences);
 
-    // FixME for time being adding below line statically as no Foreign key constraint defined for table 'civicrm_entity_tag'
-    $contactReferences['civicrm_entity_tag'][] = 'entity_id';
+    $contactReferences = $coreReferences = CRM_Core_DAO::getReferencesToContactTable();
 
-    // Allow hook_civicrm_merge() to adjust $cidRefs.
-    // Note that if entities are registered using the entityTypes hook there
-    // is no need to use this hook.
     CRM_Utils_Hook::merge('cidRefs', $contactReferences);
+    if ($contactReferences !== $coreReferences) {
+      Civi::log()->warning("Deprecated hook ::merge in context of 'cidRefs. Use entityTypes instead.", array('civi.tag' => 'deprecated'));
+    }
     \Civi::$statics[__CLASS__]['contact_references'] = $contactReferences;
     return \Civi::$statics[__CLASS__]['contact_references'];
   }
@@ -486,7 +474,8 @@ INNER JOIN  civicrm_membership membership2 ON membership1.membership_type_id = m
     // getting all custom tables
     $customTables = array();
     if ($customTableToCopyFrom !== NULL) {
-      self::addCustomTablesExtendingContactsToCidRefs($customTables);
+      // @todo this duplicates cidRefs?
+      CRM_Core_DAO::appendCustomTablesExtendingContacts($customTables);
       $customTables = array_keys($customTables);
     }
 
@@ -651,18 +640,31 @@ INNER JOIN  civicrm_membership membership2 ON membership1.membership_type_id = m
    *   mode does a force merge.
    * @param int $batchLimit number of merges to carry out in one batch.
    * @param int $isSelected if records with is_selected column needs to be processed.
+   *   Note the option of '2' is only used in conjunction with $redirectForPerformance
+   *   to determine when to reload the cache (!). The use of anything other than a boolean is being grandfathered
+   *   out in favour of explicitly passing in $reloadCacheIfEmpty
    *
    * @param array $criteria
    *   Criteria to use in the filter.
    *
    * @param bool $checkPermissions
    *   Respect logged in user permissions.
+   * @param bool|NULL $reloadCacheIfEmpty
+   *  If not set explicitly this is calculated but it is preferred that it be set
+   *  per comments on isSelected above.
    *
    * @return array|bool
    */
-  public static function batchMerge($rgid, $gid = NULL, $mode = 'safe', $batchLimit = 1, $isSelected = 2, $criteria = array(), $checkPermissions = TRUE) {
+  public static function batchMerge($rgid, $gid = NULL, $mode = 'safe', $batchLimit = 1, $isSelected = 2, $criteria = array(), $checkPermissions = TRUE, $reloadCacheIfEmpty = NULL) {
     $redirectForPerformance = ($batchLimit > 1) ? TRUE : FALSE;
-    $reloadCacheIfEmpty = (!$redirectForPerformance && $isSelected == 2);
+
+    if (!isset($reloadCacheIfEmpty)) {
+      $reloadCacheIfEmpty = (!$redirectForPerformance && $isSelected == 2);
+    }
+    if ($isSelected !== 0 && $isSelected !== 1) {
+      // explicitly set to NULL if not 1 or 0 as part of grandfathering out the mystical '2' value.
+      $isSelected = NULL;
+    }
     $dupePairs = self::getDuplicatePairs($rgid, $gid, $reloadCacheIfEmpty, $batchLimit, $isSelected, '', ($mode == 'aggressive'), $criteria, $checkPermissions);
 
     $cacheParams = array(
@@ -670,7 +672,8 @@ INNER JOIN  civicrm_membership membership2 ON membership1.membership_type_id = m
       // @todo stop passing these parameters in & instead calculate them in the merge function based
       // on the 'real' params like $isRespectExclusions $batchLimit and $isSelected.
       'join' => self::getJoinOnDedupeTable(),
-      'where' => self::getWhereString($batchLimit, $isSelected),
+      'where' => self::getWhereString($isSelected),
+      'limit' => (int) $batchLimit,
     );
     return CRM_Dedupe_Merger::merge($dupePairs, $cacheParams, $mode, $redirectForPerformance, $checkPermissions);
   }
@@ -693,21 +696,15 @@ INNER JOIN  civicrm_membership membership2 ON membership1.membership_type_id = m
   /**
    * Get where string for dedupe join.
    *
-   * @param int $batchLimit
    * @param bool $isSelected
    *
    * @return string
    */
-  protected static function getWhereString($batchLimit, $isSelected) {
+  protected static function getWhereString($isSelected) {
     $where = "de.id IS NULL";
     if ($isSelected === 0 || $isSelected === 1) {
       $where .= " AND pn.is_selected = {$isSelected}";
     }
-    // else consider all dupe pairs
-    // @todo Adding limit to Where??!!
-    if ($batchLimit) {
-      $where .= " LIMIT {$batchLimit}";
-    }
     return $where;
   }
 
@@ -858,7 +855,7 @@ INNER JOIN  civicrm_membership membership2 ON membership1.membership_type_id = m
           $cacheParams['join'],
           $cacheParams['where'],
           0,
-          0,
+          $cacheParams['limit'],
           array(),
           '',
           FALSE
@@ -1034,7 +1031,7 @@ INNER JOIN  civicrm_membership membership2 ON membership1.membership_type_id = m
       ),
       'email' => array(
         'label' => 'Email',
-        'displayField' => 'email',
+        'displayField' => 'display',
         'sortString' => 'location_type_id',
         'hasLocation' => TRUE,
         'hasType' => FALSE,
@@ -1231,6 +1228,10 @@ INNER JOIN  civicrm_membership membership2 ON membership1.membership_type_id = m
               CRM_Core_BAO_Address::fixAddress($value);
               $locations[$moniker][$blockName][$cnt]['display'] = CRM_Utils_Address::format($value);
             }
+            // Fix email display
+            elseif ($blockName == 'email') {
+              $locations[$moniker][$blockName][$cnt]['display'] = CRM_Utils_Mail::format($value);
+            }
 
             $cnt++;
           }
@@ -1445,7 +1446,6 @@ INNER JOIN  civicrm_membership membership2 ON membership1.membership_type_id = m
     $otherTree = CRM_Core_BAO_CustomGroup::getTree($main['contact_type'], NULL, $otherId, -1,
       CRM_Utils_Array::value('contact_sub_type', $other), NULL, TRUE, NULL, TRUE, $checkPermissions
     );
-    CRM_Core_DAO::freeResult();
 
     foreach ($otherTree as $gid => $group) {
       $foundField = FALSE;
@@ -1914,26 +1914,6 @@ INNER JOIN  civicrm_membership membership2 ON membership1.membership_type_id = m
     }
   }
 
-  /**
-   * Add custom tables that extend contacts to the list of contact references.
-   *
-   * CRM_Core_BAO_CustomGroup::getAllCustomGroupsByBaseEntity seems like a safe-ish
-   * function to be sure all are retrieved & we don't miss subtypes or inactive or multiples
-   * - the down side is it is not cached.
-   *
-   * Further changes should be include tests in the CRM_Core_MergerTest class
-   * to ensure that disabled, subtype, multiple etc groups are still captured.
-   *
-   * @param array $cidRefs
-   */
-  public static function addCustomTablesExtendingContactsToCidRefs(&$cidRefs) {
-    $customValueTables = CRM_Core_BAO_CustomGroup::getAllCustomGroupsByBaseEntity('Contact');
-    $customValueTables->find();
-    while ($customValueTables->fetch()) {
-      $cidRefs[$customValueTables->table_name] = array('entity_id');
-    }
-  }
-
   /**
    * Create activities tracking the merge on affected contacts.
    *
@@ -1974,6 +1954,7 @@ INNER JOIN  civicrm_membership membership2 ON membership1.membership_type_id = m
    * @param int $rule_group_id
    * @param int $group_id
    * @param bool $reloadCacheIfEmpty
+   *   Should the cache be reloaded if empty - this must be false when in a dedupe action!
    * @param int $batchLimit
    * @param bool $isSelected
    *   Limit to selected pairs.
@@ -1992,16 +1973,16 @@ INNER JOIN  civicrm_membership membership2 ON membership1.membership_type_id = m
    *    Array of matches meeting the criteria.
    */
   public static function getDuplicatePairs($rule_group_id, $group_id, $reloadCacheIfEmpty, $batchLimit, $isSelected, $orderByClause = '', $includeConflicts = TRUE, $criteria = array(), $checkPermissions = TRUE, $searchLimit = 0) {
-    $where = self::getWhereString($batchLimit, $isSelected);
+    $where = self::getWhereString($isSelected);
     $cacheKeyString = self::getMergeCacheKeyString($rule_group_id, $group_id, $criteria, $checkPermissions);
     $join = self::getJoinOnDedupeTable();
-    $dupePairs = CRM_Core_BAO_PrevNextCache::retrieve($cacheKeyString, $join, $where, 0, 0, array(), $orderByClause, $includeConflicts);
+    $dupePairs = CRM_Core_BAO_PrevNextCache::retrieve($cacheKeyString, $join, $where, 0, $batchLimit, array(), $orderByClause, $includeConflicts);
     if (empty($dupePairs) && $reloadCacheIfEmpty) {
       // If we haven't found any dupes, probably cache is empty.
       // Try filling cache and give another try. We don't need to specify include conflicts here are there will not be any
       // until we have done some processing.
       CRM_Core_BAO_PrevNextCache::refillCache($rule_group_id, $group_id, $cacheKeyString, $criteria, $checkPermissions, $searchLimit);
-      $dupePairs = CRM_Core_BAO_PrevNextCache::retrieve($cacheKeyString, $join, $where, 0, 0, array(), $orderByClause, $includeConflicts);
+      $dupePairs = CRM_Core_BAO_PrevNextCache::retrieve($cacheKeyString, $join, $where, 0, $batchLimit, array(), $orderByClause, $includeConflicts);
       return $dupePairs;
     }
     return $dupePairs;
@@ -2023,7 +2004,7 @@ INNER JOIN  civicrm_membership membership2 ON membership1.membership_type_id = m
    */
   public static function getMergeCacheKeyString($rule_group_id, $group_id, $criteria = array(), $checkPermissions = TRUE) {
     $contactType = CRM_Dedupe_BAO_RuleGroup::getContactTypeForRuleGroup($rule_group_id);
-    $cacheKeyString = "merge {$contactType}";
+    $cacheKeyString = "merge_{$contactType}";
     $cacheKeyString .= $rule_group_id ? "_{$rule_group_id}" : '_0';
     $cacheKeyString .= $group_id ? "_{$group_id}" : '_0';
     $cacheKeyString .= !empty($criteria) ? md5(serialize($criteria)) : '_0';
@@ -2316,8 +2297,6 @@ INNER JOIN  civicrm_membership membership2 ON membership1.membership_type_id = m
       // pair may have been flipped, so make sure we delete using both orders
       CRM_Core_BAO_PrevNextCache::deletePair($mainId, $otherId, $cacheKeyString, TRUE);
     }
-
-    CRM_Core_DAO::freeResult();
   }
 
 }