class CRM_Dedupe_Merger

Methods

static array
relTables()

FIXME: consider creating a common structure with cidRefs() and eidRefs() FIXME: the sub-pages references by the URLs should be loaded dynamically on the merge form instead

static array
getActiveRelTables(int $cid)

Returns the related tables groups for which a contact has any info entered.

static 
cidRefs()

Get array tables and fields that reference civicrm_contact.id.

static 
eidRefs()

Return tables and their fields referencing civicrm_contact.contact_id with entity_id

static 
locTables()

Return tables using locations.

static array
getMultiValueCustomSets(string $request)

We treat multi-valued custom sets as "related tables" similar to activities, contributions, etc.

static 
cpTables()

Tables which require custom processing should declare functions to call here.

static 
paymentTables()

Return payment related table.

static array
paymentSql(string $tableName, int $mainContactId, int $otherContactId)

Return payment update Query.

static array
operationSql(int $mainId, int $otherId, string $tableName, array $tableOperations = [], string $mode = 'add')

No description

static 
removeContactBelongings(int $otherID, bool $tables)

Based on the provided two contact_ids and a set of tables, remove the belongings of the other contact and of their relations.

static 
moveContactBelongings(int $mainId, int $otherId, bool $tables = FALSE, array $tableOperations = [], array $customTableToCopyFrom = NULL)

Based on the provided two contact_ids and a set of tables, move the belongings of the other contact to the main one.

static array
retrieveFields(array $main, array $other)

Load all non-empty fields for the contacts

static array|bool
batchMerge(int $rgid, int $gid = NULL, string $mode = 'safe', int $batchLimit = 1, int $isSelected = 2, array $criteria = [], bool $checkPermissions = TRUE, bool|NULL $reloadCacheIfEmpty = NULL, int $searchLimit = 0)

Batch merge a set of contacts based on rule-group and group.

static string
getJoinOnDedupeTable()

Get the string to join the prevnext cache to the dedupe table.

static string
getWhereString(bool $isSelected)

Get where string for dedupe join.

static 
updateMergeStats(string $cacheKeyString, array $result = [])

Update the statistics for the merge set.

static 
resetMergeStats($cacheKeyString)

Delete information about merges for the given string.

static array
getMergeStats(string $cacheKeyString)

Get merge outcome statistics.

static string
getMergeStatsMsg(array $stats)

Get merge statistics message.

static array|bool
merge(array $dupePairs = [], array $cacheParams = [], string $mode = 'safe', bool $redirectForPerformance = FALSE, bool $checkPermissions = TRUE)

Merge given set of contacts. Performs core operation.

static bool
skipMerge(int $mainId, int $otherId, array $migrationInfo, string $mode = 'safe', array $conflicts = [])

A function which uses various rules / algorithms for choosing which contact to bias to when there's a conflict (to handle "gotchas"). Plus the safest route to merge.

static bool
locationIsSame(array $mainAddress, array $comparisonAddress)

Compare 2 addresses to see if they are the same.

static array
getLocationBlockInfo()

A function to build an array of information about location blocks that is required when merging location fields

static array|bool|int
getRowsElementsAndInfo(int $mainId, int $otherId, bool $checkPermissions = TRUE)

A function to build an array of information required by merge function and the merge UI.

static bool
moveAllBelongings(int $mainId, int $otherId, array $migrationInfo, bool $checkPermissions = TRUE)

Based on the provided two contact_ids and a set of tables, move the belongings of the other contact to the main one - be it Location / CustomFields or Contact .

static array
getContactFields()

Get fields in the contact table suitable for merging.

static 
addMembershipToRealtedContacts(int $contactID)

Added for CRM-12695 Based on the contactID provided add/update membership(s) to related contacts

static 
createMergeActivities(int $mainId, int $otherId)

Create activities tracking the merge on affected contacts.

static array
getDuplicatePairs(int $rule_group_id, int $group_id, bool $reloadCacheIfEmpty, int $batchLimit, bool $isSelected, bool $includeConflicts = TRUE, array $criteria = [], bool $checkPermissions = TRUE, int $searchLimit = 0, int $isForceNewSearch = 0)

