From b8cb7e46ca7e5def15f41f0b0aa300f892c1a731 Mon Sep 17 00:00:00 2001 From: "Matthew Wire (MJW Consulting)" Date: Wed, 5 Dec 2018 18:10:54 +0000 Subject: [PATCH] Add 'Find Duplicates' hook to override duplicate checking when registering/contributing --- CRM/Contact/BAO/Contact.php | 23 +++++++++--- CRM/Event/Form/Registration/Register.php | 2 +- CRM/Utils/Hook.php | 23 ++++++++++++ tests/phpunit/CRM/Dedupe/DedupeFinderTest.php | 37 ++++++++++++++++++- 4 files changed, 78 insertions(+), 7 deletions(-) diff --git a/CRM/Contact/BAO/Contact.php b/CRM/Contact/BAO/Contact.php index a38e8409cb..8395ded73d 100644 --- a/CRM/Contact/BAO/Contact.php +++ b/CRM/Contact/BAO/Contact.php @@ -3594,14 +3594,25 @@ LEFT JOIN civicrm_address ON ( civicrm_address.contact_id = civicrm_contact.id ) * @param bool $checkPermissions * @param int $ruleGroupID * ID of the rule group to be used if an override is desirable. + * @param array $contextParams + * The context if relevant, eg. ['event_id' => X] * * @return array */ - public static function getDuplicateContacts($input, $contactType, $rule = 'Unsupervised', $excludedContactIDs = array(), $checkPermissions = TRUE, $ruleGroupID = NULL) { + public static function getDuplicateContacts($input, $contactType, $rule = 'Unsupervised', $excludedContactIDs = [], $checkPermissions = TRUE, $ruleGroupID = NULL, $contextParams = []) { $dedupeParams = CRM_Dedupe_Finder::formatParams($input, $contactType); $dedupeParams['check_permission'] = $checkPermissions; - $ids = CRM_Dedupe_Finder::dupesByParams($dedupeParams, $contactType, $rule, $excludedContactIDs, $ruleGroupID); - return $ids; + $dedupeParams['contact_type'] = $contactType; + $dedupeParams['rule'] = $rule; + $dedupeParams['rule_group_id'] = $ruleGroupID; + $dedupeParams['excluded_contact_ids'] = $excludedContactIDs; + $dedupeResults['ids'] = []; + $dedupeResults['handled'] = FALSE; + CRM_Utils_Hook::findDuplicates($dedupeParams, $dedupeResults, $contextParams); + if (!$dedupeResults['handled']) { + $dedupeResults['ids'] = CRM_Dedupe_Finder::dupesByParams($dedupeParams, $contactType, $rule, $excludedContactIDs, $ruleGroupID); + } + return $dedupeResults['ids']; } /** @@ -3618,11 +3629,13 @@ LEFT JOIN civicrm_address ON ( civicrm_address.contact_id = civicrm_contact.id ) * @param bool $checkPermissions * @param int $ruleGroupID * ID of the rule group to be used if an override is desirable. + * @param array $contextParams + * The context if relevant, eg. ['event_id' => X] * * @return int|NULL */ - public static function getFirstDuplicateContact($input, $contactType, $rule = 'Unsupervised', $excludedContactIDs = array(), $checkPermissions = TRUE, $ruleGroupID = NULL) { - $ids = self::getDuplicateContacts($input, $contactType, $rule, $excludedContactIDs, $checkPermissions, $ruleGroupID); + public static function getFirstDuplicateContact($input, $contactType, $rule = 'Unsupervised', $excludedContactIDs = [], $checkPermissions = TRUE, $ruleGroupID = NULL, $contextParams = []) { + $ids = self::getDuplicateContacts($input, $contactType, $rule, $excludedContactIDs, $checkPermissions, $ruleGroupID, $contextParams); if (empty($ids)) { return NULL; } diff --git a/CRM/Event/Form/Registration/Register.php b/CRM/Event/Form/Registration/Register.php index da54819b40..d2ed584ad1 100644 --- a/CRM/Event/Form/Registration/Register.php +++ b/CRM/Event/Form/Registration/Register.php @@ -99,7 +99,7 @@ class CRM_Event_Form_Registration_Register extends CRM_Event_Form_Registration { $contactID = $form->getContactID(); } if (!$contactID && is_array($fields) && $fields) { - $contactID = CRM_Contact_BAO_Contact::getFirstDuplicateContact($fields, 'Individual', 'Unsupervised', array(), FALSE, CRM_Utils_Array::value('dedupe_rule_group_id', $form->_values['event'])); + $contactID = CRM_Contact_BAO_Contact::getFirstDuplicateContact($fields, 'Individual', 'Unsupervised', [], FALSE, CRM_Utils_Array::value('dedupe_rule_group_id', $form->_values['event']), ['event_id' => CRM_Utils_Array::value('id', $form->_values['event'])]); } return $contactID; } diff --git a/CRM/Utils/Hook.php b/CRM/Utils/Hook.php index 021ecc5d33..e759533aa4 100644 --- a/CRM/Utils/Hook.php +++ b/CRM/Utils/Hook.php @@ -1297,6 +1297,29 @@ abstract class CRM_Utils_Hook { ); } + /** + * Check for duplicate contacts + * + * @param array $dedupeParams + * Array of params for finding duplicates: [ + * '{parameters returned by CRM_Dedupe_Finder::formatParams} + * 'check_permission' => TRUE/FALSE; + * 'contact_type' => $contactType; + * 'rule' = $rule; + * 'rule_group_id' => $ruleGroupID; + * 'excludedContactIDs' => $excludedContactIDs; + * @param array $dedupeResults + * Array of results ['handled' => TRUE/FALSE, 'ids' => array of IDs of duplicate contacts] + * @param array $contextParams + * The context if relevant, eg. ['event_id' => X] + * + * @return mixed + */ + public static function findDuplicates($dedupeParams, &$dedupeResults, $contextParams) { + return self::singleton() + ->invoke(array('dedupeParams', 'dedupeResults', 'contextParams'), $dedupeParams, $dedupeResults, $contextParams, self::$_nullObject, self::$_nullObject, self::$_nullObject, 'civicrm_findDuplicates'); + } + /** * This hook is called AFTER EACH email has been processed by the script bin/EmailProcessor.php * diff --git a/tests/phpunit/CRM/Dedupe/DedupeFinderTest.php b/tests/phpunit/CRM/Dedupe/DedupeFinderTest.php index 00382553ea..f559aece3c 100644 --- a/tests/phpunit/CRM/Dedupe/DedupeFinderTest.php +++ b/tests/phpunit/CRM/Dedupe/DedupeFinderTest.php @@ -169,6 +169,8 @@ class CRM_Dedupe_DedupeFinderTest extends CiviUnitTestCase { ), ); + $this->hookClass->setHook('civicrm_findDuplicates', array($this, 'hook_civicrm_findDuplicates')); + $count = 1; foreach ($params as $param) { @@ -192,7 +194,7 @@ class CRM_Dedupe_DedupeFinderTest extends CiviUnitTestCase { 'street_address' => 'Ambachtstraat 23', ); CRM_Core_TemporaryErrorScope::useException(); - $ids = CRM_Contact_BAO_Contact::getDuplicateContacts($fields, 'Individual', 'General'); + $ids = CRM_Contact_BAO_Contact::getDuplicateContacts($fields, 'Individual', 'General', [], TRUE, NULL, ['event_id' => 1]); // Check with default Individual-General rule $this->assertEquals(count($ids), 2, 'Check Individual-General rule for dupesByParams().'); @@ -203,6 +205,39 @@ class CRM_Dedupe_DedupeFinderTest extends CiviUnitTestCase { } } + /** + * Implements hook_civicrm_findDuplicates(). + * + * Locks in expected params + * + */ + public function hook_civicrm_findDuplicates($dedupeParams, &$dedupeResults, $contextParams) { + $expectedDedupeParams = [ + 'check_permission' => TRUE, + 'contact_type' => 'Individual', + 'rule' => 'General', + 'rule_group_id' => NULL, + 'excluded_contact_ids' => [], + ]; + foreach ($expectedDedupeParams as $key => $value) { + $this->assertEquals($value, $dedupeParams[$key]); + } + $expectedDedupeResults = [ + 'ids' => [], + 'handled' => FALSE, + ]; + foreach ($expectedDedupeResults as $key => $value) { + $this->assertEquals($value, $dedupeResults[$key]); + } + + $expectedContext = ['event_id' => 1]; + foreach ($expectedContext as $key => $value) { + $this->assertEquals($value, $contextParams[$key]); + } + + return $dedupeResults; + } + /** * Set up a group of dedupable contacts. */ -- 2.25.1