4 * Class CRM_Dedupe_DedupeMergerTest
7 class CRM_Dedupe_MergerTest
extends CiviUnitTestCase
{
10 protected $_contactIds = array();
12 public function tearDown() {
13 $this->quickCleanup(array('civicrm_contact', 'civicrm_group_contact', 'civicrm_group'));
17 public function createDupeContacts() {
18 // create a group to hold contacts, so that dupe checks don't consider any other contacts in the DB
20 'name' => 'Test Dupe Merger Group',
21 'title' => 'Test Dupe Merger Group',
24 'visibility' => 'Public Pages',
27 $result = $this->callAPISuccess('group', 'create', $params);
28 $this->_groupId
= $result['id'];
32 // make dupe checks based on based on following contact sets:
33 // FIRST - LAST - EMAIL
34 // ---------------------------------
35 // robin - hood - robin@example.com
36 // robin - hood - robin@example.com
37 // robin - hood - hood@example.com
38 // robin - dale - robin@example.com
39 // little - dale - dale@example.com
40 // little - dale - dale@example.com
41 // will - dale - dale@example.com
42 // will - dale - will@example.com
43 // will - dale - will@example.com
46 'first_name' => 'robin',
47 'last_name' => 'hood',
48 'email' => 'robin@example.com',
49 'contact_type' => 'Individual',
52 'first_name' => 'robin',
53 'last_name' => 'hood',
54 'email' => 'robin@example.com',
55 'contact_type' => 'Individual',
58 'first_name' => 'robin',
59 'last_name' => 'hood',
60 'email' => 'hood@example.com',
61 'contact_type' => 'Individual',
64 'first_name' => 'robin',
65 'last_name' => 'dale',
66 'email' => 'robin@example.com',
67 'contact_type' => 'Individual',
70 'first_name' => 'little',
71 'last_name' => 'dale',
72 'email' => 'dale@example.com',
73 'contact_type' => 'Individual',
76 'first_name' => 'little',
77 'last_name' => 'dale',
78 'email' => 'dale@example.com',
79 'contact_type' => 'Individual',
82 'first_name' => 'will',
83 'last_name' => 'dale',
84 'email' => 'dale@example.com',
85 'contact_type' => 'Individual',
88 'first_name' => 'will',
89 'last_name' => 'dale',
90 'email' => 'will@example.com',
91 'contact_type' => 'Individual',
94 'first_name' => 'will',
95 'last_name' => 'dale',
96 'email' => 'will@example.com',
97 'contact_type' => 'Individual',
102 foreach ($params as $param) {
103 $param['version'] = 3;
104 $contact = civicrm_api('contact', 'create', $param);
105 $this->_contactIds
[$count++
] = $contact['id'];
108 'contact_id' => $contact['id'],
109 'group_id' => $this->_groupId
,
112 $this->callAPISuccess('group_contact', 'create', $grpParams);
117 * Delete all created contacts.
119 public function deleteDupeContacts() {
120 foreach ($this->_contactIds
as $contactId) {
121 $this->contactDelete($contactId);
123 $this->groupDelete($this->_groupId
);
127 * Test the batch merge.
129 public function testBatchMergeSelectedDuplicates() {
130 $this->createDupeContacts();
132 // verify that all contacts have been created separately
133 $this->assertEquals(count($this->_contactIds
), 9, 'Check for number of contacts.');
135 $dao = new CRM_Dedupe_DAO_RuleGroup();
136 $dao->contact_type
= 'Individual';
137 $dao->name
= 'IndividualSupervised';
138 $dao->is_default
= 1;
141 $foundDupes = CRM_Dedupe_Finder
::dupesInGroup($dao->id
, $this->_groupId
);
143 // -------------------------------------------------------------------------
144 // Name and Email (reserved) Matches ( 3 pairs )
145 // --------------------------------------------------------------------------
146 // robin - hood - robin@example.com
147 // robin - hood - robin@example.com
148 // little - dale - dale@example.com
149 // little - dale - dale@example.com
150 // will - dale - will@example.com
151 // will - dale - will@example.com
152 // so 3 pairs for - first + last + mail
153 $this->assertEquals(count($foundDupes), 3, 'Check Individual-Supervised dupe rule for dupesInGroup().');
155 // Run dedupe finder as the browser would
156 //avoid invalid key error
157 $_SERVER['REQUEST_METHOD'] = 'GET';
158 $object = new CRM_Contact_Page_DedupeFind();
159 $object->set('gid', $this->_groupId
);
160 $object->set('rgid', $dao->id
);
161 $object->set('action', CRM_Core_Action
::UPDATE
);
162 $object->setEmbedded(TRUE);
165 // Retrieve pairs from prev next cache table
166 $select = array('pn.is_selected' => 'is_selected');
167 $cacheKeyString = CRM_Dedupe_Merger
::getMergeCacheKeyString($dao->id
, $this->_groupId
);
168 $pnDupePairs = CRM_Core_BAO_PrevNextCache
::retrieve($cacheKeyString, NULL, NULL, 0, 0, $select);
170 $this->assertEquals(count($foundDupes), count($pnDupePairs), 'Check number of dupe pairs in prev next cache.');
172 // mark first two pairs as selected
173 CRM_Core_DAO
::singleValueQuery("UPDATE civicrm_prevnext_cache SET is_selected = 1 WHERE id IN ({$pnDupePairs[0]['prevnext_id']}, {$pnDupePairs[1]['prevnext_id']})");
175 $pnDupePairs = CRM_Core_BAO_PrevNextCache
::retrieve($cacheKeyString, NULL, NULL, 0, 0, $select);
176 $this->assertEquals($pnDupePairs[0]['is_selected'], 1, 'Check if first record in dupe pairs is marked as selected.');
177 $this->assertEquals($pnDupePairs[0]['is_selected'], 1, 'Check if second record in dupe pairs is marked as selected.');
179 // batch merge selected dupes
180 $result = CRM_Dedupe_Merger
::batchMerge($dao->id
, $this->_groupId
, 'safe', 5, 1);
181 $this->assertEquals(count($result['merged']), 2, 'Check number of merged pairs.');
183 // retrieve pairs from prev next cache table
184 $pnDupePairs = CRM_Core_BAO_PrevNextCache
::retrieve($cacheKeyString, NULL, NULL, 0, 0, $select);
185 $this->assertEquals(count($pnDupePairs), 1, 'Check number of remaining dupe pairs in prev next cache.');
187 $this->deleteDupeContacts();
191 * Test the batch merge.
193 public function testBatchMergeAllDuplicates() {
194 $this->createDupeContacts();
196 // verify that all contacts have been created separately
197 $this->assertEquals(count($this->_contactIds
), 9, 'Check for number of contacts.');
199 $dao = new CRM_Dedupe_DAO_RuleGroup();
200 $dao->contact_type
= 'Individual';
201 $dao->name
= 'IndividualSupervised';
202 $dao->is_default
= 1;
205 $foundDupes = CRM_Dedupe_Finder
::dupesInGroup($dao->id
, $this->_groupId
);
207 // -------------------------------------------------------------------------
208 // Name and Email (reserved) Matches ( 3 pairs )
209 // --------------------------------------------------------------------------
210 // robin - hood - robin@example.com
211 // robin - hood - robin@example.com
212 // little - dale - dale@example.com
213 // little - dale - dale@example.com
214 // will - dale - will@example.com
215 // will - dale - will@example.com
216 // so 3 pairs for - first + last + mail
217 $this->assertEquals(count($foundDupes), 3, 'Check Individual-Supervised dupe rule for dupesInGroup().');
219 // Run dedupe finder as the browser would
220 //avoid invalid key error
221 $_SERVER['REQUEST_METHOD'] = 'GET';
222 $object = new CRM_Contact_Page_DedupeFind();
223 $object->set('gid', $this->_groupId
);
224 $object->set('rgid', $dao->id
);
225 $object->set('action', CRM_Core_Action
::UPDATE
);
226 $object->setEmbedded(TRUE);
229 // Retrieve pairs from prev next cache table
230 $select = array('pn.is_selected' => 'is_selected');
231 $cacheKeyString = CRM_Dedupe_Merger
::getMergeCacheKeyString($dao->id
, $this->_groupId
);
232 $pnDupePairs = CRM_Core_BAO_PrevNextCache
::retrieve($cacheKeyString, NULL, NULL, 0, 0, $select);
234 $this->assertEquals(count($foundDupes), count($pnDupePairs), 'Check number of dupe pairs in prev next cache.');
236 // batch merge all dupes
237 $result = CRM_Dedupe_Merger
::batchMerge($dao->id
, $this->_groupId
, 'safe', 5, 2);
238 $this->assertEquals(count($result['merged']), 3, 'Check number of merged pairs.');
240 // retrieve pairs from prev next cache table
241 $pnDupePairs = CRM_Core_BAO_PrevNextCache
::retrieve($cacheKeyString, NULL, NULL, 0, 0, $select);
242 $this->assertEquals(count($pnDupePairs), 0, 'Check number of remaining dupe pairs in prev next cache.');
244 $this->deleteDupeContacts();
248 * The goal of this function is to test that all required tables are returned.
250 public function testGetCidRefs() {
251 $this->entityCustomGroupWithSingleFieldCreate(__FUNCTION__
, 'Contacts');
252 $this->assertEquals(array_merge($this->getStaticCIDRefs(), $this->getHackedInCIDRef()), CRM_Dedupe_Merger
::cidRefs());
253 $this->assertEquals(array_merge($this->getCalculatedCIDRefs(), $this->getHackedInCIDRef()), CRM_Dedupe_Merger
::cidRefs());
257 * Get the list of not-really-cid-refs that are currently hacked in.
259 * This is hacked into getCIDs function.
263 public function getHackedInCIDRef() {
265 'civicrm_entity_tag' => array(
272 * Test function that gets duplicate pairs.
274 * It turns out there are 2 code paths retrieving this data so my initial focus is on ensuring
277 public function testGetMatches() {
278 $this->setupMatchData();
279 $pairs = CRM_Dedupe_Merger
::getDuplicatePairs(
287 $this->assertEquals(array(
289 'srcID' => $this->contacts
[1]['id'],
290 'srcName' => 'Mr. Mickey Mouse II',
291 'dstID' => $this->contacts
[0]['id'],
292 'dstName' => 'Mr. Mickey Mouse II',
297 'srcID' => $this->contacts
[3]['id'],
298 'srcName' => 'Mr. Minnie Mouse II',
299 'dstID' => $this->contacts
[2]['id'],
300 'dstName' => 'Mr. Minnie Mouse II',
308 * Test function that gets organization pairs.
310 * Note the rule will match on organization_name OR email - hence lots of matches.
312 public function testGetOrganizationMatches() {
313 $this->setupMatchData();
314 $ruleGroups = $this->callAPISuccessGetSingle('RuleGroup', array('contact_type' => 'Organization', 'used' => 'Supervised'));
316 $pairs = CRM_Dedupe_Merger
::getDuplicatePairs(
324 $expectedPairs = array(
326 'srcID' => $this->contacts
[5]['id'],
327 'srcName' => 'Walt Disney Ltd',
328 'dstID' => $this->contacts
[4]['id'],
329 'dstName' => 'Walt Disney Ltd',
334 'srcID' => $this->contacts
[7]['id'],
335 'srcName' => 'Walt Disney',
336 'dstID' => $this->contacts
[6]['id'],
337 'dstName' => 'Walt Disney',
342 'srcID' => $this->contacts
[6]['id'],
343 'srcName' => 'Walt Disney',
344 'dstID' => $this->contacts
[4]['id'],
345 'dstName' => 'Walt Disney Ltd',
350 'srcID' => $this->contacts
[6]['id'],
351 'srcName' => 'Walt Disney',
352 'dstID' => $this->contacts
[5]['id'],
353 'dstName' => 'Walt Disney Ltd',
358 usort($pairs, array(__CLASS__
, 'compareDupes'));
359 usort($expectedPairs, array(__CLASS__
, 'compareDupes'));
360 $this->assertEquals($expectedPairs, $pairs);
364 * Function to sort $duplicate records in a stable way.
370 public static function compareDupes($a, $b) {
371 foreach (array('srcName', 'dstName', 'srcID', 'dstID') as $field) {
372 if ($a[$field] != $b[$field]) {
373 return ($a[$field] < $b[$field]) ?
1 : -1;
380 * Test function that gets organization duplicate pairs.
382 public function testGetOrganizationMatchesInGroup() {
383 $this->setupMatchData();
384 $ruleGroups = $this->callAPISuccessGetSingle('RuleGroup', array('contact_type' => 'Organization', 'used' => 'Supervised'));
386 $groupID = $this->groupCreate(array('title' => 'she-mice'));
388 $this->callAPISuccess('GroupContact', 'create', array('group_id' => $groupID, 'contact_id' => $this->contacts
[4]['id']));
390 $pairs = CRM_Dedupe_Merger
::getDuplicatePairs(
398 $this->assertEquals(array(
400 'srcID' => $this->contacts
[5]['id'],
401 'srcName' => 'Walt Disney Ltd',
402 'dstID' => $this->contacts
[4]['id'],
403 'dstName' => 'Walt Disney Ltd',
408 'srcID' => $this->contacts
[6]['id'],
409 'srcName' => 'Walt Disney',
410 'dstID' => $this->contacts
[4]['id'],
411 'dstName' => 'Walt Disney Ltd',
417 $this->callAPISuccess('GroupContact', 'create', array('group_id' => $groupID, 'contact_id' => $this->contacts
[5]['id']));
418 CRM_Core_DAO
::executeQuery("DELETE FROM civicrm_prevnext_cache");
419 $pairs = CRM_Dedupe_Merger
::getDuplicatePairs(
427 $this->assertEquals(array(
429 'srcID' => $this->contacts
[5]['id'],
430 'srcName' => 'Walt Disney Ltd',
431 'dstID' => $this->contacts
[4]['id'],
432 'dstName' => 'Walt Disney Ltd',
437 'srcID' => $this->contacts
[6]['id'],
438 'srcName' => 'Walt Disney',
439 'dstID' => $this->contacts
[4]['id'],
440 'dstName' => 'Walt Disney Ltd',
445 'srcID' => $this->contacts
[6]['id'],
446 'srcName' => 'Walt Disney',
447 'dstID' => $this->contacts
[5]['id'],
448 'dstName' => 'Walt Disney Ltd',
456 * Test function that gets duplicate pairs.
458 * It turns out there are 2 code paths retrieving this data so my initial focus is on ensuring
461 public function testGetMatchesInGroup() {
462 $this->setupMatchData();
464 $groupID = $this->groupCreate(array('title' => 'she-mice'));
466 $this->callAPISuccess('GroupContact', 'create', array('group_id' => $groupID, 'contact_id' => $this->contacts
[3]['id']));
468 $pairs = CRM_Dedupe_Merger
::getDuplicatePairs(
476 $this->assertEquals(array(
478 'srcID' => $this->contacts
[3]['id'],
479 'srcName' => 'Mr. Minnie Mouse II',
480 'dstID' => $this->contacts
[2]['id'],
481 'dstName' => 'Mr. Minnie Mouse II',
489 * Test migration of Membership.
491 public function testMergeMembership() {
493 $this->setupMatchData();
494 $originalContactID = $this->contacts
[0]['id'];
495 $duplicateContactID = $this->contacts
[1]['id'];
497 //Add Membership for the duplicate contact.
498 $memTypeId = $this->membershipTypeCreate();
499 $membership = $this->callAPISuccess('Membership', 'create', [
500 'membership_type_id' => $memTypeId,
501 'contact_id' => $duplicateContactID,
503 //Assert if 'add new' checkbox is enabled on the merge form.
504 $rowsElementsAndInfo = CRM_Dedupe_Merger
::getRowsElementsAndInfo($originalContactID, $duplicateContactID);
505 foreach ($rowsElementsAndInfo['elements'] as $element) {
506 if (!empty($element[3]) && $element[3] == 'add new') {
507 $checkedAttr = ['checked' => 'checked'];
508 $this->checkArrayEquals($element[4], $checkedAttr);
512 //Merge and move the mem to the main contact.
513 $this->mergeContacts($originalContactID, $duplicateContactID, [
514 'move_rel_table_memberships' => 1,
515 'operation' => ['move_rel_table_memberships' => ['add' => 1]],
518 //Check if membership is correctly transferred to original contact.
519 $originalContactMembership = $this->callAPISuccess('Membership', 'get', [
520 'membership_type_id' => $memTypeId,
521 'contact_id' => $originalContactID,
523 $this->assertEquals(1, $originalContactMembership['count']);
527 * CRM-19653 : Test that custom field data should/shouldn't be overriden on
528 * selecting/not selecting option to migrate data respectively
530 public function testCustomDataOverwrite() {
531 // Create Custom Field
532 $createGroup = $this->setupCustomGroupForIndividual();
533 $createField = $this->setupCustomField('Graduation', $createGroup);
534 $customFieldName = "custom_" . $createField['id'];
537 $this->setupMatchData();
539 $originalContactID = $this->contacts
[0]['id'];
540 // used as duplicate contact in 1st use-case
541 $duplicateContactID1 = $this->contacts
[1]['id'];
542 // used as duplicate contact in 2nd use-case
543 $duplicateContactID2 = $this->contacts
[2]['id'];
545 // update the text custom field for original contact with value 'abc'
546 $this->callAPISuccess('Contact', 'create', array(
547 'id' => $originalContactID,
548 "{$customFieldName}" => 'abc',
550 $this->assertCustomFieldValue($originalContactID, 'abc', $customFieldName);
552 // update the text custom field for duplicate contact 1 with value 'def'
553 $this->callAPISuccess('Contact', 'create', array(
554 'id' => $duplicateContactID1,
555 "{$customFieldName}" => 'def',
557 $this->assertCustomFieldValue($duplicateContactID1, 'def', $customFieldName);
559 // update the text custom field for duplicate contact 2 with value 'ghi'
560 $this->callAPISuccess('Contact', 'create', array(
561 'id' => $duplicateContactID2,
562 "{$customFieldName}" => 'ghi',
564 $this->assertCustomFieldValue($duplicateContactID2, 'ghi', $customFieldName);
566 /*** USE-CASE 1: DO NOT OVERWRITE CUSTOM FIELD VALUE **/
567 $this->mergeContacts($originalContactID, $duplicateContactID1, array(
568 "move_{$customFieldName}" => NULL,
570 $this->assertCustomFieldValue($originalContactID, 'abc', $customFieldName);
572 /*** USE-CASE 2: OVERWRITE CUSTOM FIELD VALUE **/
573 $this->mergeContacts($originalContactID, $duplicateContactID2, array(
574 "move_{$customFieldName}" => 'ghi',
576 $this->assertCustomFieldValue($originalContactID, 'ghi', $customFieldName);
578 // cleanup created custom set
579 $this->callAPISuccess('CustomField', 'delete', array('id' => $createField['id']));
580 $this->callAPISuccess('CustomGroup', 'delete', array('id' => $createGroup['id']));
584 * Verifies that when a contact with a custom field value is merged into a
585 * contact without a record int its corresponding custom group table, and none
586 * of the custom fields of that custom table are selected, the value is not
589 public function testMigrationOfUnselectedCustomDataOnEmptyCustomRecord() {
590 // Create Custom Fields
591 $createGroup = $this->setupCustomGroupForIndividual();
592 $customField1 = $this->setupCustomField('TestField', $createGroup);
594 // Create multi-value custom field
595 $multiGroup = $this->CustomGroupMultipleCreateByParams();
596 $multiField = $this->customFieldCreate(array(
597 'custom_group_id' => $multiGroup['id'],
598 'label' => 'field_1' . $multiGroup['id'],
603 $this->setupMatchData();
604 $originalContactID = $this->contacts
[0]['id'];
605 $duplicateContactID = $this->contacts
[1]['id'];
607 // Update the text custom fields for duplicate contact
608 $this->callAPISuccess('Contact', 'create', array(
609 'id' => $duplicateContactID,
610 "custom_{$customField1['id']}" => 'abc',
611 "custom_{$multiField['id']}" => 'def',
613 $this->assertCustomFieldValue($duplicateContactID, 'abc', "custom_{$customField1['id']}");
614 $this->assertCustomFieldValue($duplicateContactID, 'def', "custom_{$multiField['id']}");
616 // Merge, and ensure that no value was migrated
617 $this->mergeContacts($originalContactID, $duplicateContactID, array(
618 "move_custom_{$customField1['id']}" => NULL,
619 "move_rel_table_custom_{$multiGroup['id']}" => NULL,
621 $this->assertCustomFieldValue($originalContactID, '', "custom_{$customField1['id']}");
622 $this->assertCustomFieldValue($originalContactID, '', "custom_{$multiField['id']}");
624 // cleanup created custom set
625 $this->callAPISuccess('CustomField', 'delete', array('id' => $customField1['id']));
626 $this->callAPISuccess('CustomGroup', 'delete', array('id' => $createGroup['id']));
627 $this->callAPISuccess('CustomField', 'delete', array('id' => $multiField['id']));
628 $this->callAPISuccess('CustomGroup', 'delete', array('id' => $multiGroup['id']));
632 * Tests that if only part of the custom fields of a custom group are selected
633 * for a merge, only those values are merged, while all other fields of the
634 * custom group retain their original value, specifically for a contact with
635 * no records on the custom group table.
637 public function testMigrationOfSomeCustomDataOnEmptyCustomRecord() {
638 // Create Custom Fields
639 $createGroup = $this->setupCustomGroupForIndividual();
640 $customField1 = $this->setupCustomField('Test1', $createGroup);
641 $customField2 = $this->setupCustomField('Test2', $createGroup);
643 // Create multi-value custom field
644 $multiGroup = $this->CustomGroupMultipleCreateByParams();
645 $multiField = $this->customFieldCreate(array(
646 'custom_group_id' => $multiGroup['id'],
647 'label' => 'field_1' . $multiGroup['id'],
652 $this->setupMatchData();
653 $originalContactID = $this->contacts
[0]['id'];
654 $duplicateContactID = $this->contacts
[1]['id'];
656 // Update the text custom fields for duplicate contact
657 $this->callAPISuccess('Contact', 'create', array(
658 'id' => $duplicateContactID,
659 "custom_{$customField1['id']}" => 'abc',
660 "custom_{$customField2['id']}" => 'def',
661 "custom_{$multiField['id']}" => 'ghi',
663 $this->assertCustomFieldValue($duplicateContactID, 'abc', "custom_{$customField1['id']}");
664 $this->assertCustomFieldValue($duplicateContactID, 'def', "custom_{$customField2['id']}");
665 $this->assertCustomFieldValue($duplicateContactID, 'ghi', "custom_{$multiField['id']}");
668 $this->mergeContacts($originalContactID, $duplicateContactID, array(
669 "move_custom_{$customField1['id']}" => NULL,
670 "move_custom_{$customField2['id']}" => 'def',
671 "move_rel_table_custom_{$multiGroup['id']}" => '1',
673 $this->assertCustomFieldValue($originalContactID, '', "custom_{$customField1['id']}");
674 $this->assertCustomFieldValue($originalContactID, 'def', "custom_{$customField2['id']}");
675 $this->assertCustomFieldValue($originalContactID, 'ghi', "custom_{$multiField['id']}");
677 // cleanup created custom set
678 $this->callAPISuccess('CustomField', 'delete', array('id' => $customField1['id']));
679 $this->callAPISuccess('CustomField', 'delete', array('id' => $customField2['id']));
680 $this->callAPISuccess('CustomGroup', 'delete', array('id' => $createGroup['id']));
681 $this->callAPISuccess('CustomField', 'delete', array('id' => $multiField['id']));
682 $this->callAPISuccess('CustomGroup', 'delete', array('id' => $multiGroup['id']));
686 * Calls merge method on given contacts, with values given in $params array.
688 * @param $originalContactID
689 * ID of target contact
690 * @param $duplicateContactID
691 * ID of contact to be merged
693 * Array of fields to be merged from source into target contact, of the form
694 * ['move_<fieldName>' => <fieldValue>]
696 private function mergeContacts($originalContactID, $duplicateContactID, $params) {
697 $rowsElementsAndInfo = CRM_Dedupe_Merger
::getRowsElementsAndInfo($originalContactID, $duplicateContactID);
699 $migrationData = array(
700 'main_details' => $rowsElementsAndInfo['main_details'],
701 'other_details' => $rowsElementsAndInfo['other_details'],
704 // Migrate data of duplicate contact
705 CRM_Dedupe_Merger
::moveAllBelongings($originalContactID, $duplicateContactID, array_merge($migrationData, $params));
709 * Checks if the expected value for the given field corresponds to what is
710 * stored in the database for the given contact ID.
713 * @param $expectedValue
714 * @param $customFieldName
716 private function assertCustomFieldValue($contactID, $expectedValue, $customFieldName) {
717 $data = $this->callAPISuccess('Contact', 'getsingle', array(
719 'return' => array($customFieldName),
722 $this->assertEquals($expectedValue, $data[$customFieldName], "Custom field value was supposed to be '{$expectedValue}', '{$data[$customFieldName]}' found.");
726 * Creates a custom group to run tests on contacts that are individuals.
729 * Data for the created custom group record
731 private function setupCustomGroupForIndividual() {
732 $customGroup = $this->callAPISuccess('custom_group', 'get', array(
733 'name' => 'test_group',
736 if ($customGroup['count'] > 0) {
737 $this->callAPISuccess('CustomGroup', 'delete', array('id' => $customGroup['id']));
740 $customGroup = $this->callAPISuccess('custom_group', 'create', array(
741 'title' => 'Test_Group',
742 'name' => 'test_group',
743 'extends' => array('Individual'),
745 'is_multiple' => FALSE,
753 * Creates a custom field on the provided custom group with the given field
757 * @param $createGroup
760 * Data for the created custom field record
762 private function setupCustomField($fieldLabel, $createGroup) {
763 return $this->callAPISuccess('custom_field', 'create', array(
764 'label' => $fieldLabel,
765 'data_type' => 'Alphanumeric',
766 'html_type' => 'Text',
767 'custom_group_id' => $createGroup['id'],
772 * Set up some contacts for our matching.
774 public function setupMatchData() {
777 'first_name' => 'Mickey',
778 'last_name' => 'Mouse',
779 'email' => 'mickey@mouse.com',
782 'first_name' => 'Mickey',
783 'last_name' => 'Mouse',
784 'email' => 'mickey@mouse.com',
787 'first_name' => 'Minnie',
788 'last_name' => 'Mouse',
789 'email' => 'mickey@mouse.com',
792 'first_name' => 'Minnie',
793 'last_name' => 'Mouse',
794 'email' => 'mickey@mouse.com',
797 foreach ($fixtures as $fixture) {
798 $contactID = $this->individualCreate($fixture);
799 $this->contacts
[] = array_merge($fixture, array('id' => $contactID));
801 $organizationFixtures = array(
803 'organization_name' => 'Walt Disney Ltd',
804 'email' => 'walt@disney.com',
807 'organization_name' => 'Walt Disney Ltd',
808 'email' => 'walt@disney.com',
811 'organization_name' => 'Walt Disney',
812 'email' => 'walt@disney.com',
815 'organization_name' => 'Walt Disney',
816 'email' => 'walter@disney.com',
819 foreach ($organizationFixtures as $fixture) {
820 $contactID = $this->organizationCreate($fixture);
821 $this->contacts
[] = array_merge($fixture, array('id' => $contactID));
826 * Get the list of tables that refer to the CID.
828 * This is a statically maintained (in this test list).
830 * There is also a check against an automated list but having both seems to add extra stability to me. They do
833 public function getStaticCIDRefs() {
835 'civicrm_acl_cache' => array(
838 'civicrm_acl_contact_cache' => array(
841 'civicrm_action_log' => array(
844 'civicrm_activity_contact' => array(
847 'civicrm_address' => array(
850 'civicrm_batch' => array(
854 'civicrm_campaign' => array(
856 1 => 'last_modified_id',
858 'civicrm_case_contact' => array(
861 'civicrm_contact' => array(
862 0 => 'primary_contact_id',
865 'civicrm_contribution' => array(
868 'civicrm_contribution_page' => array(
871 'civicrm_contribution_recur' => array(
874 'civicrm_contribution_soft' => array(
877 'civicrm_custom_group' => array(
880 'civicrm_dashboard_contact' => array(
883 'civicrm_dedupe_exception' => array(
887 'civicrm_domain' => array(
890 'civicrm_email' => array(
893 'civicrm_event' => array(
896 'civicrm_event_carts' => array(
899 'civicrm_financial_account' => array(
902 'civicrm_financial_item' => array(
905 'civicrm_grant' => array(
908 'civicrm_group' => array(
912 'civicrm_group_contact' => array(
915 'civicrm_group_contact_cache' => array(
918 'civicrm_group_organization' => array(
919 0 => 'organization_id',
921 'civicrm_im' => array(
924 'civicrm_log' => array(
927 'civicrm_mailing' => array(
932 'civicrm_file' => array(
935 'civicrm_mailing_abtest' => array(
938 'civicrm_mailing_event_queue' => array(
941 'civicrm_mailing_event_subscribe' => array(
944 'civicrm_mailing_recipients' => array(
947 'civicrm_membership' => array(
950 'civicrm_membership_log' => array(
953 'civicrm_membership_type' => array(
954 0 => 'member_of_contact_id',
956 'civicrm_note' => array(
959 'civicrm_openid' => array(
962 'civicrm_participant' => array(
965 1 => 'transferred_to_contact_id',
967 'civicrm_payment_token' => array(
971 'civicrm_pcp' => array(
974 'civicrm_phone' => array(
977 'civicrm_pledge' => array(
980 'civicrm_print_label' => array(
983 'civicrm_relationship' => array(
987 'civicrm_report_instance' => array(
991 'civicrm_setting' => array(
995 'civicrm_subscription_history' => array(
998 'civicrm_survey' => array(
1000 1 => 'last_modified_id',
1002 'civicrm_tag' => array(
1005 'civicrm_uf_group' => array(
1008 'civicrm_uf_match' => array(
1011 'civicrm_value_testgetcidref_1' => array(
1014 'civicrm_website' => array(
1021 * Get a list of CIDs that is calculated off the schema.
1023 * Note this is an expensive and table locking query. Should be safe in tests though.
1025 public function getCalculatedCIDRefs() {
1031 FROM information_schema.key_column_usage
1033 referenced_table_schema = database() AND
1034 referenced_table_name = 'civicrm_contact' AND
1035 referenced_column_name = 'id';
1037 $dao = CRM_Core_DAO
::executeQuery($sql);
1038 while ($dao->fetch()) {
1039 $cidRefs[$dao->table_name
][] = $dao->column_name
;
1041 // Do specific re-ordering changes to make this the same as the ref validated one.
1042 // The above query orders by FK alphabetically.
1043 // There might be cleverer ways to do this but it shouldn't change much.
1044 $cidRefs['civicrm_contact'][0] = 'primary_contact_id';
1045 $cidRefs['civicrm_contact'][1] = 'employer_id';
1046 $cidRefs['civicrm_acl_contact_cache'][0] = 'contact_id';
1047 $cidRefs['civicrm_mailing'][0] = 'created_id';
1048 $cidRefs['civicrm_mailing'][1] = 'scheduled_id';
1049 $cidRefs['civicrm_mailing'][2] = 'approver_id';