Get Duplicate Pairs based on a rule for a group.

static string
getMergeCacheKeyString(int $rule_group_id, int $group_id, array $criteria, bool $checkPermissions, int $searchLimit)

Get the cache key string for the merge action.

static array
getMergeFieldsMetadata()

Get the metadata for the merge fields.

static array
getMergeContactDetails(int $contact_id)

Get the details of the contact to be merged.

static 
mergeLocations(int $mainId, int $otherId, array $migrationInfo)

Merge location.

static bool|array
dedupePair(array $dupes, string $mode = 'safe', bool $checkPermissions = TRUE, string $cacheKeyString = NULL)

Dedupe a pair of contacts.

static 
swapOutFieldsAffectedByQFZeroBug(array $migrationInfo)

Replace the pseudo QFKey with zero if it is present.

static array
processCustomFields($mainId, $key, $cFields, $submitted, $value)

Honestly - what DOES this do - hopefully some refactoring will reveal it's purpose.

static array
getCustomFieldMetadata(string $contactType)

Get metadata for the custom fields for the merge.

static array
getConflicts(array $migrationInfo, int $mainId, int $otherId, string $mode)

Get conflicts for proposed merge pair.

static mixed
formatConflictArray(array $conflicts, array $migrationInfo, $toKeepContactLocationBlocks, $toRemoveContactLocationBlocks, $toKeepID, $toRemoveID)

No description

static array
getCachedDuplicateMatches(int $rule_group_id, int $group_id, int $batchLimit, bool $isSelected, bool $includeConflicts, array $criteria, int $checkPermissions, int $searchLimit = 0)

Get any duplicate merge pairs that have been previously cached.

static array
ignoredFields()

No description

Details

at line 41
static array relTables()

FIXME: consider creating a common structure with cidRefs() and eidRefs() FIXME: the sub-pages references by the URLs should be loaded dynamically on the merge form instead

Return Value

array

at line 193
static array getActiveRelTables(int $cid)

Returns the related tables groups for which a contact has any info entered.

Parameters

int $cid

Return Value

array

at line 232
static cidRefs()

Get array tables and fields that reference civicrm_contact.id.

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.

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.

at line 251
static eidRefs()

Return tables and their fields referencing civicrm_contact.contact_id with entity_id

at line 274
static locTables()

Return tables using locations.

at line 292
static array getMultiValueCustomSets(string $request)

We treat multi-valued custom sets as "related tables" similar to activities, contributions, etc.

Parameters

string $request 'relTables' or 'cidRefs'.

Return Value

array

See also

CRM-13836

at line 332
static cpTables()

Tables which require custom processing should declare functions to call here.

Doing so will override normal processing.

at line 350
static paymentTables()

Return payment related table.

at line 367
static array paymentSql(string $tableName, int $mainContactId, int $otherContactId)

Return payment update Query.

Parameters

string $tableName
int $mainContactId
int $otherContactId

Return Value

array

at line 419
static array operationSql(int $mainId, int $otherId, string $tableName, array $tableOperations = [], string $mode = 'add')

Parameters

int $mainId
int $otherId
string $tableName
array $tableOperations
string $mode

Return Value

array

at line 465
static removeContactBelongings(int $otherID, bool $tables)

Based on the provided two contact_ids and a set of tables, remove the belongings of the other contact and of their relations.

Parameters

int $otherID
bool $tables

at line 496
static moveContactBelongings(int $mainId, int $otherId, bool $tables = FALSE, array $tableOperations = [], array $customTableToCopyFrom = NULL)

Based on the provided two contact_ids and a set of tables, move the belongings of the other contact to the main one.

Parameters

int $mainId
int $otherId
bool $tables
array $tableOperations
array $customTableToCopyFrom

at line 635
static array retrieveFields(array $main, array $other)

Load all non-empty fields for the contacts

Parameters

array $main Contact details.
array $other Contact details.

Return Value

array

at line 704
static array|bool batchMerge(int $rgid, int $gid = NULL, string $mode = 'safe', int $batchLimit = 1, int $isSelected = 2, array $criteria = [], bool $checkPermissions = TRUE, bool|NULL $reloadCacheIfEmpty = NULL, int $searchLimit = 0)

