4 * Class CRM_Dedupe_DedupeFinderTest
7 class CRM_Dedupe_DedupeFinderTest
extends CiviUnitTestCase
{
10 * IDs of created contacts.
14 protected $contactIDs = [];
17 * ID of the group holding the contacts.
24 * Clean up after the test.
26 public function tearDown() {
28 foreach ($this->contactIDs
as $contactId) {
29 $this->contactDelete($contactId);
32 $this->callAPISuccess('group', 'delete', ['id' => $this->groupID
]);
38 * Test the unsupervised dedupe rule against a group.
42 public function testUnsupervisedDupes() {
43 // make dupe checks based on following contact sets:
44 // FIRST - LAST - EMAIL
45 // ---------------------------------
46 // robin - hood - robin@example.com
47 // robin - hood - hood@example.com
48 // robin - dale - robin@example.com
49 // little - dale - dale@example.com
50 // will - dale - dale@example.com
51 // will - dale - will@example.com
52 // will - dale - will@example.com
53 $this->setupForGroupDedupe();
55 $ruleGroup = $this->callAPISuccessGetSingle('RuleGroup', ['is_reserved' => 1, 'contact_type' => 'Individual', 'used' => 'Unsupervised']);
57 $foundDupes = CRM_Dedupe_Finder
::dupesInGroup($ruleGroup['id'], $this->groupID
);
58 $this->assertEquals(count($foundDupes), 3, 'Check Individual-Fuzzy dupe rule for dupesInGroup().');
62 * Test duplicate contact retrieval with 2 email fields.
64 public function testUnsupervisedWithTwoEmailFields() {
65 $this->setupForGroupDedupe();
67 ['hood@example.com', ''],
68 ['', 'hood@example.com'],
70 for ($i = 0; $i < 2; $i++
) {
72 'first_name' => 'robin',
73 'last_name' => 'hood',
74 'email-1' => $emails[$i][0],
75 'email-2' => $emails[$i][1],
77 $dedupeParams = CRM_Dedupe_Finder
::formatParams($fields, 'Individual');
78 $dedupeResults = CRM_Dedupe_Finder
::dupesByParams($dedupeParams, 'Individual');
79 $this->assertEquals(count($dedupeResults), 1);
84 * Test that a rule set to is_reserved = 0 works.
86 * There is a different search used dependent on this variable.
88 public function testCustomRule() {
89 $this->setupForGroupDedupe();
91 $ruleGroup = $this->callAPISuccess('RuleGroup', 'create', [
92 'contact_type' => 'Individual',
96 'title' => 'TestRule',
100 foreach (['birth_date', 'first_name', 'last_name'] as $field) {
101 $rules[$field] = $this->callAPISuccess('Rule', 'create', [
102 'dedupe_rule_group_id' => $ruleGroup['id'],
103 'rule_table' => 'civicrm_contact',
105 'rule_field' => $field,
108 $foundDupes = CRM_Dedupe_Finder
::dupesInGroup($ruleGroup['id'], $this->groupID
);
109 $this->assertEquals(count($foundDupes), 4);
110 CRM_Dedupe_Finder
::dupes($ruleGroup['id']);
115 * Test a custom rule with a non-default field.
117 public function testCustomRuleWithAddress() {
118 $this->setupForGroupDedupe();
120 $ruleGroup = $this->callAPISuccess('RuleGroup', 'create', [
121 'contact_type' => 'Individual',
124 'name' => 'TestRule',
125 'title' => 'TestRule',
129 foreach (['postal_code'] as $field) {
130 $rules[$field] = $this->callAPISuccess('Rule', 'create', [
131 'dedupe_rule_group_id' => $ruleGroup['id'],
132 'rule_table' => 'civicrm_address',
134 'rule_field' => $field,
137 $foundDupes = CRM_Dedupe_Finder
::dupesInGroup($ruleGroup['id'], $this->groupID
);
138 $this->assertEquals(count($foundDupes), 1);
139 CRM_Dedupe_Finder
::dupes($ruleGroup['id']);
144 * Test a custom rule with a non-default field.
146 public function testInclusiveRule() {
147 $this->setupForGroupDedupe();
149 $ruleGroup = $this->callAPISuccess('RuleGroup', 'create', [
150 'contact_type' => 'Individual',
153 'name' => 'TestRule',
154 'title' => 'TestRule',
158 foreach (['first_name', 'last_name'] as $field) {
159 $rules[$field] = $this->callAPISuccess('Rule', 'create', [
160 'dedupe_rule_group_id' => $ruleGroup['id'],
161 'rule_table' => 'civicrm_contact',
163 'rule_field' => $field,
166 $foundDupes = CRM_Dedupe_Finder
::dupesInGroup($ruleGroup['id'], $this->groupID
);
167 $this->assertEquals(4, count($foundDupes));
168 CRM_Dedupe_Finder
::dupes($ruleGroup['id']);
172 * Test the supervised dedupe rule against a group.
176 public function testSupervisedDupes() {
177 $this->setupForGroupDedupe();
178 $ruleGroup = $this->callAPISuccessGetSingle('RuleGroup', ['is_reserved' => 1, 'contact_type' => 'Individual', 'used' => 'Supervised']);
179 $foundDupes = CRM_Dedupe_Finder
::dupesInGroup($ruleGroup['id'], $this->groupID
);
180 // -------------------------------------------------------------------------
181 // default dedupe rule: threshold = 20 => (First + Last + Email) Matches ( 1 pair )
182 // --------------------------------------------------------------------------
183 // will - dale - will@example.com
184 // will - dale - will@example.com
185 // so 1 pair for - first + last + mail
186 $this->assertEquals(count($foundDupes), 1, 'Check Individual-Fuzzy dupe rule for dupesInGroup().');
190 * Test dupesByParams function.
192 public function testDupesByParams() {
193 // make dupe checks based on based on following contact sets:
194 // FIRST - LAST - EMAIL
195 // ---------------------------------
196 // robin - hood - robin@example.com
197 // robin - hood - hood@example.com
198 // robin - dale - robin@example.com
199 // little - dale - dale@example.com
200 // will - dale - dale@example.com
201 // will - dale - will@example.com
202 // will - dale - will@example.com
205 // FIXME: move create params to separate function
208 'first_name' => 'robin',
209 'last_name' => 'hood',
210 'email' => 'robin@example.com',
211 'contact_type' => 'Individual',
214 'first_name' => 'robin',
215 'last_name' => 'hood',
216 'email' => 'hood@example.com',
217 'contact_type' => 'Individual',
220 'first_name' => 'robin',
221 'last_name' => 'dale',
222 'email' => 'robin@example.com',
223 'contact_type' => 'Individual',
226 'first_name' => 'little',
227 'last_name' => 'dale',
228 'email' => 'dale@example.com',
229 'contact_type' => 'Individual',
232 'first_name' => 'will',
233 'last_name' => 'dale',
234 'email' => 'dale@example.com',
235 'contact_type' => 'Individual',
238 'first_name' => 'will',
239 'last_name' => 'dale',
240 'email' => 'will@example.com',
241 'contact_type' => 'Individual',
244 'first_name' => 'will',
245 'last_name' => 'dale',
246 'email' => 'will@example.com',
247 'contact_type' => 'Individual',
251 $this->hookClass
->setHook('civicrm_findDuplicates', [$this, 'hook_civicrm_findDuplicates']);
255 foreach ($params as $param) {
256 $contact = $this->callAPISuccess('contact', 'create', $param);
258 'contact_id' => $contact['id'],
259 'street_address' => 'Ambachtstraat 23',
260 'location_type_id' => 1,
262 $this->callAPISuccess('address', 'create', $params);
263 $contactIds[$count++
] = $contact['id'];
266 // verify that all contacts have been created separately
267 $this->assertEquals(count($contactIds), 7, 'Check for number of contacts.');
270 'first_name' => 'robin',
271 'last_name' => 'hood',
272 'email' => 'hood@example.com',
273 'street_address' => 'Ambachtstraat 23',
275 CRM_Core_TemporaryErrorScope
::useException();
276 $ids = CRM_Contact_BAO_Contact
::getDuplicateContacts($fields, 'Individual', 'General', [], TRUE, NULL, ['event_id' => 1]);
278 // Check with default Individual-General rule
279 $this->assertEquals(count($ids), 2, 'Check Individual-General rule for dupesByParams().');
281 // delete all created contacts
282 foreach ($contactIds as $contactId) {
283 $this->contactDelete($contactId);
288 * Implements hook_civicrm_findDuplicates().
290 * Locks in expected params
293 public function hook_civicrm_findDuplicates($dedupeParams, &$dedupeResults, $contextParams) {
294 $expectedDedupeParams = [
295 'check_permission' => TRUE,
296 'contact_type' => 'Individual',
298 'rule_group_id' => NULL,
299 'excluded_contact_ids' => [],
301 foreach ($expectedDedupeParams as $key => $value) {
302 $this->assertEquals($value, $dedupeParams[$key]);
304 $expectedDedupeResults = [
308 foreach ($expectedDedupeResults as $key => $value) {
309 $this->assertEquals($value, $dedupeResults[$key]);
312 $expectedContext = ['event_id' => 1];
313 foreach ($expectedContext as $key => $value) {
314 $this->assertEquals($value, $contextParams[$key]);
317 return $dedupeResults;
321 * Set up a group of dedupable contacts.
323 protected function setupForGroupDedupe() {
325 'name' => 'Dupe Group',
326 'title' => 'New Test Dupe Group',
329 'visibility' => 'Public Pages',
332 $result = $this->callAPISuccess('group', 'create', $params);
333 $this->groupID
= $result['id'];
337 'first_name' => 'robin',
338 'last_name' => 'hood',
339 'email' => 'robin@example.com',
340 'contact_type' => 'Individual',
341 'birth_date' => '2016-01-01',
342 'api.Address.create' => ['street_address' => '123 Happy world', 'location_type_id' => 'Billing', 'postal_code' => '99999'],
345 'first_name' => 'robin',
346 'last_name' => 'hood',
347 'email' => 'hood@example.com',
348 'contact_type' => 'Individual',
349 'birth_date' => '2016-01-01',
350 'api.Address.create' => ['street_address' => '123 Happy World', 'location_type_id' => 'Billing', 'postal_code' => '99999'],
353 'first_name' => 'robin',
354 'last_name' => 'dale',
355 'email' => 'robin@example.com',
356 'contact_type' => 'Individual',
359 'first_name' => 'little',
360 'last_name' => 'dale',
361 'email' => 'dale@example.com',
362 'contact_type' => 'Individual',
365 'first_name' => 'will',
366 'last_name' => 'dale',
367 'email' => 'dale@example.com',
368 'contact_type' => 'Individual',
371 'first_name' => 'will',
372 'last_name' => 'dale',
373 'email' => 'will@example.com',
374 'contact_type' => 'Individual',
377 'first_name' => 'will',
378 'last_name' => 'dale',
379 'email' => 'will@example.com',
380 'contact_type' => 'Individual',
385 foreach ($params as $param) {
386 $contact = $this->callAPISuccess('contact', 'create', $param);
387 $this->contactIDs
[$count++
] = $contact['id'];
390 'contact_id' => $contact['id'],
391 'group_id' => $this->groupID
,
393 $this->callAPISuccess('group_contact', 'create', $grpParams);
396 // verify that all contacts have been created separately
397 $this->assertEquals(count($this->contactIDs
), 7, 'Check for number of contacts.');