* An empty array to be filed with conflict information.
*
* @return bool
+ *
+ * @throws \CRM_Core_Exception
+ * @throws \CiviCRM_API3_Exception
+ * @throws \API_Exception
*/
public static function skipMerge($mainId, $otherId, &$migrationInfo, $mode = 'safe', &$conflicts = []) {
$conflicts = self::getConflicts($migrationInfo, $mainId, $otherId, $mode);
if (!empty($conflicts)) {
- foreach ($conflicts as $key => $val) {
- if ($val === NULL and $mode == 'safe') {
- // un-resolved conflicts still present. Lets skip this merge after saving the conflict / reason.
- return TRUE;
- }
- else {
- // copy over the resolved values
- $migrationInfo[$key] = $val;
- }
- }
// if there are conflicts and mode is aggressive, allow hooks to decide if to skip merges
return (bool) $migrationInfo['skip_merge'];
}
* @return bool
*/
public static function locationIsSame($mainAddress, $comparisonAddress) {
- $keysToIgnore = [
- 'id',
- 'is_primary',
- 'is_billing',
- 'manual_geo_code',
- 'contact_id',
- 'reset_date',
- 'hold_date',
- ];
+ $keysToIgnore = self::ignoredFields();
foreach ($comparisonAddress as $field => $value) {
if (in_array($field, $keysToIgnore)) {
continue;
if (!isset($submitted['suffix_id']) && !empty($migrationInfo['main_details']['suffix_id'])) {
$submitted['suffix_id'] = $migrationInfo['main_details']['suffix_id'];
}
-
- CRM_Contact_BAO_Contact::createProfileContact($submitted, CRM_Core_DAO::$_nullArray, $mainId);
+ $null = [];
+ CRM_Contact_BAO_Contact::createProfileContact($submitted, $null, $mainId);
}
$transaction->commit();
CRM_Utils_Hook::post('merge', 'Contact', $mainId);
*
* @throws \CRM_Core_Exception
* @throws \CiviCRM_API3_Exception
+ * @throws \API_Exception
*/
protected static function dedupePair(&$resultStats, &$deletedContacts, $mode, $checkPermissions, $mainId, $otherId, $cacheKeyString) {
- // Generate var $migrationInfo. The variable structure is exactly same as
- // $formValues submitted during a UI merge for a pair of contacts.
- $rowsElementsAndInfo = CRM_Dedupe_Merger::getRowsElementsAndInfo($mainId, $otherId, $checkPermissions);
- // add additional details that we might need to resolve conflicts
- $rowsElementsAndInfo['migration_info']['main_details'] = &$rowsElementsAndInfo['main_details'];
- $rowsElementsAndInfo['migration_info']['other_details'] = &$rowsElementsAndInfo['other_details'];
- $rowsElementsAndInfo['migration_info']['rows'] = &$rowsElementsAndInfo['rows'];
- $migrationInfo = $rowsElementsAndInfo['migration_info'];
- // go ahead with merge if there is no conflict
+ $migrationInfo = [];
$conflicts = [];
if (!CRM_Dedupe_Merger::skipMerge($mainId, $otherId, $migrationInfo, $mode, $conflicts)) {
CRM_Dedupe_Merger::moveAllBelongings($mainId, $otherId, $migrationInfo, $checkPermissions);
// 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);
+ CRM_Core_BAO_PrevNextCache::markConflict($mainId, $otherId, $cacheKeyString, $conflicts, $mode);
}
else {
CRM_Core_BAO_PrevNextCache::deletePair($mainId, $otherId, $cacheKeyString);
* - Does a force merge otherwise (aggressive mode).
*
* @return array
+ *
+ * @throws \CRM_Core_Exception
+ * @throws \CiviCRM_API3_Exception
*/
public static function getConflicts(&$migrationInfo, $mainId, $otherId, $mode) {
$conflicts = [];
+ // Generate var $migrationInfo. The variable structure is exactly same as
+ // $formValues submitted during a UI merge for a pair of contacts.
+ $rowsElementsAndInfo = CRM_Dedupe_Merger::getRowsElementsAndInfo($mainId, $otherId, FALSE);
+ // add additional details that we might need to resolve conflicts
+ $migrationInfo = $rowsElementsAndInfo['migration_info'];
+ $migrationInfo['main_details'] = &$rowsElementsAndInfo['main_details'];
+ $migrationInfo['other_details'] = &$rowsElementsAndInfo['other_details'];
+ $migrationInfo['rows'] = &$rowsElementsAndInfo['rows'];
+ // go ahead with merge if there is no conflict
$originalMigrationInfo = $migrationInfo;
foreach ($migrationInfo as $key => $val) {
if ($val === "null") {
$conflicts = $migrationData['fields_in_conflict'];
// allow hook to override / manipulate migrationInfo as well
$migrationInfo = $migrationData['migration_info'];
- $migrationInfo['skip_merge'] = CRM_Utils_Array::value('skip_merge', $migrationData);
- return $conflicts;
+ foreach ($conflicts as $key => $val) {
+ if ($val !== NULL || $mode !== 'safe') {
+ // copy over the resolved values
+ $migrationInfo[$key] = $val;
+ unset($conflicts[$key]);
+ }
+ }
+ $migrationInfo['skip_merge'] = $migrationData['skip_merge'] ?? !empty($conflicts);
+ return self::formatConflictArray($conflicts, $migrationInfo['rows'], $migrationInfo['main_details']['location_blocks'], $migrationInfo['other_details']['location_blocks'], $mainId, $otherId);
+ }
+
+ /**
+ * @param array $conflicts
+ * @param array $migrationInfo
+ * @param $toKeepContactLocationBlocks
+ * @param $toRemoveContactLocationBlocks
+ * @param $toKeepID
+ * @param $toRemoveID
+ *
+ * @return mixed
+ * @throws \CRM_Core_Exception
+ */
+ protected static function formatConflictArray($conflicts, $migrationInfo, $toKeepContactLocationBlocks, $toRemoveContactLocationBlocks, $toKeepID, $toRemoveID) {
+ $return = [];
+ foreach (array_keys($conflicts) as $index) {
+ if (substr($index, 0, 14) === 'move_location_') {
+ $parts = explode('_', $index);
+ $entity = $parts[2];
+ $blockIndex = $parts[3];
+ $locationTypeID = $toKeepContactLocationBlocks[$entity][$blockIndex]['location_type_id'];
+ $entityConflicts = [
+ 'location_type_id' => $locationTypeID,
+ 'title' => $migrationInfo[$index]['title'],
+ ];
+ foreach ($toKeepContactLocationBlocks[$entity][$blockIndex] as $fieldName => $fieldValue) {
+ if (in_array($fieldName, self::ignoredFields())) {
+ continue;
+ }
+ $toRemoveValue = CRM_Utils_Array::value($fieldName, $toRemoveContactLocationBlocks[$entity][$blockIndex]);
+ if ($fieldValue !== $toRemoveValue) {
+ $entityConflicts[$fieldName] = [
+ $toKeepID => $fieldValue,
+ $toRemoveID => $toRemoveValue,
+ ];
+ }
+ }
+ $return[$entity][] = $entityConflicts;
+ }
+ elseif (substr($index, 0, 5) === 'move_') {
+ $contactFieldsToCompare[] = str_replace('move_', '', $index);
+ $return['contact'][str_replace('move_', '', $index)] = [
+ 'title' => $migrationInfo[$index]['title'],
+ $toKeepID => $migrationInfo[$index]['main'],
+ $toRemoveID => $migrationInfo[$index]['other'],
+ ];
+ }
+ else {
+ // Can't think of why this would be the case but perhaps it's ensuring it isn't as we
+ // refactor this.
+ throw new CRM_Core_Exception(ts('Unknown parameter') . $index);
+ }
+ }
+ return $return;
}
/**
);
}
+ /**
+ * @return array
+ */
+ protected static function ignoredFields(): array {
+ $keysToIgnore = [
+ 'id',
+ 'is_primary',
+ 'is_billing',
+ 'manual_geo_code',
+ 'contact_id',
+ 'reset_date',
+ 'hold_date',
+ ];
+ return $keysToIgnore;
+ }
+
}