Batch merge a set of contacts based on rule-group and group.

Parameters

int $rgid Rule group id.
int $gid Group id.
string $mode Helps decide how to behave when there are conflicts. A 'safe' value skips the merge if there are any un-resolved conflicts, wheras 'aggressive' mode does a force merge.
int $batchLimit number of merges to carry out in one batch.
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
array $criteria Criteria to use in the filter.
bool $checkPermissions Respect logged in user permissions.
bool|NULL $reloadCacheIfEmpty If not set explicitly this is calculated but it is preferred that it be set per comments on isSelected above.
int $searchLimit Limit on number of contacts to search for duplicates for. This means that if the limit is 1000 then only duplicates for the first 1000 contacts matching criteria will be found and batchMerged (the number of merges could be less than or greater than 100)

Return Value

array|bool

Exceptions

CRM_Core_Exception
CiviCRM_API3_Exception

at line 735
static string getJoinOnDedupeTable()

Get the string to join the prevnext cache to the dedupe table.

Return Value

string The join string to join prevnext cache on the dedupe table.

at line 751
static protected string getWhereString(bool $isSelected)

Get where string for dedupe join.

Parameters

bool $isSelected

Return Value

string

at line 765
static updateMergeStats(string $cacheKeyString, array $result = [])

Update the statistics for the merge set.

Parameters

string $cacheKeyString
array $result

at line 803
static resetMergeStats($cacheKeyString)

Delete information about merges for the given string.

Parameters

$cacheKeyString

at line 817
static array getMergeStats(string $cacheKeyString)

Get merge outcome statistics.

Parameters

string $cacheKeyString

Return Value

array Array of how many were merged and how many were skipped.

Exceptions

CiviCRM_API3_Exception

at line 832
static string getMergeStatsMsg(array $stats)

Get merge statistics message.

Parameters

array $stats

Return Value

string

at line 874
static array|bool merge(array $dupePairs = [], array $cacheParams = [], string $mode = 'safe', bool $redirectForPerformance = FALSE, bool $checkPermissions = TRUE)

Merge given set of contacts. Performs core operation.

Parameters

array $dupePairs Set of pair of contacts for whom merge is to be done.
array $cacheParams Prev-next-cache params based on which next pair of contacts are computed. Generally used with batch-merge.
string $mode Helps decide how to behave when there are conflicts. A 'safe' value skips the merge if there are any un-resolved conflicts. Does a force merge otherwise (aggressive mode).
bool $redirectForPerformance Redirect to a url for batch processing.
bool $checkPermissions Respect logged in user permissions.

Return Value

array|bool

Exceptions

API_Exception
CRM_Core_Exception
CiviCRM_API3_Exception

at line 950
static bool skipMerge(int $mainId, int $otherId, array $migrationInfo, string $mode = 'safe', array $conflicts = [])

A function which uses various rules / algorithms for choosing which contact to bias to when there's a conflict (to handle "gotchas"). Plus the safest route to merge.

Parameters

int $mainId Main contact with whom merge has to happen.
int $otherId Duplicate contact which would be deleted after merge operation.
array $migrationInfo Array of information about which elements to merge.
string $mode Helps decide how to behave when there are conflicts. - A 'safe' value skips the merge if there are any un-resolved conflicts. - Does a force merge otherwise (aggressive mode).
array $conflicts An empty array to be filed with conflict information.

Return Value

bool

Exceptions

CRM_Core_Exception
CiviCRM_API3_Exception
API_Exception

at line 969
static bool locationIsSame(array $mainAddress, array $comparisonAddress)

Compare 2 addresses to see if they are the same.

Parameters

array $mainAddress
array $comparisonAddress

Return Value

bool

at line 988
static array getLocationBlockInfo()

A function to build an array of information about location blocks that is required when merging location fields

Return Value

array

at line 1078
static array|bool|int getRowsElementsAndInfo(int $mainId, int $otherId, bool $checkPermissions = TRUE)

A function to build an array of information required by merge function and the merge UI.

Parameters

