<?php
/*
+--------------------------------------------------------------------+
- | CiviCRM version 4.6 |
+ | CiviCRM version 4.7 |
+--------------------------------------------------------------------+
| Copyright CiviCRM LLC (c) 2004-2015 |
+--------------------------------------------------------------------+
$title = ts('%1 User: %2; user id: %3', array(1 => $config->userFramework, 2 => '$ufname', 3 => '$ufid'));
}
elseif ($config->userFramework == 'Joomla') {
- $userRecordUrl = $config->userFrameworkVersion > 1.5 ? $config->userFrameworkBaseURL . "index.php?option=com_users&view=user&task=user.edit&id=" . '%ufid' : $config->userFrameworkBaseURL . "index2.php?option=com_users&view=user&task=edit&id[]=" . '%ufid';
+ $userRecordUrl = $config->userSystem->getVersion() > 1.5 ? $config->userFrameworkBaseURL . "index.php?option=com_users&view=user&task=user.edit&id=" . '%ufid' : $config->userFrameworkBaseURL . "index2.php?option=com_users&view=user&task=edit&id[]=" . '%ufid';
$title = ts('%1 User: %2; user id: %3', array(1 => $config->userFramework, 2 => '$ufname', 3 => '$ufid'));
}
* Does a force merge otherwise.
* @param bool $autoFlip to let api decide which contact to retain and which to delete.
* Wether to let api decide which contact to retain and which to delete.
- * @param bool $redirectForPerformance
+ * @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.
*
* @return array|bool
*/
- public static function batchMerge($rgid, $gid = NULL, $mode = 'safe', $autoFlip = TRUE, $redirectForPerformance = FALSE) {
+ public static function batchMerge($rgid, $gid = NULL, $mode = 'safe', $autoFlip = TRUE, $batchLimit = 1, $isSelected = 2) {
$contactType = CRM_Core_DAO::getFieldValue('CRM_Dedupe_DAO_RuleGroup', $rgid, 'contact_type');
$cacheKeyString = "merge {$contactType}";
$cacheKeyString .= $rgid ? "_{$rgid}" : '_0';
$join = "LEFT JOIN civicrm_dedupe_exception de ON ( pn.entity_id1 = de.contact_id1 AND
pn.entity_id2 = de.contact_id2 )";
- $limit = $redirectForPerformance ? 75 : 1;
- $where = "de.id IS NULL LIMIT {$limit}";
+ $where = "de.id IS NULL";
+ if ($isSelected === 0 || $isSelected === 1) {
+ $where .= " AND pn.is_selected = {$isSelected}";
+ }// else consider all dupe pairs
+ $where .= " LIMIT {$batchLimit}";
+
+ $redirectForPerformance = ($batchLimit > 1) ? TRUE : FALSE;
$dupePairs = CRM_Core_BAO_PrevNextCache::retrieve($cacheKeyString, $join, $where);
- if (empty($dupePairs) && !$redirectForPerformance) {
+ if (empty($dupePairs) && !$redirectForPerformance && $isSelected == 2) {
// If we haven't found any dupes, probably cache is empty.
// Try filling cache and give another try.
CRM_Core_BAO_PrevNextCache::refillCache($rgid, $gid, $cacheKeyString);
return CRM_Dedupe_Merger::merge($dupePairs, $cacheParams, $mode, $autoFlip, $redirectForPerformance);
}
+ public static function updateMergeStats($cacheKeyString, $result = array()) {
+ // gather latest stats
+ $merged = count($result['merged']);
+ $skipped = count($result['skipped']);
+
+ if ($merged <= 0 && $skipped <= 0) {
+ return;
+ }
+
+ // get previous stats
+ $previousStats = CRM_Core_BAO_PrevNextCache::retrieve("{$cacheKeyString}_stats");
+ if (!empty($previousStats)) {
+ if ($previousStats[0]['merged']) {
+ $merged = $merged + $previousStats[0]['merged'];
+ }
+ if ($previousStats[0]['skipped']) {
+ $skipped = $skipped + $previousStats[0]['skipped'];
+ }
+ }
+
+ // delete old stats
+ CRM_Dedupe_Merger::resetMergeStats($cacheKeyString);
+
+ // store the updated stats
+ $data = array(
+ 'merged' => $merged,
+ 'skipped' => $skipped,
+ );
+ $data = CRM_Core_DAO::escapeString(serialize($data));
+
+ $values = array();
+ $values[] = " ( 'civicrm_contact', 0, 0, '{$cacheKeyString}_stats', '$data' ) ";
+ CRM_Core_BAO_PrevNextCache::setItem($values);
+ }
+
+ public static function resetMergeStats($cacheKeyString) {
+ return CRM_Core_BAO_PrevNextCache::deleteItem(NULL, "{$cacheKeyString}_stats");
+ }
+
+ public static function getMergeStats($cacheKeyString) {
+ $stats = CRM_Core_BAO_PrevNextCache::retrieve("{$cacheKeyString}_stats");
+ if (!empty($stats)) {
+ $stats = $stats[0];
+ }
+ return $stats;
+ }
+
+ public static function getMergeStatsMsg($cacheKeyString) {
+ $msg = '';
+ $stats = CRM_Dedupe_Merger::getMergeStats($cacheKeyString);
+ if (!empty($stats['merged'])) {
+ $msg = "{$stats['merged']} " . ts(' Contact(s) were merged. ');
+ }
+ if (!empty($stats['skipped'])) {
+ $msg .= $stats['skipped'] . ts(' Contact(s) were skipped.');
+ }
+ return $msg;
+ }
+
/**
* Merge given set of contacts. Performs core operation.
*
$migrationInfo['rows'] = &$rowsElementsAndInfo['rows'];
// go ahead with merge if there is no conflict
- if (!CRM_Dedupe_Merger::skipMerge($mainId, $otherId, $migrationInfo, $mode)) {
+ $conflicts = array();
+ if (!CRM_Dedupe_Merger::skipMerge($mainId, $otherId, $migrationInfo, $mode, $conflicts)) {
CRM_Dedupe_Merger::moveAllBelongings($mainId, $otherId, $migrationInfo);
$resultStats['merged'][] = array('main_id' => $mainId, 'other_id' => $otherId);
}
$resultStats['skipped'][] = array('main_id' => $mainId, 'other_id' => $otherId);
}
- // delete entry from PrevNextCache table so we don't consider the pair next time
- // pair may have been flipped, so make sure we delete using both orders
- CRM_Core_BAO_PrevNextCache::deletePair($mainId, $otherId, $cacheKeyString);
- CRM_Core_BAO_PrevNextCache::deletePair($otherId, $mainId, $cacheKeyString);
+ // store any conflicts
+ if (!empty($conflicts)) {
+ foreach ($conflicts as $key => $dnc) {
+ $conflicts[$key] = "{$migrationInfo['rows'][$key]['title']}: '{$migrationInfo['rows'][$key]['main']}' vs. '{$migrationInfo['rows'][$key]['other']}'";
+ }
+ CRM_Core_BAO_PrevNextCache::markConflict($mainId, $otherId, $cacheKeyString, $conflicts);
+ }
+ else {
+ // delete entry from PrevNextCache table so we don't consider the pair next time
+ // 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();
unset($rowsElementsAndInfo, $migrationInfo);
unset($dupePairs);
}
}
+
+ CRM_Dedupe_Merger::updateMergeStats($cacheKeyString, $resultStats);
return $resultStats;
}
*
* @return bool
*/
- public static function skipMerge($mainId, $otherId, &$migrationInfo, $mode = 'safe') {
- $conflicts = array();
+ public static function skipMerge($mainId, $otherId, &$migrationInfo, $mode = 'safe', &$conflicts = array()) {
+ //$conflicts = array();
$migrationData = array(
'old_migration_info' => $migrationInfo,
'mode' => $mode,
// particular field or not
if (!empty($migrationInfo['rows'][$key]['main'])) {
// if main also has a value its a conflict
- if ($mode == 'safe') {
- // note it down & lets wait for response from the hook.
- // For no response skip this merge
- $conflicts[$key] = NULL;
- }
- elseif ($mode == 'aggressive') {
- // let the main-field be overwritten
- continue;
- }
+
+ // note it down & lets wait for response from the hook.
+ // For no response $mode will decide if to skip this merge
+ $conflicts[$key] = NULL;
}
}
elseif (substr($key, 0, 14) == 'move_location_' and $val != NULL) {
// try insert address at new available loc-type
$migrationInfo['location'][$fieldName][$fieldCount]['locTypeId'] = $newTypeId;
}
- elseif ($mode == 'safe') {
+ else {
// note it down & lets wait for response from the hook.
- // For no response skip this merge
+ // For no response $mode will decide if to skip this merge
$conflicts[$key] = NULL;
}
- elseif ($mode == 'aggressive') {
- // let the loc-type-id be same as that of other-contact & go ahead
- // with merge assuming aggressive mode
- continue;
- }
}
}
elseif ($migrationInfo['rows'][$key]['main'] == $migrationInfo['rows'][$key]['other']) {
// merge happens with new values filled in here. For a particular field / row not to be merged
// field should be unset from fields_in_conflict.
$migrationData['fields_in_conflict'] = $conflicts;
+ $migrationData['merge_mode'] = $mode;
CRM_Utils_Hook::merge('batch', $migrationData, $mainId, $otherId);
$conflicts = $migrationData['fields_in_conflict'];
+ // allow hook to override / manipulate migrationInfo as well
+ $migrationInfo = $migrationData['old_migration_info'];
if (!empty($conflicts)) {
foreach ($conflicts as $key => $val) {
if ($val === NULL and $mode == 'safe') {
- // un-resolved conflicts still present. Lets skip this merge.
+ // un-resolved conflicts still present. Lets skip this merge after saving the conflict / reason.
return TRUE;
}
else {
$migrationInfo[$key] = $val;
}
}
+ // if there are conflicts and mode is aggressive, allow hooks to decide if to skip merges
+ if (array_key_exists('skip_merge', $migrationData)) {
+ return (bool) $migrationData['skip_merge'];
+ }
}
return FALSE;
}