int $mainId Main contact with whom merge has to happen.
int $otherId Duplicate contact which would be deleted after merge operation.
bool $checkPermissions Should the logged in user's permissions be ignore. Setting this to false is highly risky as it could cause data to be lost due to conflicts not showing up. OTOH there is a risk a merger might view custom data they do not have permission to. Hence for now only making this really explicit and making it reflect perms in an api call.

Return Value

array|bool|int rows => An array of arrays, each is row of merge information for the table Format: move_fieldname, eg: move_contact_type main => Value associated with the main contact other => Value associated with the other contact title => The title of the field to display in the merge table

elements => An array of form elements for the merge UI

rel_table_elements => An array of form elements for the merge UI for entities related to the contact (eg: checkbox to move 'mailings')

rel_tables => Stores the tables that have related entities for the contact for example mailings, groups

main_details => An array of core contact field values, eg: first_name, etc. location_blocks => An array of location block data for the main contact stored as the 'result' of an API call. eg: main_details['location_blocks']['address'][0]['id'] eg: main_details['location_blocks']['email'][1]['id']

other_details => As above, but for the 'other' contact

migration_info => Stores the 'default' merge actions for each field which is used when programatically merging contacts. It contains instructions to move all fields from the 'other' contact to the 'main' contact, as though the form had been submitted with those options.

Exceptions

CRM_Core_Exception
CiviCRM_API3_Exception
Exception

at line 1455
static bool moveAllBelongings(int $mainId, int $otherId, array $migrationInfo, bool $checkPermissions = TRUE)

Based on the provided two contact_ids and a set of tables, move the belongings of the other contact to the main one - be it Location / CustomFields or Contact .

. related info. A superset of moveContactBelongings() function.

Parameters

int $mainId Main contact with whom merge has to happen.
int $otherId Duplicate contact which would be deleted after merge operation.
array $migrationInfo
bool $checkPermissions Respect logged in user permissions.

Return Value

bool

Exceptions

CiviCRM_API3_Exception

at line 1668
static array getContactFields()

Get fields in the contact table suitable for merging.

Return Value

array Array of field names to be potentially merged.

at line 1696
static addMembershipToRealtedContacts(int $contactID)

Added for CRM-12695 Based on the contactID provided add/update membership(s) to related contacts

Parameters

int $contactID

at line 1730
static createMergeActivities(int $mainId, int $otherId)

Create activities tracking the merge on affected contacts.

Parameters

int $mainId
int $otherId

Exceptions

CiviCRM_API3_Exception

at line 1788
static array getDuplicatePairs(int $rule_group_id, int $group_id, bool $reloadCacheIfEmpty, int $batchLimit, bool $isSelected, bool $includeConflicts = TRUE, array $criteria = [], bool $checkPermissions = TRUE, int $searchLimit = 0, int $isForceNewSearch = 0)

Get Duplicate Pairs based on a rule for a group.

Parameters

int $rule_group_id
int $group_id
bool $reloadCacheIfEmpty Should the cache be reloaded if empty - this must be false when in a dedupe action!
int $batchLimit
bool $isSelected Limit to selected pairs.
bool $includeConflicts
array $criteria Additional criteria to narrow down the merge group.
bool $checkPermissions Respect logged in user permissions.
int $searchLimit Limit to searching for matches against this many contacts.
int $isForceNewSearch Should a new search be forced, bypassing any cache retrieval.

Return Value

array Array of matches meeting the criteria.

Exceptions

CRM_Core_Exception
CiviCRM_API3_Exception

at line 1817
static string getMergeCacheKeyString(int $rule_group_id, int $group_id, array $criteria, bool $checkPermissions, int $searchLimit)

Get the cache key string for the merge action.

Parameters

int $rule_group_id
int $group_id
array $criteria Additional criteria to narrow down the merge group. Currently we are only supporting the key 'contact' within it.
bool $checkPermissions Respect the users permissions.
int $searchLimit Number of contacts to seek dupes for (we need this because if we change it the results won't be refreshed otherwise. Changing the limit from 100 to 1000 SHOULD result in a new dedupe search).

Return Value

string

at line 1846
static array getMergeFieldsMetadata()

Get the metadata for the merge fields.

This is basically the contact metadata, augmented with fields to represent email greeting, postal greeting & addressee.

Return Value

array

at line 1871
static array getMergeContactDetails(int $contact_id)

Get the details of the contact to be merged.

Parameters

int $contact_id

Return Value

array

Exceptions

CRM_Core_Exception

at line 1913
static mergeLocations(int $mainId, int $otherId, array $migrationInfo)

Merge location.

Based on the data in the $locationMigrationInfo merge the locations for 2 contacts.

The data is in the format received from the merge form (which is a fairly confusing format).

It is converted into an array of DAOs which is passed to the alterLocationMergeData hook before saving or deleting the DAOs. A new hook is added to allow these to be altered after they have been calculated and before saving because - the existing format & hook combo is so confusing it is hard for developers to change & inherently fragile - passing to a hook right before save means calculations only have to be done once - the existing pattern of passing dissimilar data to the same (merge) hook with a different 'type' is just ugly.

The use of the new hook is tested, including the fact it is called before contributions are merged, as this is likely to be significant data in merge hooks.

Parameters

int $mainId
int $otherId
array $migrationInfo Migration info for the merge. This is passed to the hook as informational only.

at line 2053
static protected bool|array dedupePair(array $dupes, string $mode = 'safe', bool $checkPermissions = TRUE, string $cacheKeyString = NULL)

Dedupe a pair of contacts.

Parameters

array $dupes
string $mode
bool $checkPermissions
string $cacheKeyString

Return Value

bool|array

Exceptions

CRM_Core_Exception
CiviCRM_API3_Exception
API_Exception

at line 2099
static protected swapOutFieldsAffectedByQFZeroBug(array $migrationInfo)

Replace the pseudo QFKey with zero if it is present.

Parameters

array $migrationInfo

at line 2127
static protected array processCustomFields($mainId, $key, $cFields, $submitted, $value)

Honestly - what DOES this do - hopefully some refactoring will reveal it's purpose.

Update this function formats fields in preparation for them to be submitted to the 'ProfileContactCreate action. This is a lot of code to do this & for - for some fields it fails - e.g Country - per testMergeCustomFields.

Goal is to move all custom field handling into 'move' functions on the various BAO with an underlying DAO function. For custom fields it has been started on the BAO.

Parameters

$mainId
$key
$cFields
$submitted
$value

Return Value

array

Exceptions

Exception

at line 2230
static protected array getCustomFieldMetadata(string $contactType)

Get metadata for the custom fields for the merge.

Parameters

string $contactType

Return Value

array

at line 2279
static array getConflicts(array $migrationInfo, int $mainId, int $otherId, string $mode)

Get conflicts for proposed merge pair.

Parameters

array $migrationInfo This is primarily to inform hooks. The can also modify it which feels pretty fragile to do it here - but it is historical.
int $mainId Main contact with whom merge has to happen.
int $otherId Duplicate contact which would be deleted after merge operation.
string $mode Helps decide how to behave when there are conflicts. - A 'safe' value skips the merge if there are any un-resolved conflicts. - Does a force merge otherwise (aggressive mode).

Return Value

array

Exceptions

CRM_Core_Exception
CiviCRM_API3_Exception

at line 2393
static protected mixed formatConflictArray(array $conflicts, array $migrationInfo, $toKeepContactLocationBlocks, $toRemoveContactLocationBlocks, $toKeepID, $toRemoveID)

Parameters

array $conflicts
array $migrationInfo
$toKeepContactLocationBlocks
$toRemoveContactLocationBlocks
$toKeepID
$toRemoveID

Return Value

mixed

Exceptions

CRM_Core_Exception

at line 2450
static protected array getCachedDuplicateMatches(int $rule_group_id, int $group_id, int $batchLimit, bool $isSelected, bool $includeConflicts, array $criteria, int $checkPermissions, int $searchLimit = 0)

Get any duplicate merge pairs that have been previously cached.

Parameters

int $rule_group_id
int $group_id
int $batchLimit
bool $isSelected
bool $includeConflicts
array $criteria
int $checkPermissions
int $searchLimit

Return Value

array

at line 2464
static protected array ignoredFields()

Return Value

array