4 * File for the TestContact class.
8 * @author Walt Haas <walt@dharmatech.org> (801) 534-1262
9 * @copyright Copyright CiviCRM LLC (C) 2009
10 * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html
11 * GNU Affero General Public License version 3
12 * @version $Id: ContactTest.php 31254 2010-12-15 10:09:29Z eileen $
15 * This file is part of CiviCRM
17 * CiviCRM is free software; you can redistribute it and/or
18 * modify it under the terms of the GNU Affero General Public License
19 * as published by the Free Software Foundation; either version 3 of
20 * the License, or (at your option) any later version.
22 * CiviCRM is distributed in the hope that it will be useful,
23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 * GNU Affero General Public License for more details.
27 * You should have received a copy of the GNU Affero General Public
28 * License along with this program. If not, see
29 * <http://www.gnu.org/licenses/>.
33 * Test APIv3 civicrm_contact* functions
35 * @package CiviCRM_APIv3
36 * @subpackage API_Contact
39 class api_v3_ContactTest
extends CiviUnitTestCase
{
41 use CRMTraits_Custom_CustomDataTrait
;
43 public $DBResetRequired = FALSE;
45 protected $_apiversion;
51 protected $_contactID;
53 protected $_financialTypeId = 1;
57 * Entity to be extended.
61 protected $entity = 'Contact';
64 * Test setup for every test.
66 * Connect to the database, truncate the tables that will be used
67 * and redirect stdin to a temporary file
69 public function setUp() {
70 // Connect to the database.
72 $this->_entity
= 'contact';
74 'first_name' => 'abc1',
75 'contact_type' => 'Individual',
76 'last_name' => 'xyz1',
81 * Restore the DB for the next test.
85 public function tearDown() {
86 $this->_apiversion
= 3;
87 $this->callAPISuccess('Setting', 'create', ['includeOrderByClause' => TRUE]);
88 // truncate a few tables
91 'civicrm_contribution',
94 'civicrm_relationship',
98 'civicrm_acl_contact_cache',
99 'civicrm_activity_contact',
102 'civicrm_group_contact',
103 'civicrm_saved_search',
104 'civicrm_group_contact_cache',
105 'civicrm_prevnext_cache',
108 $this->quickCleanup($tablesToTruncate, TRUE);
113 * Test civicrm_contact_create.
115 * Verify that attempt to create individual contact with only
116 * first and last names succeeds
118 * @param int $version
120 * @dataProvider versionThreeAndFour
122 public function testAddCreateIndividual($version) {
123 $this->_apiversion
= $version;
124 $oldCount = CRM_Core_DAO
::singleValueQuery('select count(*) from civicrm_contact');
126 'first_name' => 'abc1',
127 'contact_type' => 'Individual',
128 'last_name' => 'xyz1',
131 $contact = $this->callAPISuccess('contact', 'create', $params);
132 $this->assertTrue(is_numeric($contact['id']));
133 $this->assertTrue($contact['id'] > 0);
134 $newCount = CRM_Core_DAO
::singleValueQuery('select count(*) from civicrm_contact');
135 $this->assertEquals($oldCount +
1, $newCount);
137 $this->assertDBState('CRM_Contact_DAO_Contact',
144 * Test that it is possible to prevent cache clearing via option.
146 * Cache clearing is bypassed if 'options' => array('do_not_reset_cache' => 1 is used.
148 public function testCreateIndividualNoCacheClear() {
150 $contact = $this->callAPISuccess('contact', 'create', $this->_params
);
151 $groupID = $this->groupCreate();
153 $this->putGroupContactCacheInClearableState($groupID, $contact);
155 $this->callAPISuccess('contact', 'create', ['id' => $contact['id']]);
156 $this->assertEquals(0, CRM_Core_DAO
::singleValueQuery("SELECT count(*) FROM civicrm_group_contact_cache"));
158 // Rinse & repeat, but with the option.
159 $this->putGroupContactCacheInClearableState($groupID, $contact);
160 CRM_Core_Config
::setPermitCacheFlushMode(FALSE);
161 $this->callAPISuccess('contact', 'create', ['id' => $contact['id']]);
162 $this->assertEquals(1, CRM_Core_DAO
::singleValueQuery("SELECT count(*) FROM civicrm_group_contact_cache"));
163 CRM_Core_Config
::setPermitCacheFlushMode(TRUE);
167 * Test for international string acceptance (CRM-10210).
168 * Requires the databsase to be in utf8.
170 * @dataProvider getInternationalStrings
172 * @param string $string
173 * String to be tested.
175 * Bool to see if we should check charset.
179 public function testInternationalStrings($string) {
180 $this->callAPISuccess('Contact', 'create', array_merge(
182 ['first_name' => $string]
185 $result = $this->callAPISuccessGetSingle('Contact', ['first_name' => $string]);
186 $this->assertEquals($string, $result['first_name']);
188 $organizationParams = [
189 'organization_name' => $string,
190 'contact_type' => 'Organization',
193 $this->callAPISuccess('Contact', 'create', $organizationParams);
194 $result = $this->callAPISuccessGetSingle('Contact', $organizationParams);
195 $this->assertEquals($string, $result['organization_name']);
199 * Get international string data for testing against api calls.
201 public function getInternationalStrings() {
203 $invocations[] = ['Scarabée'];
204 $invocations[] = ['Iñtërnâtiônàlizætiøn'];
205 $invocations[] = ['これは日本語のテキストです。読めますか'];
206 $invocations[] = ['देखें हिन्दी कैसी नजर आती है। अरे वाह ये तो नजर आती है।'];
211 * Test civicrm_contact_create.
213 * Verify that preferred language can be set.
215 * @param int $version
217 * @dataProvider versionThreeAndFour
219 public function testAddCreateIndividualWithPreferredLanguage($version) {
220 $this->_apiversion
= $version;
222 'first_name' => 'abc1',
223 'contact_type' => 'Individual',
224 'last_name' => 'xyz1',
225 'preferred_language' => 'es_ES',
228 $contact = $this->callAPISuccess('contact', 'create', $params);
229 $this->getAndCheck($params, $contact['id'], 'Contact');
233 * Test civicrm_contact_create with sub-types.
235 * Verify that sub-types are created successfully and not deleted by subsequent updates.
237 * @param int $version
239 * @dataProvider versionThreeAndFour
241 public function testIndividualSubType($version) {
242 $this->_apiversion
= $version;
244 'first_name' => 'test abc',
245 'contact_type' => 'Individual',
246 'last_name' => 'test xyz',
247 'contact_sub_type' => ['Student', 'Staff'],
249 $contact = $this->callAPISuccess('contact', 'create', $params);
250 $cid = $contact['id'];
254 'middle_name' => 'foo',
256 $this->callAPISuccess('contact', 'create', $params);
258 $contact = $this->callAPISuccess('contact', 'get', ['id' => $cid]);
260 $this->assertEquals(['Student', 'Staff'], $contact['values'][$cid]['contact_sub_type']);
262 $this->callAPISuccess('Contact', 'create', [
264 'contact_sub_type' => [],
267 $contact = $this->callAPISuccess('contact', 'get', ['id' => $cid]);
268 $this->assertTrue(empty($contact['values'][$cid]['contact_sub_type']));
272 * Verify that we can retreive contacts of different sub types
274 * @param int $version
276 * @dataProvider versionThreeAndFour
278 public function testGetMultipleContactSubTypes($version) {
279 $this->_apiversion
= $version;
281 // This test presumes that there are no parents or students in the dataset
284 $student = $this->callAPISuccess('contact', 'create', [
285 'email' => 'student@example.com',
286 'contact_type' => 'Individual',
287 'contact_sub_type' => 'Student',
291 $parent = $this->callAPISuccess('contact', 'create', [
292 'email' => 'parent@example.com',
293 'contact_type' => 'Individual',
294 'contact_sub_type' => 'Parent',
298 $this->callAPISuccess('contact', 'create', [
299 'email' => 'parent@example.com',
300 'contact_type' => 'Individual',
303 // get all students and parents
304 $getParams = ['contact_sub_type' => ['IN' => ['Parent', 'Student']]];
305 $result = civicrm_api3('contact', 'get', $getParams);
307 // check that we retrieved the student and the parent
308 $this->assertArrayHasKey($student['id'], $result['values']);
309 $this->assertArrayHasKey($parent['id'], $result['values']);
310 $this->assertEquals(2, $result['count']);
315 * Verify that attempt to create contact with empty params fails.
317 public function testCreateEmptyContact() {
318 $this->callAPIFailure('contact', 'create', []);
322 * Verify that attempt to create contact with bad contact type fails.
324 public function testCreateBadTypeContact() {
326 'email' => 'man1@yahoo.com',
327 'contact_type' => 'Does not Exist',
329 $this->callAPIFailure('contact', 'create', $params, "'Does not Exist' is not a valid option for field contact_type");
333 * Verify that attempt to create individual contact without required fields fails.
335 public function testCreateBadRequiredFieldsIndividual() {
337 'middle_name' => 'This field is not required',
338 'contact_type' => 'Individual',
340 $this->callAPIFailure('contact', 'create', $params);
344 * Verify that attempt to create household contact without required fields fails.
346 public function testCreateBadRequiredFieldsHousehold() {
348 'middle_name' => 'This field is not required',
349 'contact_type' => 'Household',
351 $this->callAPIFailure('contact', 'create', $params);
355 * Test required field check.
357 * Verify that attempt to create organization contact without required fields fails.
359 public function testCreateBadRequiredFieldsOrganization() {
361 'middle_name' => 'This field is not required',
362 'contact_type' => 'Organization',
365 $this->callAPIFailure('contact', 'create', $params);
369 * Verify that attempt to create individual contact with only an email succeeds.
371 public function testCreateEmailIndividual() {
372 $primaryEmail = 'man3@yahoo.com';
373 $notPrimaryEmail = 'man4@yahoo.com';
375 'email' => $primaryEmail,
376 'contact_type' => 'Individual',
377 'location_type_id' => 1,
380 $contact1 = $this->callAPISuccess('contact', 'create', $params);
382 $this->assertEquals(3, $contact1['id']);
383 $email1 = $this->callAPISuccess('email', 'get', ['contact_id' => $contact1['id']]);
384 $this->assertEquals(1, $email1['count']);
385 $this->assertEquals($primaryEmail, $email1['values'][$email1['id']]['email']);
387 $email2 = $this->callAPISuccess('email', 'create', ['contact_id' => $contact1['id'], 'is_primary' => 0, 'email' => $notPrimaryEmail]);
389 // Case 1: Check with criteria primary 'email' => array('IS NOT NULL' => 1)
390 $result = $this->callAPISuccess('contact', 'get', ['email' => ['IS NOT NULL' => 1]]);
391 $primaryEmailContactIds = array_keys($result['values']);
392 $this->assertEquals($primaryEmail, $email1['values'][$email1['id']]['email']);
394 // Case 2: Check with criteria primary 'email' => array('<>' => '')
395 $result = $this->callAPISuccess('contact', 'get', ['email' => ['<>' => '']]);
396 $primaryEmailContactIds = array_keys($result['values']);
397 $this->assertEquals($primaryEmail, $email1['values'][$email1['id']]['email']);
399 // Case 3: Check with email_id='primary email id'
400 $result = $this->callAPISuccess('contact', 'get', ['email_id' => $email1['id']]);
401 $this->assertEquals(1, $result['count']);
402 $this->assertEquals($contact1['id'], $result['id']);
404 $this->callAPISuccess('contact', 'delete', $contact1);
408 * Test creating individual by name.
410 * Verify create individual contact with only first and last names succeeds.
412 * @param int $version
414 * @dataProvider versionThreeAndFour
416 public function testCreateNameIndividual($version) {
417 $this->_apiversion
= $version;
419 'first_name' => 'abc1',
420 'contact_type' => 'Individual',
421 'last_name' => 'xyz1',
424 $this->callAPISuccess('contact', 'create', $params);
428 * Test creating individual by display_name.
430 * Display name & sort name should be set.
432 * @param int $version
434 * @dataProvider versionThreeAndFour
436 public function testCreateDisplayNameIndividual($version) {
437 $this->_apiversion
= $version;
439 'display_name' => 'abc1',
440 'contact_type' => 'Individual',
443 $contact = $this->callAPISuccess('contact', 'create', $params);
444 $params['sort_name'] = 'abc1';
445 $this->getAndCheck($params, $contact['id'], 'contact');
449 * Test that name searches are case insensitive.
451 * @param int $version
453 * @dataProvider versionThreeAndFour
455 public function testGetNameVariantsCaseInsensitive($version) {
456 $this->_apiversion
= $version;
457 $this->callAPISuccess('contact', 'create', [
458 'display_name' => 'Abc1',
459 'contact_type' => 'Individual',
461 $this->callAPISuccessGetSingle('Contact', ['display_name' => 'aBc1']);
462 $this->callAPISuccessGetSingle('Contact', ['sort_name' => 'aBc1']);
463 Civi
::settings()->set('includeNickNameInName', TRUE);
464 $result = $this->callAPISuccessGetSingle('Contact', ['display_name' => 'aBc1']);
465 $this->callAPISuccessGetSingle('Contact', ['sort_name' => 'aBc1']);
466 Civi
::settings()->set('includeNickNameInName', FALSE);
470 * Test old keys still work.
472 * Verify that attempt to create individual contact with
473 * first and last names and old key values works
475 public function testCreateNameIndividualOldKeys() {
477 'individual_prefix' => 'Dr.',
478 'first_name' => 'abc1',
479 'contact_type' => 'Individual',
480 'last_name' => 'xyz1',
481 'individual_suffix' => 'Jr.',
484 $contact = $this->callAPISuccess('contact', 'create', $params);
485 $result = $this->callAPISuccess('contact', 'getsingle', ['id' => $contact['id']]);
487 $this->assertArrayKeyExists('prefix_id', $result);
488 $this->assertArrayKeyExists('suffix_id', $result);
489 $this->assertArrayKeyExists('gender_id', $result);
490 $this->assertEquals(4, $result['prefix_id']);
491 $this->assertEquals(1, $result['suffix_id']);
495 * Test preferred keys work.
497 * Verify that attempt to create individual contact with
498 * first and last names and old key values works
500 public function testCreateNameIndividualRecommendedKeys2() {
502 'prefix_id' => 'Dr.',
503 'first_name' => 'abc1',
504 'contact_type' => 'Individual',
505 'last_name' => 'xyz1',
506 'suffix_id' => 'Jr.',
507 'gender_id' => 'Male',
510 $contact = $this->callAPISuccess('contact', 'create', $params);
511 $result = $this->callAPISuccess('contact', 'getsingle', ['id' => $contact['id']]);
513 $this->assertArrayKeyExists('prefix_id', $result);
514 $this->assertArrayKeyExists('suffix_id', $result);
515 $this->assertArrayKeyExists('gender_id', $result);
516 $this->assertEquals(4, $result['prefix_id']);
517 $this->assertEquals(1, $result['suffix_id']);
521 * Test household name is sufficient for create.
523 * Verify that attempt to create household contact with only
524 * household name succeeds
526 * @param int $version
528 * @dataProvider versionThreeAndFour
530 public function testCreateNameHousehold($version) {
531 $this->_apiversion
= $version;
533 'household_name' => 'The abc Household',
534 'contact_type' => 'Household',
536 $this->callAPISuccess('contact', 'create', $params);
540 * Test organization name is sufficient for create.
542 * Verify that attempt to create organization contact with only
543 * organization name succeeds.
545 * @param int $version
547 * @dataProvider versionThreeAndFour
549 public function testCreateNameOrganization($version) {
550 $this->_apiversion
= $version;
552 'organization_name' => 'The abc Organization',
553 'contact_type' => 'Organization',
555 $this->callAPISuccess('contact', 'create', $params);
559 * Verify that attempt to create organization contact without organization name fails.
561 public function testCreateNoNameOrganization() {
563 'first_name' => 'The abc Organization',
564 'contact_type' => 'Organization',
566 $this->callAPIFailure('contact', 'create', $params);
570 * Check that permissions on API key are restricted (CRM-18112).
572 * @param int $version
574 * @dataProvider versionThreeAndFour
576 public function testCreateApiKey($version) {
577 $this->_apiversion
= $version;
578 $config = CRM_Core_Config
::singleton();
579 $contactId = $this->individualCreate([
584 // Allow edit -- because permissions aren't being checked
585 $config->userPermissionClass
->permissions
= [];
586 $result = $this->callAPISuccess('Contact', 'create', [
588 'api_key' => 'original',
590 $this->assertEquals('original', $result['values'][$contactId]['api_key']);
592 // Allow edit -- because we have adequate permission
593 $config->userPermissionClass
->permissions
= ['access CiviCRM', 'edit all contacts', 'edit api keys'];
594 $result = $this->callAPISuccess('Contact', 'create', [
595 'check_permissions' => 1,
597 'api_key' => 'abcd1234',
599 $this->assertEquals('abcd1234', $result['values'][$contactId]['api_key']);
601 // Disallow edit -- because we don't have permission
602 $config->userPermissionClass
->permissions
= ['access CiviCRM', 'edit all contacts'];
603 $result = $this->callAPIFailure('Contact', 'create', [
604 'check_permissions' => 1,
606 'api_key' => 'defg4321',
608 $this->assertRegExp(';Permission denied to modify api key;', $result['error_message']);
610 // Return everything -- because permissions are not being checked
611 $config->userPermissionClass
->permissions
= [];
612 $result = $this->callAPISuccess('Contact', 'create', [
614 'first_name' => 'A2',
616 $this->assertEquals('A2', $result['values'][$contactId]['first_name']);
617 $this->assertEquals('B', $result['values'][$contactId]['last_name']);
618 $this->assertEquals('abcd1234', $result['values'][$contactId]['api_key']);
620 // Return everything -- because we have adequate permission
621 $config->userPermissionClass
->permissions
= ['access CiviCRM', 'edit all contacts', 'edit api keys'];
622 $result = $this->callAPISuccess('Contact', 'create', [
623 'check_permissions' => 1,
625 'first_name' => 'A3',
627 $this->assertEquals('A3', $result['values'][$contactId]['first_name']);
628 $this->assertEquals('B', $result['values'][$contactId]['last_name']);
629 $this->assertEquals('abcd1234', $result['values'][$contactId]['api_key']);
631 // Restricted return -- because we don't have permission
632 $config->userPermissionClass
->permissions
= ['access CiviCRM', 'edit all contacts'];
633 $result = $this->callAPISuccess('Contact', 'create', [
634 'check_permissions' => 1,
636 'first_name' => 'A4',
638 $this->assertEquals('A4', $result['values'][$contactId]['first_name']);
639 $this->assertEquals('B', $result['values'][$contactId]['last_name']);
640 $this->assertTrue(empty($result['values'][$contactId]['api_key']));
644 * Check with complete array + custom field.
646 * Note that the test is written on purpose without any
647 * variables specific to participant so it can be replicated into other entities
648 * and / or moved to the automated test suite
650 * @param int $version
652 * @dataProvider versionThreeAndFour
654 public function testCreateWithCustom($version) {
655 $this->_apiversion
= $version;
656 $ids = $this->entityCustomGroupWithSingleFieldCreate(__FUNCTION__
, __FILE__
);
658 $params = $this->_params
;
659 $params['custom_' . $ids['custom_field_id']] = "custom string";
660 $description = "This demonstrates setting a custom field through the API.";
661 $result = $this->callAPIAndDocument($this->_entity
, 'create', $params, __FUNCTION__
, __FILE__
, $description);
663 $check = $this->callAPISuccess($this->_entity
, 'get', [
664 'return.custom_' . $ids['custom_field_id'] => 1,
665 'id' => $result['id'],
667 $this->assertEquals("custom string", $check['values'][$check['id']]['custom_' . $ids['custom_field_id']]);
669 $this->customFieldDelete($ids['custom_field_id']);
670 $this->customGroupDelete($ids['custom_group_id']);
674 * CRM-12773 - expectation is that civicrm quietly ignores fields without values.
676 public function testCreateWithNULLCustomCRM12773() {
677 $ids = $this->entityCustomGroupWithSingleFieldCreate(__FUNCTION__
, __FILE__
);
678 $params = $this->_params
;
679 $params['custom_' . $ids['custom_field_id']] = NULL;
680 $this->callAPISuccess('contact', 'create', $params);
681 $this->customFieldDelete($ids['custom_field_id']);
682 $this->customGroupDelete($ids['custom_group_id']);
686 * CRM-14232 test preferred language set to site default if not passed.
688 * @param int $version
690 * @dataProvider versionThreeAndFour
692 public function testCreatePreferredLanguageUnset($version) {
693 $this->_apiversion
= $version;
694 $this->callAPISuccess('Contact', 'create', [
695 'first_name' => 'Snoop',
696 'last_name' => 'Dog',
697 'contact_type' => 'Individual',
699 $result = $this->callAPISuccessGetSingle('Contact', ['last_name' => 'Dog']);
700 $this->assertEquals('en_US', $result['preferred_language']);
704 * CRM-14232 test preferred language returns setting if not passed.
706 * @param int $version
708 * @dataProvider versionThreeAndFour
710 public function testCreatePreferredLanguageSet($version) {
711 $this->_apiversion
= $version;
712 $this->callAPISuccess('Setting', 'create', ['contact_default_language' => 'fr_FR']);
713 $this->callAPISuccess('Contact', 'create', [
714 'first_name' => 'Snoop',
715 'last_name' => 'Dog',
716 'contact_type' => 'Individual',
718 $result = $this->callAPISuccessGetSingle('Contact', ['last_name' => 'Dog']);
719 $this->assertEquals('fr_FR', $result['preferred_language']);
723 * CRM-14232 test preferred language returns setting if not passed where setting is NULL.
726 public function testCreatePreferredLanguageNull() {
727 $this->callAPISuccess('Setting', 'create', ['contact_default_language' => 'null']);
728 $this->callAPISuccess('Contact', 'create', [
729 'first_name' => 'Snoop',
730 'last_name' => 'Dog',
731 'contact_type' => 'Individual',
733 $result = $this->callAPISuccessGetSingle('Contact', ['last_name' => 'Dog']);
734 $this->assertEquals(NULL, $result['preferred_language']);
738 * CRM-14232 test preferred language returns setting if not passed where setting is NULL.
740 * @param int $version
742 * @dataProvider versionThreeAndFour
744 public function testCreatePreferredLanguagePassed($version) {
745 $this->_apiversion
= $version;
746 $this->callAPISuccess('Setting', 'create', ['contact_default_language' => 'null']);
747 $this->callAPISuccess('Contact', 'create', [
748 'first_name' => 'Snoop',
749 'last_name' => 'Dog',
750 'contact_type' => 'Individual',
751 'preferred_language' => 'en_AU',
753 $result = $this->callAPISuccessGetSingle('Contact', ['last_name' => 'Dog']);
754 $this->assertEquals('en_AU', $result['preferred_language']);
758 * CRM-15792 - create/update datetime field for contact.
760 public function testCreateContactCustomFldDateTime() {
761 $customGroup = $this->customGroupCreate(['extends' => 'Individual', 'title' => 'datetime_test_group']);
762 $dateTime = CRM_Utils_Date
::currentDBDate();
763 //check date custom field is saved along with time when time_format is set
765 'first_name' => 'abc3',
766 'last_name' => 'xyz3',
767 'contact_type' => 'Individual',
768 'email' => 'man3@yahoo.com',
769 'api.CustomField.create' => [
770 'custom_group_id' => $customGroup['id'],
771 'name' => 'test_datetime',
772 'label' => 'Demo Date',
773 'html_type' => 'Select Date',
774 'data_type' => 'Date',
778 'is_searchable' => 0,
783 $result = $this->callAPISuccess('Contact', 'create', $params);
784 $customFldId = $result['values'][$result['id']]['api.CustomField.create']['id'];
785 $this->assertNotNull($result['id']);
786 $this->assertNotNull($customFldId);
789 'id' => $result['id'],
790 "custom_{$customFldId}" => $dateTime,
791 'api.CustomValue.get' => 1,
794 $result = $this->callAPISuccess('Contact', 'create', $params);
795 $this->assertNotNull($result['id']);
796 $customFldDate = date("YmdHis", strtotime($result['values'][$result['id']]['api.CustomValue.get']['values'][0]['latest']));
797 $this->assertNotNull($customFldDate);
798 $this->assertEquals($dateTime, $customFldDate);
799 $customValueId = $result['values'][$result['id']]['api.CustomValue.get']['values'][0]['id'];
800 $dateTime = date('Ymd');
801 //date custom field should not contain time part when time_format is null
803 'id' => $result['id'],
804 'api.CustomField.create' => [
805 'id' => $customFldId,
806 'html_type' => 'Select Date',
807 'data_type' => 'Date',
810 'api.CustomValue.create' => [
811 'id' => $customValueId,
812 'entity_id' => $result['id'],
813 "custom_{$customFldId}" => $dateTime,
815 'api.CustomValue.get' => 1,
817 $result = $this->callAPISuccess('Contact', 'create', $params);
818 $this->assertNotNull($result['id']);
819 $customFldDate = date("Ymd", strtotime($result['values'][$result['id']]['api.CustomValue.get']['values'][0]['latest']));
820 $customFldTime = date("His", strtotime($result['values'][$result['id']]['api.CustomValue.get']['values'][0]['latest']));
821 $this->assertNotNull($customFldDate);
822 $this->assertEquals($dateTime, $customFldDate);
823 $this->assertEquals(000000, $customFldTime);
824 $this->callAPISuccess('Contact', 'create', $params);
828 * Test creating a current employer through API.
830 public function testContactCreateCurrentEmployer() {
831 // Here we will just do the get for set-up purposes.
832 $count = $this->callAPISuccess('contact', 'getcount', [
833 'organization_name' => 'new employer org',
834 'contact_type' => 'Organization',
836 $this->assertEquals(0, $count);
837 $employerResult = $this->callAPISuccess('contact', 'create', array_merge($this->_params
, [
838 'current_employer' => 'new employer org',
840 // do it again as an update to check it doesn't cause an error
841 $employerResult = $this->callAPISuccess('contact', 'create', array_merge($this->_params
, [
842 'current_employer' => 'new employer org',
843 'id' => $employerResult['id'],
846 $this->callAPISuccess('contact', 'getcount', [
847 'organization_name' => 'new employer org',
848 'contact_type' => 'Organization',
851 $result = $this->callAPISuccess('contact', 'getsingle', [
852 'id' => $employerResult['id'],
855 $this->assertEquals('new employer org', $result['current_employer']);
860 * Test creating a current employer through API.
862 * Check it will re-activate a de-activated employer
864 public function testContactCreateDuplicateCurrentEmployerEnables() {
865 // Set up - create employer relationship.
866 $employerResult = $this->callAPISuccess('contact', 'create', array_merge($this->_params
, ['current_employer' => 'new employer org']));
867 $relationship = $this->callAPISuccess('relationship', 'get', [
868 'contact_id_a' => $employerResult['id'],
871 //disable & check it is disabled
872 $this->callAPISuccess('relationship', 'create', ['id' => $relationship['id'], 'is_active' => 0]);
873 $this->callAPISuccess('relationship', 'getvalue', [
874 'id' => $relationship['id'],
875 'return' => 'is_active',
878 // Re-set the current employer - thus enabling the relationship.
879 $this->callAPISuccess('contact', 'create', array_merge($this->_params
, [
880 'current_employer' => 'new employer org',
881 'id' => $employerResult['id'],
883 //check is_active is now 1
884 $relationship = $this->callAPISuccess('relationship', 'getsingle', ['return' => 'is_active']);
885 $this->assertEquals(1, $relationship['is_active']);
889 * Check deceased contacts are not retrieved.
891 * Note at time of writing the default is to return default. This should possibly be changed & test added.
893 * @param int $version
895 * @dataProvider versionThreeAndFour
897 public function testGetDeceasedRetrieved($version) {
898 $this->_apiversion
= $version;
899 $this->callAPISuccess($this->_entity
, 'create', $this->_params
);
900 $c2 = $this->callAPISuccess($this->_entity
, 'create', [
901 'first_name' => 'bb',
902 'last_name' => 'ccc',
903 'contact_type' => 'Individual',
906 $result = $this->callAPISuccess($this->_entity
, 'get', ['is_deceased' => 0]);
907 $this->assertFalse(array_key_exists($c2['id'], $result['values']));
911 * Test that sort works - old syntax.
913 public function testGetSort() {
914 $c1 = $this->callAPISuccess($this->_entity
, 'create', $this->_params
);
915 $c2 = $this->callAPISuccess($this->_entity
, 'create', [
916 'first_name' => 'bb',
917 'last_name' => 'ccc',
918 'contact_type' => 'Individual',
920 $result = $this->callAPISuccess($this->_entity
, 'get', [
921 'sort' => 'first_name ASC',
922 'return.first_name' => 1,
925 'contact_type' => 'Individual',
928 $this->assertEquals('abc1', $result['values'][0]['first_name']);
929 $result = $this->callAPISuccess($this->_entity
, 'get', [
930 'sort' => 'first_name DESC',
931 'return.first_name' => 1,
935 $this->assertEquals('bb', $result['values'][0]['first_name']);
937 $this->callAPISuccess($this->_entity
, 'delete', ['id' => $c1['id']]);
938 $this->callAPISuccess($this->_entity
, 'delete', ['id' => $c2['id']]);
942 * Test that we can retrieve contacts using array syntax.
944 * I.e 'id' => array('IN' => array('3,4')).
946 * @param int $version
948 * @dataProvider versionThreeAndFour
950 public function testGetINIDArray($version) {
951 $this->_apiversion
= $version;
952 $c1 = $this->callAPISuccess($this->_entity
, 'create', $this->_params
);
953 $c2 = $this->callAPISuccess($this->_entity
, 'create', [
954 'first_name' => 'bb',
955 'last_name' => 'ccc',
956 'contact_type' => 'Individual',
958 $c3 = $this->callAPISuccess($this->_entity
, 'create', [
959 'first_name' => 'hh',
961 'contact_type' => 'Individual',
963 $result = $this->callAPISuccess($this->_entity
, 'get', ['id' => ['IN' => [$c1['id'], $c3['id']]]]);
964 $this->assertEquals(2, $result['count']);
965 $this->assertEquals([$c1['id'], $c3['id']], array_keys($result['values']));
966 $this->callAPISuccess($this->_entity
, 'delete', ['id' => $c1['id']]);
967 $this->callAPISuccess($this->_entity
, 'delete', ['id' => $c2['id']]);
968 $this->callAPISuccess($this->_entity
, 'delete', ['id' => $c3['id']]);
972 * Test variants on deleted behaviour.
974 public function testGetDeleted() {
975 $params = $this->_params
;
976 $contact1 = $this->callAPISuccess('contact', 'create', $params);
977 $params['is_deleted'] = 1;
978 $params['last_name'] = 'bcd';
979 $contact2 = $this->callAPISuccess('contact', 'create', $params);
980 $countActive = $this->callAPISuccess('contact', 'getcount', [
981 'showAll' => 'active',
982 'contact_type' => 'Individual',
984 $countAll = $this->callAPISuccess('contact', 'getcount', ['showAll' => 'all', 'contact_type' => 'Individual']);
985 $countTrash = $this->callAPISuccess('contact', 'getcount', ['showAll' => 'trash', 'contact_type' => 'Individual']);
986 $countDefault = $this->callAPISuccess('contact', 'getcount', ['contact_type' => 'Individual']);
987 $countDeleted = $this->callAPISuccess('contact', 'getcount', [
988 'contact_type' => 'Individual',
989 'contact_is_deleted' => 1,
991 $countNotDeleted = $this->callAPISuccess('contact', 'getcount', [
992 'contact_is_deleted' => 0,
993 'contact_type' => 'Individual',
995 $this->callAPISuccess('contact', 'delete', ['id' => $contact1['id']]);
996 $this->callAPISuccess('contact', 'delete', ['id' => $contact2['id']]);
997 $this->assertEquals(1, $countNotDeleted, 'contact_is_deleted => 0 is respected');
998 $this->assertEquals(1, $countActive);
999 $this->assertEquals(1, $countTrash);
1000 $this->assertEquals(2, $countAll);
1001 $this->assertEquals(1, $countDeleted);
1002 $this->assertEquals(1, $countDefault, 'Only active by default in line');
1006 * Test that sort works - new syntax.
1008 * @param int $version
1010 * @dataProvider versionThreeAndFour
1012 public function testGetSortNewSyntax($version) {
1013 $this->_apiversion
= $version;
1014 $c1 = $this->callAPISuccess($this->_entity
, 'create', $this->_params
);
1015 $c2 = $this->callAPISuccess($this->_entity
, 'create', [
1016 'first_name' => 'bb',
1017 'last_name' => 'ccc',
1018 'contact_type' => 'Individual',
1020 $result = $this->callAPISuccess($this->_entity
, 'getvalue', [
1021 'return' => 'first_name',
1022 'contact_type' => 'Individual',
1025 'sort' => 'first_name',
1028 $this->assertEquals('abc1', $result);
1030 $result = $this->callAPISuccess($this->_entity
, 'getvalue', [
1031 'return' => 'first_name',
1032 'contact_type' => 'Individual',
1035 'sort' => 'first_name DESC',
1038 $this->assertEquals('bb', $result);
1040 $this->callAPISuccess($this->_entity
, 'delete', ['id' => $c1['id']]);
1041 $this->callAPISuccess($this->_entity
, 'delete', ['id' => $c2['id']]);
1045 * Test sort and limit for chained relationship get.
1047 * https://issues.civicrm.org/jira/browse/CRM-15983
1048 * @param int $version
1050 * @dataProvider versionThreeAndFour
1052 public function testSortLimitChainedRelationshipGetCRM15983($version) {
1053 $this->_apiversion
= $version;
1055 $create_result_1 = $this->callAPISuccess('contact', 'create', [
1056 'first_name' => 'Jules',
1057 'last_name' => 'Smos',
1058 'contact_type' => 'Individual',
1061 // Create another contact with two relationships.
1063 'first_name' => 'Jos',
1064 'last_name' => 'Smos',
1065 'contact_type' => 'Individual',
1066 'api.relationship.create' => [
1068 'contact_id_a' => '$value.id',
1069 'contact_id_b' => $create_result_1['id'],
1071 'relationship_type_id' => 2,
1072 'start_date' => '2005-01-12',
1073 'end_date' => '2006-01-11',
1074 'description' => 'old',
1077 'contact_id_a' => '$value.id',
1078 'contact_id_b' => $create_result_1['id'],
1079 // spouse of (was married twice :))
1080 'relationship_type_id' => 2,
1081 'start_date' => '2006-07-01',
1082 'end_date' => '2010-07-01',
1083 'description' => 'new',
1087 $create_result = $this->callAPISuccess('contact', 'create', $create_params);
1089 // Try to retrieve the contact and the most recent relationship.
1092 'id' => $create_result['id'],
1093 'api.relationship.get' => [
1094 'contact_id_a' => '$value.id',
1097 'sort' => 'start_date DESC',
1101 $get_result = $this->callAPISuccess('contact', 'getsingle', $get_params);
1104 $this->callAPISuccess('contact', 'delete', [
1105 'id' => $create_result['id'],
1109 $this->assertEquals(1, $get_result['api.relationship.get']['count']);
1110 $this->assertEquals('new', $get_result['api.relationship.get']['values'][0]['description']);
1114 * Test apostrophe works in get & create.
1116 * @param int $version
1118 * @dataProvider versionThreeAndFour
1120 public function testGetApostropheCRM10857($version) {
1121 $this->_apiversion
= $version;
1122 $params = array_merge($this->_params
, ['last_name' => "O'Connor"]);
1123 $this->callAPISuccess($this->_entity
, 'create', $params);
1124 $result = $this->callAPISuccess($this->_entity
, 'getsingle', [
1125 'last_name' => "O'Connor",
1128 $this->assertEquals("O'Connor", $result['last_name']);
1132 * Test between accepts zero.
1134 * In the past it incorrectly required !empty.
1136 * @param int $version
1138 * @dataProvider versionThreeAndFour
1140 public function testGetBetweenZeroWorks($version) {
1141 $this->_apiversion
= $version;
1142 $this->callAPISuccess($this->_entity
, 'get', [
1143 'contact_id' => ['BETWEEN' => [0, 9]],
1145 $this->callAPISuccess($this->_entity
, 'get', [
1156 * Test retrieval by addressee id.
1157 * V3 only - the "skip_greeting_processing" param is not currently in v4
1159 public function testGetByAddresseeID() {
1160 $individual1ID = $this->individualCreate([
1161 'skip_greeting_processing' => 1,
1162 'addressee_id' => 'null',
1163 'email_greeting_id' => 'null',
1164 'postal_greeting_id' => 'null',
1166 $individual2ID = $this->individualCreate();
1168 $this->assertEquals($individual1ID,
1169 $this->callAPISuccessGetValue('Contact', ['contact_type' => 'Individual', 'addressee_id' => ['IS NULL' => 1], 'return' => 'id'])
1171 $this->assertEquals($individual1ID,
1172 $this->callAPISuccessGetValue('Contact', ['contact_type' => 'Individual', 'email_greeting_id' => ['IS NULL' => 1], 'return' => 'id'])
1174 $this->assertEquals($individual1ID,
1175 $this->callAPISuccessGetValue('Contact', ['contact_type' => 'Individual', 'postal_greeting_id' => ['IS NULL' => 1], 'return' => 'id'])
1178 $this->assertEquals($individual2ID,
1179 $this->callAPISuccessGetValue('Contact', ['contact_type' => 'Individual', 'addressee_id' => ['NOT NULL' => 1], 'return' => 'id'])
1184 * Check with complete array + custom field.
1186 * Note that the test is written on purpose without any
1187 * variables specific to participant so it can be replicated into other entities
1188 * and / or moved to the automated test suite
1190 public function testGetWithCustom() {
1191 $ids = $this->entityCustomGroupWithSingleFieldCreate(__FUNCTION__
, __FILE__
);
1193 $params = $this->_params
;
1194 $params['custom_' . $ids['custom_field_id']] = "custom string";
1195 $description = "This demonstrates setting a custom field through the API.";
1196 $subfile = "CustomFieldGet";
1197 $result = $this->callAPISuccess($this->_entity
, 'create', $params);
1199 $check = $this->callAPIAndDocument($this->_entity
, 'get', [
1200 'return.custom_' . $ids['custom_field_id'] => 1,
1201 'id' => $result['id'],
1202 ], __FUNCTION__
, __FILE__
, $description, $subfile);
1204 $this->assertEquals("custom string", $check['values'][$check['id']]['custom_' . $ids['custom_field_id']]);
1205 $fields = ($this->callAPISuccess('contact', 'getfields', $params));
1206 $this->assertTrue(is_array($fields['values']['custom_' . $ids['custom_field_id']]));
1207 $this->customFieldDelete($ids['custom_field_id']);
1208 $this->customGroupDelete($ids['custom_group_id']);
1212 * Tests that using 'return' with a custom field not of type contact does not inappropriately filter.
1214 * https://lab.civicrm.org/dev/core/issues/1025
1216 * @throws \CRM_Core_Exception
1218 public function testGetWithCustomOfActivityType() {
1219 $this->createCustomGroupWithFieldOfType(['extends' => 'Activity']);
1220 $this->createCustomGroupWithFieldOfType(['extends' => 'Contact'], 'text', 'contact_');
1221 $contactID = $this->individualCreate();
1222 $this->callAPISuccessGetSingle('Contact', ['id' => $contactID, 'return' => ['external_identifier', $this->getCustomFieldName('contact_text')]]);
1226 * Check with complete array + custom field.
1228 * Note that the test is written on purpose without any
1229 * variables specific to participant so it can be replicated into other entities
1230 * and / or moved to the automated test suite
1232 public function testGetWithCustomReturnSyntax() {
1233 $ids = $this->entityCustomGroupWithSingleFieldCreate(__FUNCTION__
, __FILE__
);
1235 $params = $this->_params
;
1236 $params['custom_' . $ids['custom_field_id']] = "custom string";
1237 $description = "This demonstrates setting a custom field through the API.";
1238 $subfile = "CustomFieldGetReturnSyntaxVariation";
1239 $result = $this->callAPISuccess($this->_entity
, 'create', $params);
1240 $params = ['return' => 'custom_' . $ids['custom_field_id'], 'id' => $result['id']];
1241 $check = $this->callAPIAndDocument($this->_entity
, 'get', $params, __FUNCTION__
, __FILE__
, $description, $subfile);
1243 $this->assertEquals("custom string", $check['values'][$check['id']]['custom_' . $ids['custom_field_id']]);
1244 $this->customFieldDelete($ids['custom_field_id']);
1245 $this->customGroupDelete($ids['custom_group_id']);
1249 * Check that address name, ID is returned if required.
1251 public function testGetReturnAddress() {
1252 $contactID = $this->individualCreate();
1253 $result = $this->callAPISuccess('address', 'create', [
1254 'contact_id' => $contactID,
1255 'address_name' => 'My house',
1256 'location_type_id' => 'Home',
1257 'street_address' => '1 my road',
1259 $addressID = $result['id'];
1261 $result = $this->callAPISuccessGetSingle('contact', [
1262 'return' => 'address_name, street_address, address_id',
1265 $this->assertEquals($addressID, $result['address_id']);
1266 $this->assertEquals('1 my road', $result['street_address']);
1267 $this->assertEquals('My house', $result['address_name']);
1272 * Test group filter syntaxes.
1274 public function testGetGroupIDFromContact() {
1275 $groupId = $this->groupCreate();
1277 'email' => 'man2@yahoo.com',
1278 'contact_type' => 'Individual',
1279 'location_type_id' => 1,
1280 'api.group_contact.create' => ['group_id' => $groupId],
1283 $this->callAPISuccess('contact', 'create', $params);
1284 // testing as integer
1286 'filter.group_id' => $groupId,
1287 'contact_type' => 'Individual',
1289 $result = $this->callAPISuccess('contact', 'get', $params);
1290 $this->assertEquals(1, $result['count']);
1291 // group 26 doesn't exist, but we can still search contacts in it.
1293 'filter.group_id' => 26,
1294 'contact_type' => 'Individual',
1296 $this->callAPISuccess('contact', 'get', $params);
1297 // testing as string
1299 'filter.group_id' => "$groupId, 26",
1300 'contact_type' => 'Individual',
1302 $result = $this->callAPISuccess('contact', 'get', $params);
1303 $this->assertEquals(1, $result['count']);
1305 'filter.group_id' => "26,27",
1306 'contact_type' => 'Individual',
1308 $this->callAPISuccess('contact', 'get', $params);
1310 // testing as string
1312 'filter.group_id' => [$groupId, 26],
1313 'contact_type' => 'Individual',
1315 $result = $this->callAPISuccess('contact', 'get', $params);
1316 $this->assertEquals(1, $result['count']);
1318 //test in conjunction with other criteria
1320 'filter.group_id' => [$groupId, 26],
1321 'contact_type' => 'Organization',
1323 $this->callAPISuccess('contact', 'get', $params);
1325 'filter.group_id' => [26, 27],
1326 'contact_type' => 'Individual',
1328 $result = $this->callAPISuccess('contact', 'get', $params);
1329 $this->assertEquals(0, $result['count']);
1333 * Verify that attempt to create individual contact with two chained websites succeeds.
1335 public function testCreateIndividualWithContributionDottedSyntax() {
1336 $description = "This demonstrates the syntax to create 2 chained entities.";
1337 $subFile = "ChainTwoWebsites";
1339 'first_name' => 'abc3',
1340 'last_name' => 'xyz3',
1341 'contact_type' => 'Individual',
1342 'email' => 'man3@yahoo.com',
1343 'api.contribution.create' => [
1344 'receive_date' => '2010-01-01',
1345 'total_amount' => 100.00,
1346 'financial_type_id' => $this->_financialTypeId
,
1347 'payment_instrument_id' => 1,
1348 'non_deductible_amount' => 10.00,
1349 'fee_amount' => 50.00,
1350 'net_amount' => 90.00,
1352 'invoice_id' => 67990,
1354 'contribution_status_id' => 1,
1355 'skipCleanMoney' => 1,
1357 'api.website.create' => [
1358 'url' => "http://civicrm.org",
1360 'api.website.create.2' => [
1361 'url' => "http://chained.org",
1365 $result = $this->callAPIAndDocument('Contact', 'create', $params, __FUNCTION__
, __FILE__
, $description, $subFile);
1367 // checking child function result not covered in callAPIAndDocument
1368 $this->assertAPISuccess($result['values'][$result['id']]['api.website.create']);
1369 $this->assertEquals("http://chained.org", $result['values'][$result['id']]['api.website.create.2']['values'][0]['url']);
1370 $this->assertEquals("http://civicrm.org", $result['values'][$result['id']]['api.website.create']['values'][0]['url']);
1372 // delete the contact
1373 $this->callAPISuccess('contact', 'delete', $result);
1377 * Verify that attempt to create individual contact with chained contribution and website succeeds.
1379 public function testCreateIndividualWithContributionChainedArrays() {
1381 'first_name' => 'abc3',
1382 'last_name' => 'xyz3',
1383 'contact_type' => 'Individual',
1384 'email' => 'man3@yahoo.com',
1385 'api.contribution.create' => [
1386 'receive_date' => '2010-01-01',
1387 'total_amount' => 100.00,
1388 'financial_type_id' => $this->_financialTypeId
,
1389 'payment_instrument_id' => 1,
1390 'non_deductible_amount' => 10.00,
1391 'fee_amount' => 50.00,
1392 'net_amount' => 90.00,
1394 'invoice_id' => 67890,
1396 'contribution_status_id' => 1,
1397 'skipCleanMoney' => 1,
1399 'api.website.create' => [
1401 'url' => "http://civicrm.org",
1404 'url' => "http://chained.org",
1405 'website_type_id' => 2,
1410 $description = "Demonstrates creating two websites as an array.";
1411 $subfile = "ChainTwoWebsitesSyntax2";
1412 $result = $this->callAPIAndDocument('Contact', 'create', $params, __FUNCTION__
, __FILE__
, $description, $subfile);
1414 // the callAndDocument doesn't check the chained call
1415 $this->assertEquals(0, $result['values'][$result['id']]['api.website.create'][0]['is_error']);
1416 $this->assertEquals("http://chained.org", $result['values'][$result['id']]['api.website.create'][1]['values'][0]['url']);
1417 $this->assertEquals("http://civicrm.org", $result['values'][$result['id']]['api.website.create'][0]['values'][0]['url']);
1419 $this->callAPISuccess('contact', 'delete', $result);
1423 * Test for direction when chaining relationships.
1425 * https://issues.civicrm.org/jira/browse/CRM-16084
1426 * @param int $version
1428 * @dataProvider versionThreeAndFour
1430 public function testDirectionChainingRelationshipsCRM16084($version) {
1431 $this->_apiversion
= $version;
1432 // Some contact, called Jules.
1433 $create_result_1 = $this->callAPISuccess('contact', 'create', [
1434 'first_name' => 'Jules',
1435 'last_name' => 'Smos',
1436 'contact_type' => 'Individual',
1439 // Another contact: Jos, child of Jules.
1441 'first_name' => 'Jos',
1442 'last_name' => 'Smos',
1443 'contact_type' => 'Individual',
1444 'api.relationship.create' => [
1446 'contact_id_a' => '$value.id',
1447 'contact_id_b' => $create_result_1['id'],
1449 'relationship_type_id' => 1,
1453 $create_result_2 = $this->callAPISuccess('contact', 'create', $create_params);
1455 // Mia is the child of Jos.
1457 'first_name' => 'Mia',
1458 'last_name' => 'Smos',
1459 'contact_type' => 'Individual',
1460 'api.relationship.create' => [
1462 'contact_id_a' => '$value.id',
1463 'contact_id_b' => $create_result_2['id'],
1465 'relationship_type_id' => 1,
1469 $create_result_3 = $this->callAPISuccess('contact', 'create', $create_params);
1471 // Get Jos and his children.
1474 'id' => $create_result_2['id'],
1475 'api.relationship.get' => [
1476 'contact_id_b' => '$value.id',
1477 'relationship_type_id' => 1,
1480 $get_result = $this->callAPISuccess('contact', 'getsingle', $get_params);
1483 $this->callAPISuccess('contact', 'delete', [
1484 'id' => $create_result_1['id'],
1486 $this->callAPISuccess('contact', 'delete', [
1487 'id' => $create_result_2['id'],
1491 $this->assertEquals(1, $get_result['api.relationship.get']['count']);
1492 $this->assertEquals($create_result_3['id'], $get_result['api.relationship.get']['values'][0]['contact_id_a']);
1496 * Verify that attempt to create individual contact with first, and last names and email succeeds.
1498 public function testCreateIndividualWithNameEmail() {
1500 'first_name' => 'abc3',
1501 'last_name' => 'xyz3',
1502 'contact_type' => 'Individual',
1503 'email' => 'man3@yahoo.com',
1506 $contact = $this->callAPISuccess('contact', 'create', $params);
1508 $this->callAPISuccess('contact', 'delete', $contact);
1512 * Verify that attempt to create individual contact with no data fails.
1514 public function testCreateIndividualWithOutNameEmail() {
1516 'contact_type' => 'Individual',
1518 $this->callAPIFailure('contact', 'create', $params);
1522 * Test create individual contact with first &last names, email and location type succeeds.
1524 public function testCreateIndividualWithNameEmailLocationType() {
1526 'first_name' => 'abc4',
1527 'last_name' => 'xyz4',
1528 'email' => 'man4@yahoo.com',
1529 'contact_type' => 'Individual',
1530 'location_type_id' => 1,
1532 $result = $this->callAPISuccess('contact', 'create', $params);
1534 $this->callAPISuccess('contact', 'delete', ['id' => $result['id']]);
1538 * Verify that when changing employers the old employer relationship becomes inactive.
1540 public function testCreateIndividualWithEmployer() {
1541 $employer = $this->organizationCreate();
1542 $employer2 = $this->organizationCreate();
1545 'email' => 'man4@yahoo.com',
1546 'contact_type' => 'Individual',
1547 'employer_id' => $employer,
1550 $result = $this->callAPISuccess('contact', 'create', $params);
1551 $relationships = $this->callAPISuccess('relationship', 'get', [
1552 'contact_id_a' => $result['id'],
1556 $this->assertEquals($employer, $relationships['values'][0]['contact_id_b']);
1558 // Add more random relationships to make the test more realistic
1559 foreach (['Employee of', 'Volunteer for'] as $relationshipType) {
1560 $relTypeId = CRM_Core_DAO
::getFieldValue('CRM_Contact_DAO_RelationshipType', $relationshipType, 'id', 'name_a_b');
1561 $this->callAPISuccess('relationship', 'create', [
1562 'contact_id_a' => $result['id'],
1563 'contact_id_b' => $this->organizationCreate(),
1565 'relationship_type_id' => $relTypeId,
1569 // Add second employer
1570 $params['employer_id'] = $employer2;
1571 $params['id'] = $result['id'];
1572 $result = $this->callAPISuccess('contact', 'create', $params);
1574 $relationships = $this->callAPISuccess('relationship', 'get', [
1575 'contact_id_a' => $result['id'],
1580 $this->assertEquals($employer, $relationships['values'][0]['contact_id_b']);
1584 * Verify that attempt to create household contact with details succeeds.
1586 public function testCreateHouseholdDetails() {
1588 'household_name' => 'abc8\'s House',
1589 'nick_name' => 'x House',
1590 'email' => 'man8@yahoo.com',
1591 'contact_type' => 'Household',
1594 $contact = $this->callAPISuccess('contact', 'create', $params);
1596 $this->callAPISuccess('contact', 'delete', $contact);
1600 * Verify that attempt to create household contact with inadequate details fails.
1602 public function testCreateHouseholdInadequateDetails() {
1604 'nick_name' => 'x House',
1605 'email' => 'man8@yahoo.com',
1606 'contact_type' => 'Household',
1608 $this->callAPIFailure('contact', 'create', $params);
1612 * Verify successful update of individual contact.
1614 public function testUpdateIndividualWithAll() {
1615 $contactID = $this->individualCreate();
1619 'first_name' => 'abcd',
1620 'contact_type' => 'Individual',
1621 'nick_name' => 'This is nickname first',
1622 'do_not_email' => '1',
1623 'do_not_phone' => '1',
1624 'do_not_mail' => '1',
1625 'do_not_trade' => '1',
1626 'legal_identifier' => 'ABC23853ZZ2235',
1627 'external_identifier' => '1928837465',
1628 'image_URL' => 'http://some.url.com/image.jpg',
1629 'home_url' => 'http://www.example.org',
1632 $this->callAPISuccess('Contact', 'Update', $params);
1633 $getResult = $this->callAPISuccess('Contact', 'Get', $params);
1634 unset($params['contact_id']);
1635 //Todo - neither API v2 or V3 are testing for home_url - not sure if it is being set.
1636 //reducing this test partially back to api v2 level to get it through
1637 unset($params['home_url']);
1638 foreach ($params as $key => $value) {
1639 $this->assertEquals($value, $getResult['values'][$contactID][$key]);
1644 * Verify successful update of organization contact.
1646 * @throws \Exception
1648 public function testUpdateOrganizationWithAll() {
1649 $contactID = $this->organizationCreate();
1653 'organization_name' => 'WebAccess India Pvt Ltd',
1654 'legal_name' => 'WebAccess',
1655 'sic_code' => 'ABC12DEF',
1656 'contact_type' => 'Organization',
1659 $this->callAPISuccess('Contact', 'Update', $params);
1660 $this->getAndCheck($params, $contactID, 'Contact');
1664 * Test merging 2 organizations.
1666 * CRM-20421: This test make sure that inherited memberships are deleted upon merging organization.
1668 public function testMergeOrganizations() {
1669 $organizationID1 = $this->organizationCreate([], 0);
1670 $organizationID2 = $this->organizationCreate([], 1);
1671 $contact = $this->callAPISuccess('contact', 'create', array_merge($this->_params
, [
1672 'employer_id' => $organizationID1,
1674 $contact = $contact["values"][$contact["id"]];
1676 $membershipType = $this->createEmployerOfMembership();
1677 $membershipParams = [
1678 'membership_type_id' => $membershipType["id"],
1679 'contact_id' => $organizationID1,
1680 'start_date' => "01/01/2015",
1681 'join_date' => "01/01/2010",
1682 'end_date' => "12/31/2015",
1684 $ownermembershipid = $this->contactMembershipCreate($membershipParams);
1686 $contactmembership = $this->callAPISuccess("membership", "getsingle", [
1687 "contact_id" => $contact["id"],
1690 $this->assertEquals($ownermembershipid, $contactmembership["owner_membership_id"], "Contact membership must be inherited from Organization");
1692 CRM_Dedupe_Merger
::moveAllBelongings($organizationID2, $organizationID1, [
1693 "move_rel_table_memberships" => "0",
1694 "move_rel_table_relationships" => "1",
1696 "contact_id" => $organizationID2,
1697 "contact_type" => "Organization",
1699 "other_details" => [
1700 "contact_id" => $organizationID1,
1701 "contact_type" => "Organization",
1705 $contactmembership = $this->callAPISuccess("membership", "get", [
1706 "contact_id" => $contact["id"],
1709 $this->assertEquals(0, $contactmembership["count"], "Contact membership must be deleted after merging organization without memberships.");
1713 * Test the function that determines if 2 contacts have conflicts.
1715 * @throws \Exception
1717 public function testMergeGetConflicts() {
1718 $this->createCustomGroupWithFieldOfType();
1719 $contact1 = $this->individualCreate([
1720 'email' => 'bob@example.com',
1721 'api.address.create' => ['location_type_id' => 'work', 'street_address' => 'big office', 'city' => 'small city'],
1722 'api.address.create.2' => ['location_type_id' => 'home', 'street_address' => 'big house', 'city' => 'small city'],
1723 'external_identifier' => 'unique and special',
1724 $this->getCustomFieldName('text') => 'mummy loves me',
1726 $contact2 = $this->individualCreate([
1727 'first_name' => 'different',
1728 'api.address.create.1' => ['location_type_id' => 'home', 'street_address' => 'medium house', 'city' => 'small city'],
1729 'api.address.create.2' => ['location_type_id' => 'work', 'street_address' => 'medium office', 'city' => 'small city'],
1730 'external_identifier' => 'uniquer and specialler',
1731 'api.email.create' => ['location_type_id' => 'Other', 'email' => 'bob@example.com'],
1732 $this->getCustomFieldName('text') => 'mummy loves me more',
1734 $conflicts = $this->callAPISuccess('Contact', 'get_merge_conflicts', ['to_keep_id' => $contact1, 'to_remove_id' => $contact2])['values'];
1735 $this->assertEquals([
1739 'first_name' => [$contact1 => 'Anthony', $contact2 => 'different', 'title' => 'First Name'],
1740 'external_identifier' => [$contact1 => 'unique and special', $contact2 => 'uniquer and specialler', 'title' => 'External Identifier'],
1741 $this->getCustomFieldName('text') => [$contact1 => 'mummy loves me', $contact2 => 'mummy loves me more', 'title' => 'Enter text here'],
1745 'location_type_id' => '1',
1746 'title' => 'Address 1 (Home)',
1747 'street_address' => [
1748 $contact1 => 'big house',
1749 $contact2 => 'medium house',
1752 $contact1 => "big house\nsmall city, \n",
1753 $contact2 => "medium house\nsmall city, \n",
1757 'location_type_id' => '2',
1758 'street_address' => [
1759 $contact1 => 'big office',
1760 $contact2 => 'medium office',
1762 'title' => 'Address 2 (Work)',
1764 $contact1 => "big office\nsmall city, \n",
1765 $contact2 => "medium office\nsmall city, \n",
1771 'location_type_id' => '1',
1773 $contact1 => 'bob@example.com',
1774 $contact2 => 'anthony_anderson@civicrm.org',
1776 'title' => 'Email 1 (Home)',
1778 $contact1 => 'bob@example.com',
1779 $contact2 => 'anthony_anderson@civicrm.org',
1787 $result = $this->callAPISuccess('Job', 'process_batch_merge');
1788 $defaultRuleGroupID = $this->callAPISuccessGetValue('RuleGroup', [
1789 'contact_type' => 'Individual',
1790 'used' => 'Unsupervised',
1792 'options' => ['limit' => 1],
1795 $duplicates = $this->callAPISuccess('Dedupe', 'getduplicates', ['rule_group_id' => $defaultRuleGroupID]);
1796 $this->assertEquals($conflicts['safe'], $duplicates['values'][0]['safe']);
1799 private function createEmployerOfMembership() {
1801 'domain_id' => CRM_Core_Config
::domainID(),
1802 'name' => 'Organization Membership',
1803 'description' => NULL,
1804 'member_of_contact_id' => 1,
1805 'financial_type_id' => 1,
1806 'minimum_fee' => 10,
1807 'duration_unit' => 'year',
1808 'duration_interval' => 1,
1809 'period_type' => 'rolling',
1810 'relationship_type_id' => 5,
1811 'relationship_direction' => 'b_a',
1812 'visibility' => 'Public',
1815 $membershipType = $this->callAPISuccess('membership_type', 'create', $params);
1816 return $membershipType["values"][$membershipType["id"]];
1820 * Verify successful update of household contact.
1822 * @param int $version
1824 * @dataProvider versionThreeAndFour
1826 public function testUpdateHouseholdWithAll($version) {
1827 $this->_apiversion
= $version;
1828 $contactID = $this->householdCreate();
1832 'household_name' => 'ABC household',
1833 'nick_name' => 'ABC House',
1834 'contact_type' => 'Household',
1837 $result = $this->callAPISuccess('Contact', 'Update', $params);
1840 'contact_type' => 'Household',
1842 'sort_name' => 'ABC household',
1843 'display_name' => 'ABC household',
1844 'nick_name' => 'ABC House',
1846 $this->getAndCheck($expected, $result['id'], 'contact');
1850 * Test civicrm_update() without contact type.
1852 * Deliberately exclude contact_type as it should still cope using civicrm_api.
1856 * @param int $version
1858 * @dataProvider versionThreeAndFour
1860 public function testUpdateCreateWithID($version) {
1861 $this->_apiversion
= $version;
1862 $contactID = $this->individualCreate();
1863 $this->callAPISuccess('Contact', 'Update', [
1865 'first_name' => 'abcd',
1866 'last_name' => 'wxyz',
1871 * Test civicrm_contact_delete() with no contact ID.
1873 * @param int $version
1875 * @dataProvider versionThreeAndFour
1877 public function testContactDeleteNoID($version) {
1878 $this->_apiversion
= $version;
1882 $this->callAPIFailure('contact', 'delete', $params);
1886 * Test civicrm_contact_delete() with error.
1888 * @param int $version
1890 * @dataProvider versionThreeAndFour
1892 public function testContactDeleteError($version) {
1893 $this->_apiversion
= $version;
1894 $params = ['contact_id' => 999];
1895 $this->callAPIFailure('contact', 'delete', $params);
1899 * Test civicrm_contact_delete().
1901 * @param int $version
1903 * @dataProvider versionThreeAndFour
1905 public function testContactDelete($version) {
1906 $this->_apiversion
= $version;
1907 $contactID = $this->individualCreate();
1911 $this->callAPIAndDocument('contact', 'delete', $params, __FUNCTION__
, __FILE__
);
1915 * Test civicrm_contact_get() return only first name.
1917 * @param int $version
1919 * @dataProvider versionThreeAndFour
1921 public function testContactGetRetFirst($version) {
1922 $this->_apiversion
= $version;
1923 $contact = $this->callAPISuccess('contact', 'create', $this->_params
);
1925 'contact_id' => $contact['id'],
1926 'return_first_name' => TRUE,
1927 'sort' => 'first_name',
1929 $result = $this->callAPISuccess('contact', 'get', $params);
1930 $this->assertEquals(1, $result['count']);
1931 $this->assertEquals($contact['id'], $result['id']);
1932 $this->assertEquals('abc1', $result['values'][$contact['id']]['first_name']);
1936 * Test civicrm_contact_get() return only first name & last name.
1938 * Use comma separated string return with a space.
1940 * @param int $version
1942 * @dataProvider versionThreeAndFour
1944 public function testContactGetReturnFirstLast($version) {
1945 $this->_apiversion
= $version;
1946 $contact = $this->callAPISuccess('contact', 'create', $this->_params
);
1948 'contact_id' => $contact['id'],
1949 'return' => 'first_name, last_name',
1951 $result = $this->callAPISuccess('contact', 'getsingle', $params);
1952 $this->assertEquals('abc1', $result['first_name']);
1953 $this->assertEquals('xyz1', $result['last_name']);
1954 //check that other defaults not returns
1955 $this->assertArrayNotHasKey('sort_name', $result);
1957 'contact_id' => $contact['id'],
1958 'return' => 'first_name,last_name',
1960 $result = $this->callAPISuccess('contact', 'getsingle', $params);
1961 $this->assertEquals('abc1', $result['first_name']);
1962 $this->assertEquals('xyz1', $result['last_name']);
1963 //check that other defaults not returns
1964 $this->assertArrayNotHasKey('sort_name', $result);
1968 * Test civicrm_contact_get() return only first name & last name.
1970 * Use comma separated string return without a space
1972 * @param int $version
1974 * @dataProvider versionThreeAndFour
1976 public function testContactGetReturnFirstLastNoComma($version) {
1977 $this->_apiversion
= $version;
1978 $contact = $this->callAPISuccess('contact', 'create', $this->_params
);
1980 'contact_id' => $contact['id'],
1981 'return' => 'first_name,last_name',
1983 $result = $this->callAPISuccess('contact', 'getsingle', $params);
1984 $this->assertEquals('abc1', $result['first_name']);
1985 $this->assertEquals('xyz1', $result['last_name']);
1986 //check that other defaults not returns
1987 $this->assertArrayNotHasKey('sort_name', $result);
1991 * Test civicrm_contact_get() with default return properties.
1993 public function testContactGetRetDefault() {
1994 $contactID = $this->individualCreate();
1996 'contact_id' => $contactID,
1997 'sort' => 'first_name',
1999 $result = $this->callAPISuccess('contact', 'get', $params);
2000 $this->assertEquals($contactID, $result['values'][$contactID]['contact_id']);
2001 $this->assertEquals('Anthony', $result['values'][$contactID]['first_name']);
2005 * Test civicrm_contact_getquick() with empty name param.
2007 public function testContactGetQuick() {
2008 $contactID = $this->individualCreate(['first_name' => 'Test', 'last_name' => 'Contact', 'email' => 'TestContact@example.com']);
2010 $result = $this->callAPISuccess('contact', 'getquick', ['name' => 'T']);
2011 $this->assertEquals($contactID, $result['values'][0]['id']);
2013 'name' => "TestContact@example.com",
2014 'field_name' => 'sort_name',
2016 $result = $this->callAPISuccess('contact', 'getquick', $params);
2017 $this->assertEquals($contactID, $result['values'][0]['id']);
2021 * Test civicrm_contact_get) with empty params.
2023 * @param int $version
2025 * @dataProvider versionThreeAndFour
2027 public function testContactGetEmptyParams($version) {
2028 $this->_apiversion
= $version;
2029 $this->callAPISuccess('contact', 'get', []);
2033 * Test civicrm_contact_get(,true) with no matches.
2035 * @param int $version
2037 * @dataProvider versionThreeAndFour
2039 public function testContactGetOldParamsNoMatches($version) {
2040 $this->_apiversion
= $version;
2041 $this->individualCreate();
2042 $result = $this->callAPISuccess('contact', 'get', ['first_name' => 'Fred']);
2043 $this->assertEquals(0, $result['count']);
2047 * Test civicrm_contact_get(,true) with one match.
2049 public function testContactGetOldParamsOneMatch() {
2050 $contactID = $this->individualCreate(['first_name' => 'Test', 'last_name' => 'Contact']);
2052 $result = $this->callAPISuccess('contact', 'get', ['first_name' => 'Test']);
2053 $this->assertEquals($contactID, $result['values'][$contactID]['contact_id']);
2054 $this->assertEquals($contactID, $result['id']);
2058 * Test civicrm_contact_search_count().
2060 public function testContactGetEmail() {
2062 'email' => 'man2@yahoo.com',
2063 'contact_type' => 'Individual',
2064 'location_type_id' => 1,
2067 $contact = $this->callAPISuccess('contact', 'create', $params);
2070 'email' => 'man2@yahoo.com',
2072 $result = $this->callAPIAndDocument('contact', 'get', $params, __FUNCTION__
, __FILE__
);
2073 $this->assertEquals('man2@yahoo.com', $result['values'][$result['id']]['email']);
2075 $this->callAPISuccess('contact', 'delete', $contact);
2079 * Ensure consistent return format for option group fields.
2081 * @param int $version
2083 * @dataProvider versionThreeAndFour
2085 public function testSetPreferredCommunicationNull($version) {
2086 $this->_apiversion
= $version;
2087 $contact = $this->callAPISuccess('contact', 'create', array_merge($this->_params
, [
2088 'preferred_communication_method' => ['Phone', 'SMS'],
2090 $preferredCommunicationMethod = $this->callAPISuccessGetValue('Contact', [
2091 'id' => $contact['id'],
2092 'return' => 'preferred_communication_method',
2094 $this->assertNotEmpty($preferredCommunicationMethod);
2095 $contact = $this->callAPISuccess('contact', 'create', array_merge($this->_params
, [
2096 'preferred_communication_method' => 'null',
2097 'id' => $contact['id'],
2099 $preferredCommunicationMethod = $this->callAPISuccessGetValue('Contact', [
2100 'id' => $contact['id'],
2101 'return' => 'preferred_communication_method',
2103 $this->assertEmpty($preferredCommunicationMethod);
2107 * Ensure consistent return format for option group fields.
2109 public function testPseudoFields() {
2111 'preferred_communication_method' => ['Phone', 'SMS'],
2112 'preferred_language' => 'en_US',
2113 'gender_id' => 'Female',
2114 'prefix_id' => 'Mrs.',
2115 'suffix_id' => 'II',
2116 'communication_style_id' => 'Formal',
2119 $contact = $this->callAPISuccess('contact', 'create', array_merge($this->_params
, $params));
2121 $result = $this->callAPISuccess('contact', 'getsingle', ['id' => $contact['id']]);
2122 $this->assertEquals('Both', $result['preferred_mail_format']);
2124 $this->assertEquals('en_US', $result['preferred_language']);
2125 $this->assertEquals(1, $result['communication_style_id']);
2126 $this->assertEquals(1, $result['gender_id']);
2127 $this->assertEquals('Female', $result['gender']);
2128 $this->assertEquals('Mrs.', $result['individual_prefix']);
2129 $this->assertEquals(1, $result['prefix_id']);
2130 $this->assertEquals('II', $result['individual_suffix']);
2131 $this->assertEquals(CRM_Core_PseudoConstant
::getKey("CRM_Contact_BAO_Contact", 'suffix_id', 'II'), $result['suffix_id']);
2132 $this->callAPISuccess('contact', 'delete', $contact);
2133 $this->assertEquals([
2134 CRM_Core_PseudoConstant
::getKey("CRM_Contact_BAO_Contact", 'preferred_communication_method', 'Phone'),
2135 CRM_Core_PseudoConstant
::getKey("CRM_Contact_BAO_Contact", 'preferred_communication_method', 'SMS'),
2136 ], $result['preferred_communication_method']);
2140 * Test birth date parameters.
2142 * These include value, array & birth_date_high, birth_date_low
2145 public function testContactGetBirthDate() {
2146 $contact1 = $this->callAPISuccess('contact', 'create', array_merge($this->_params
, ['birth_date' => 'first day of next month - 2 years']));
2147 $contact2 = $this->callAPISuccess('contact', 'create', array_merge($this->_params
, ['birth_date' => 'first day of next month - 5 years']));
2148 $contact3 = $this->callAPISuccess('contact', 'create', array_merge($this->_params
, ['birth_date' => 'first day of next month -20 years']));
2150 $result = $this->callAPISuccess('contact', 'get', []);
2151 $this->assertEquals(date('Y-m-d', strtotime('first day of next month -2 years')), $result['values'][$contact1['id']]['birth_date']);
2152 $result = $this->callAPISuccess('contact', 'get', ['birth_date' => 'first day of next month -5 years']);
2153 $this->assertEquals(1, $result['count']);
2154 $this->assertEquals(date('Y-m-d', strtotime('first day of next month -5 years')), $result['values'][$contact2['id']]['birth_date']);
2155 $result = $this->callAPISuccess('contact', 'get', ['birth_date_high' => date('Y-m-d', strtotime('-6 years'))]);
2156 $this->assertEquals(1, $result['count']);
2157 $this->assertEquals(date('Y-m-d', strtotime('first day of next month -20 years')), $result['values'][$contact3['id']]['birth_date']);
2158 $result = $this->callAPISuccess('contact', 'get', [
2159 'birth_date_low' => date('Y-m-d', strtotime('-6 years')),
2160 'birth_date_high' => date('Y-m-d', strtotime('- 3 years')),
2162 $this->assertEquals(1, $result['count']);
2163 $this->assertEquals(date('Y-m-d', strtotime('first day of next month -5 years')), $result['values'][$contact2['id']]['birth_date']);
2164 $result = $this->callAPISuccess('contact', 'get', [
2165 'birth_date_low' => '-6 years',
2166 'birth_date_high' => '- 3 years',
2168 $this->assertEquals(1, $result['count']);
2169 $this->assertEquals(date('Y-m-d', strtotime('first day of next month -5 years')), $result['values'][$contact2['id']]['birth_date']);
2173 * Test Address parameters
2175 * This include state_province, state_province_name, country
2177 public function testContactGetWithAddressFields() {
2180 'first_name' => 'abc1',
2181 'contact_type' => 'Individual',
2182 'last_name' => 'xyz1',
2183 'api.address.create' => [
2184 'country' => 'United States',
2185 'state_province_id' => 'Michigan',
2186 'location_type_id' => 1,
2190 'first_name' => 'abc2',
2191 'contact_type' => 'Individual',
2192 'last_name' => 'xyz2',
2193 'api.address.create' => [
2194 'country' => 'United States',
2195 'state_province_id' => 'Alabama',
2196 'location_type_id' => 1,
2200 foreach ($individuals as $params) {
2201 $contact = $this->callAPISuccess('contact', 'create', $params);
2204 // Check whether Contact get API return successfully with below Address params.
2206 'state_province_name' => 'Michigan',
2207 'state_province' => 'Michigan',
2208 'country' => 'United States',
2209 'state_province_name' => ['IN' => ['Michigan', 'Alabama']],
2210 'state_province' => ['IN' => ['Michigan', 'Alabama']],
2212 foreach ($fieldsToTest as $field => $value) {
2214 'id' => $contact['id'],
2217 $result = $this->callAPISuccess('Contact', 'get', $getParams);
2218 $this->assertEquals(1, $result['count']);
2223 * Test Deceased date parameters.
2225 * These include value, array & Deceased_date_high, Deceased date_low
2228 public function testContactGetDeceasedDate() {
2229 $contact1 = $this->callAPISuccess('contact', 'create', array_merge($this->_params
, ['deceased_date' => 'first day of next month - 2 years']));
2230 $contact2 = $this->callAPISuccess('contact', 'create', array_merge($this->_params
, ['deceased_date' => 'first day of next month - 5 years']));
2231 $contact3 = $this->callAPISuccess('contact', 'create', array_merge($this->_params
, ['deceased_date' => 'first day of next month -20 years']));
2233 $result = $this->callAPISuccess('contact', 'get', []);
2234 $this->assertEquals(date('Y-m-d', strtotime('first day of next month -2 years')), $result['values'][$contact1['id']]['deceased_date']);
2235 $result = $this->callAPISuccess('contact', 'get', ['deceased_date' => 'first day of next month -5 years']);
2236 $this->assertEquals(1, $result['count']);
2237 $this->assertEquals(date('Y-m-d', strtotime('first day of next month -5 years')), $result['values'][$contact2['id']]['deceased_date']);
2238 $result = $this->callAPISuccess('contact', 'get', ['deceased_date_high' => date('Y-m-d', strtotime('-6 years'))]);
2239 $this->assertEquals(1, $result['count']);
2240 $this->assertEquals(date('Y-m-d', strtotime('first day of next month -20 years')), $result['values'][$contact3['id']]['deceased_date']);
2241 $result = $this->callAPISuccess('contact', 'get', [
2242 'deceased_date_low' => '-6 years',
2243 'deceased_date_high' => date('Y-m-d', strtotime('- 3 years')),
2245 $this->assertEquals(1, $result['count']);
2246 $this->assertEquals(date('Y-m-d', strtotime('first day of next month -5 years')), $result['values'][$contact2['id']]['deceased_date']);
2250 * Test for Contact.get id=@user:username.
2252 public function testContactGetByUsername() {
2253 // Setup - create contact with a uf-match.
2254 $cid = $this->individualCreate([
2255 'contact_type' => 'Individual',
2256 'first_name' => 'testGetByUsername',
2257 'last_name' => 'testGetByUsername',
2261 'domain_id' => CRM_Core_Config
::domainID(),
2263 'uf_name' => 'the-email-matching-key-is-not-really-the-username',
2264 'contact_id' => $cid,
2266 $ufMatch = CRM_Core_BAO_UFMatch
::create($ufMatchParams);
2267 $this->assertTrue(is_numeric($ufMatch->id
));
2269 // setup - mock the calls to CRM_Utils_System_*::getUfId
2270 $mockFunction = $this->mockMethod
;
2271 $userSystem = $this->$mockFunction('CRM_Utils_System_UnitTests', ['getUfId']);
2272 $userSystem->expects($this->once())
2274 ->with($this->equalTo('exampleUser'))
2275 ->will($this->returnValue(99));
2276 CRM_Core_Config
::singleton()->userSystem
= $userSystem;
2279 $result = $this->callAPISuccess('Contact', 'get', [
2280 'id' => '@user:exampleUser',
2282 $this->assertEquals('testGetByUsername', $result['values'][$cid]['first_name']);
2284 // Check search of contacts with & without uf records
2285 $result = $this->callAPISuccess('Contact', 'get', ['uf_user' => 1]);
2286 $this->assertArrayHasKey($cid, $result['values']);
2288 $result = $this->callAPISuccess('Contact', 'get', ['uf_user' => 0]);
2289 $this->assertArrayNotHasKey($cid, $result['values']);
2293 * Test to check return works OK.
2295 public function testContactGetReturnValues() {
2297 'nick_name' => 'Bob',
2299 'email' => 'e@mail.com',
2301 $contactID = $this->individualCreate($extraParams);
2302 //actually it turns out the above doesn't create a phone
2303 $this->callAPISuccess('phone', 'create', ['contact_id' => $contactID, 'phone' => '456']);
2304 $result = $this->callAPISuccess('contact', 'getsingle', ['id' => $contactID]);
2305 foreach ($extraParams as $key => $value) {
2306 $this->assertEquals($result[$key], $value);
2308 //now we check they are still returned with 'return' key
2309 $result = $this->callAPISuccess('contact', 'getsingle', [
2311 'return' => array_keys($extraParams),
2313 foreach ($extraParams as $key => $value) {
2314 $this->assertEquals($result[$key], $value);
2319 * Test creating multiple phones using chaining.
2321 * @param int $version
2323 * @dataProvider versionThreeAndFour
2324 * @throws \Exception
2326 public function testCRM13252MultipleChainedPhones($version) {
2327 $this->_apiversion
= $version;
2328 $contactID = $this->householdCreate();
2329 $this->callAPISuccessGetCount('phone', ['contact_id' => $contactID], 0);
2331 'contact_id' => $contactID,
2332 'household_name' => 'Household 1',
2333 'contact_type' => 'Household',
2334 'api.phone.create' => [
2336 'phone' => '111-111-1111',
2337 'location_type_id' => 1,
2338 'phone_type_id' => 1,
2341 'phone' => '222-222-2222',
2342 'location_type_id' => 1,
2343 'phone_type_id' => 2,
2347 $this->callAPISuccess('contact', 'create', $params);
2348 $this->callAPISuccessGetCount('phone', ['contact_id' => $contactID], 2);
2353 * Test for Contact.get id=@user:username (with an invalid username).
2355 public function testContactGetByUnknownUsername() {
2356 // setup - mock the calls to CRM_Utils_System_*::getUfId
2357 $mockFunction = $this->mockMethod
;
2358 $userSystem = $this->$mockFunction('CRM_Utils_System_UnitTests', ['getUfId']);
2359 $userSystem->expects($this->once())
2361 ->with($this->equalTo('exampleUser'))
2362 ->will($this->returnValue(NULL));
2363 CRM_Core_Config
::singleton()->userSystem
= $userSystem;
2366 $result = $this->callAPIFailure('Contact', 'get', [
2367 'id' => '@user:exampleUser',
2369 $this->assertRegExp('/cannot be resolved to a contact ID/', $result['error_message']);
2373 * Verify attempt to create individual with chained arrays and sequential.
2375 * @param int $version
2377 * @dataProvider versionThreeAndFour
2379 public function testGetIndividualWithChainedArraysAndSequential($version) {
2380 $this->_apiversion
= $version;
2381 $ids = $this->entityCustomGroupWithSingleFieldCreate(__FUNCTION__
, __FILE__
);
2382 $params['custom_' . $ids['custom_field_id']] = "custom string";
2384 $moreIDs = $this->CustomGroupMultipleCreateWithFields();
2387 'first_name' => 'abc3',
2388 'last_name' => 'xyz3',
2389 'contact_type' => 'Individual',
2390 'email' => 'man3@yahoo.com',
2391 'api.website.create' => [
2393 'url' => "http://civicrm.org",
2396 'url' => "https://civicrm.org",
2401 $result = $this->callAPISuccess('Contact', 'create', $params);
2403 // delete the contact and custom groups
2404 $this->callAPISuccess('contact', 'delete', ['id' => $result['id']]);
2405 $this->customGroupDelete($ids['custom_group_id']);
2406 $this->customGroupDelete($moreIDs['custom_group_id']);
2408 $this->assertEquals($result['id'], $result['values'][0]['id']);
2409 $this->assertArrayKeyExists('api.website.create', $result['values'][0]);
2413 * Verify attempt to create individual with chained arrays.
2415 public function testGetIndividualWithChainedArrays() {
2416 $ids = $this->entityCustomGroupWithSingleFieldCreate(__FUNCTION__
, __FILE__
);
2417 $params['custom_' . $ids['custom_field_id']] = "custom string";
2419 $moreIDs = $this->CustomGroupMultipleCreateWithFields();
2420 $description = "This demonstrates the usage of chained api functions.\nIn this case no notes or custom fields have been created.";
2421 $subfile = "APIChainedArray";
2423 'first_name' => 'abc3',
2424 'last_name' => 'xyz3',
2425 'contact_type' => 'Individual',
2426 'email' => 'man3@yahoo.com',
2427 'api.contribution.create' => [
2428 'receive_date' => '2010-01-01',
2429 'total_amount' => 100.00,
2430 'financial_type_id' => 1,
2431 'payment_instrument_id' => 1,
2432 'non_deductible_amount' => 10.00,
2433 'fee_amount' => 50.00,
2434 'net_amount' => 90.00,
2436 'invoice_id' => 67890,
2438 'contribution_status_id' => 1,
2440 'api.contribution.create.1' => [
2441 'receive_date' => '2011-01-01',
2442 'total_amount' => 120.00,
2443 'financial_type_id' => $this->_financialTypeId
= 1,
2444 'payment_instrument_id' => 1,
2445 'non_deductible_amount' => 10.00,
2446 'fee_amount' => 50.00,
2447 'net_amount' => 90.00,
2449 'invoice_id' => 67830,
2451 'contribution_status_id' => 1,
2453 'api.website.create' => [
2455 'url' => "http://civicrm.org",
2460 $result = $this->callAPISuccess('Contact', 'create', $params);
2462 'id' => $result['id'],
2463 'api.website.get' => [],
2464 'api.Contribution.get' => [
2465 'total_amount' => '120.00',
2467 'api.CustomValue.get' => 1,
2468 'api.Note.get' => 1,
2470 $result = $this->callAPIAndDocument('Contact', 'Get', $params, __FUNCTION__
, __FILE__
, $description, $subfile);
2471 // delete the contact
2472 $this->callAPISuccess('contact', 'delete', $result);
2473 $this->customGroupDelete($ids['custom_group_id']);
2474 $this->customGroupDelete($moreIDs['custom_group_id']);
2475 $this->assertEquals(0, $result['values'][$result['id']]['api.website.get']['is_error']);
2476 $this->assertEquals("http://civicrm.org", $result['values'][$result['id']]['api.website.get']['values'][0]['url']);
2480 * Verify attempt to create individual with chained arrays and sequential.
2482 * @see https://issues.civicrm.org/jira/browse/CRM-15815
2484 * @param int $version
2486 * @dataProvider versionThreeAndFour
2488 public function testCreateIndividualWithChainedArrayAndSequential($version) {
2489 $this->_apiversion
= $version;
2492 'first_name' => 'abc5',
2493 'last_name' => 'xyz5',
2494 'contact_type' => 'Individual',
2495 'email' => 'woman5@yahoo.com',
2496 'api.phone.create' => [
2497 ['phone' => '03-231 07 95'],
2498 ['phone' => '03-232 51 62'],
2500 'api.website.create' => [
2501 'url' => 'http://civicrm.org',
2504 $result = $this->callAPISuccess('Contact', 'create', $params);
2506 // I could try to parse the result to see whether the two phone numbers
2507 // and the website are there, but I am not sure about the correct format.
2508 // So I will just fetch it again before checking.
2509 // See also http://forum.civicrm.org/index.php/topic,35393.0.html
2512 'id' => $result['id'],
2513 'api.website.get' => [],
2514 'api.phone.get' => [],
2516 $result = $this->callAPISuccess('Contact', 'get', $params);
2518 // delete the contact
2519 $this->callAPISuccess('contact', 'delete', $result);
2521 $this->assertEquals(2, $result['values'][0]['api.phone.get']['count']);
2522 $this->assertEquals(1, $result['values'][0]['api.website.get']['count']);
2526 * Test retrieving an individual with chained array syntax.
2528 public function testGetIndividualWithChainedArraysFormats() {
2529 $description = "This demonstrates the usage of chained api functions.\nIn this case no notes or custom fields have been created.";
2530 $subfile = "APIChainedArrayFormats";
2531 $ids = $this->entityCustomGroupWithSingleFieldCreate(__FUNCTION__
, __FILE__
);
2532 $params['custom_' . $ids['custom_field_id']] = "custom string";
2534 $moreIDs = $this->CustomGroupMultipleCreateWithFields();
2536 'first_name' => 'abc3',
2537 'last_name' => 'xyz3',
2538 'contact_type' => 'Individual',
2539 'email' => 'man3@yahoo.com',
2540 'api.contribution.create' => [
2541 'receive_date' => '2010-01-01',
2542 'total_amount' => 100.00,
2543 'financial_type_id' => $this->_financialTypeId
,
2544 'payment_instrument_id' => 1,
2545 'non_deductible_amount' => 10.00,
2546 'fee_amount' => 50.00,
2547 'net_amount' => 90.00,
2549 'contribution_status_id' => 1,
2550 'skipCleanMoney' => 1,
2552 'api.contribution.create.1' => [
2553 'receive_date' => '2011-01-01',
2554 'total_amount' => 120.00,
2555 'financial_type_id' => $this->_financialTypeId
,
2556 'payment_instrument_id' => 1,
2557 'non_deductible_amount' => 10.00,
2558 'fee_amount' => 50.00,
2559 'net_amount' => 90.00,
2561 'contribution_status_id' => 1,
2562 'skipCleanMoney' => 1,
2564 'api.website.create' => [
2566 'url' => "http://civicrm.org",
2571 $result = $this->callAPISuccess('Contact', 'create', $params);
2573 'id' => $result['id'],
2574 'api.website.getValue' => ['return' => 'url'],
2575 'api.Contribution.getCount' => [],
2576 'api.CustomValue.get' => 1,
2577 'api.Note.get' => 1,
2578 'api.Membership.getCount' => [],
2580 $result = $this->callAPIAndDocument('Contact', 'Get', $params, __FUNCTION__
, __FILE__
, $description, $subfile);
2581 $this->assertEquals(2, $result['values'][$result['id']]['api.Contribution.getCount']);
2582 $this->assertEquals(0, $result['values'][$result['id']]['api.Note.get']['is_error']);
2583 $this->assertEquals("http://civicrm.org", $result['values'][$result['id']]['api.website.getValue']);
2585 $this->callAPISuccess('contact', 'delete', $result);
2586 $this->customGroupDelete($ids['custom_group_id']);
2587 $this->customGroupDelete($moreIDs['custom_group_id']);
2591 * Test complex chaining.
2593 public function testGetIndividualWithChainedArraysAndMultipleCustom() {
2594 $ids = $this->entityCustomGroupWithSingleFieldCreate(__FUNCTION__
, __FILE__
);
2595 $params['custom_' . $ids['custom_field_id']] = "custom string";
2596 $moreIDs = $this->CustomGroupMultipleCreateWithFields();
2597 $andMoreIDs = $this->CustomGroupMultipleCreateWithFields([
2598 'title' => "another group",
2599 'name' => 'another name',
2601 $description = "This demonstrates the usage of chained api functions with multiple custom fields.";
2602 $subfile = "APIChainedArrayMultipleCustom";
2604 'first_name' => 'abc3',
2605 'last_name' => 'xyz3',
2606 'contact_type' => 'Individual',
2607 'email' => 'man3@yahoo.com',
2608 'api.contribution.create' => [
2609 'receive_date' => '2010-01-01',
2610 'total_amount' => 100.00,
2611 'financial_type_id' => 1,
2612 'payment_instrument_id' => 1,
2613 'non_deductible_amount' => 10.00,
2614 'fee_amount' => 50.00,
2615 'net_amount' => 90.00,
2617 'invoice_id' => 67890,
2619 'contribution_status_id' => 1,
2620 'skipCleanMoney' => 1,
2622 'api.contribution.create.1' => [
2623 'receive_date' => '2011-01-01',
2624 'total_amount' => 120.00,
2625 'financial_type_id' => 1,
2626 'payment_instrument_id' => 1,
2627 'non_deductible_amount' => 10.00,
2628 'fee_amount' => 50.00,
2629 'net_amount' => 90.00,
2631 'invoice_id' => 67830,
2633 'contribution_status_id' => 1,
2634 'skipCleanMoney' => 1,
2636 'api.website.create' => [
2638 'url' => "http://civicrm.org",
2641 'custom_' . $ids['custom_field_id'] => "value 1",
2642 'custom_' . $moreIDs['custom_field_id'][0] => "value 2",
2643 'custom_' . $moreIDs['custom_field_id'][1] => "warm beer",
2644 'custom_' . $andMoreIDs['custom_field_id'][1] => "vegemite",
2647 $result = $this->callAPISuccess('Contact', 'create', $params);
2648 $result = $this->callAPISuccess('Contact', 'create', [
2649 'contact_type' => 'Individual',
2650 'id' => $result['id'],
2652 $moreIDs['custom_field_id'][0] => "value 3",
2654 $ids['custom_field_id'] => "value 4",
2658 'id' => $result['id'],
2659 'api.website.getValue' => ['return' => 'url'],
2660 'api.Contribution.getCount' => [],
2661 'api.CustomValue.get' => 1,
2663 $result = $this->callAPIAndDocument('Contact', 'Get', $params, __FUNCTION__
, __FILE__
, $description, $subfile);
2665 $this->customGroupDelete($ids['custom_group_id']);
2666 $this->customGroupDelete($moreIDs['custom_group_id']);
2667 $this->customGroupDelete($andMoreIDs['custom_group_id']);
2668 $this->assertEquals(0, $result['values'][$result['id']]['api.CustomValue.get']['is_error']);
2669 $this->assertEquals('http://civicrm.org', $result['values'][$result['id']]['api.website.getValue']);
2673 * Test checks usage of $values to pick & choose inputs.
2675 * Api3 Only - chaining syntax is too funky for v4 (assuming entityTag "entity_id" field will be filled by magic)
2677 public function testChainingValuesCreate() {
2678 $description = "This demonstrates the usage of chained api functions. Specifically it has one 'parent function' &
2679 2 child functions - one receives values from the parent (Contact) and the other child (Tag).";
2680 $subfile = "APIChainedArrayValuesFromSiblingFunction";
2682 'display_name' => 'batman',
2683 'contact_type' => 'Individual',
2684 'api.tag.create' => [
2685 'name' => '$value.id',
2686 'description' => '$value.display_name',
2687 'format.only_id' => 1,
2689 'api.entity_tag.create' => ['tag_id' => '$value.api.tag.create'],
2691 $result = $this->callAPIAndDocument('Contact', 'Create', $params, __FUNCTION__
, __FILE__
, $description, $subfile);
2692 $this->assertEquals(0, $result['values'][$result['id']]['api.entity_tag.create']['is_error']);
2694 $tablesToTruncate = [
2697 'civicrm_entity_tag',
2700 $this->quickCleanup($tablesToTruncate, TRUE);
2704 * Test TrueFalse format - I couldn't come up with an easy way to get an error on Get.
2706 * @param int $version
2708 * @dataProvider versionThreeAndFour
2710 public function testContactGetFormatIsSuccessTrue($version) {
2711 $this->_apiversion
= $version;
2712 $contactID = $this->individualCreate(['first_name' => 'Test', 'last_name' => 'Contact']);
2713 $description = "This demonstrates use of the 'format.is_success' param.
2714 This param causes only the success or otherwise of the function to be returned as BOOLEAN";
2715 $subfile = "FormatIsSuccess_True";
2716 $params = ['id' => $contactID, 'format.is_success' => 1];
2717 $result = $this->callAPIAndDocument('Contact', 'Get', $params, __FUNCTION__
, __FILE__
, $description, $subfile);
2718 $this->assertEquals(1, $result);
2719 $this->callAPISuccess('Contact', 'Delete', $params);
2723 * Test TrueFalse format.
2725 * @param int $version
2727 * @dataProvider versionThreeAndFour
2729 public function testContactCreateFormatIsSuccessFalse($version) {
2730 $this->_apiversion
= $version;
2732 $description = "This demonstrates use of the 'format.is_success' param.
2733 This param causes only the success or otherwise of the function to be returned as BOOLEAN";
2734 $subfile = "FormatIsSuccess_Fail";
2735 $params = ['id' => 500, 'format.is_success' => 1];
2736 $result = $this->callAPIAndDocument('Contact', 'Create', $params, __FUNCTION__
, __FILE__
, $description, $subfile);
2737 $this->assertEquals(0, $result);
2741 * Test long display names.
2745 * @param int $version
2747 * @dataProvider versionThreeAndFour
2749 public function testContactCreateLongDisplayName($version) {
2750 $this->_apiversion
= $version;
2751 $result = $this->callAPISuccess('Contact', 'Create', [
2752 'first_name' => str_pad('a', 64, 'a'),
2753 'last_name' => str_pad('a', 64, 'a'),
2754 'contact_type' => 'Individual',
2756 $this->assertEquals('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', $result['values'][$result['id']]['display_name']);
2757 $this->assertEquals('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa, aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', $result['values'][$result['id']]['sort_name']);
2761 * Test that we can set the sort name via the api or alter it via a hook.
2763 * As of writing this is being fixed for Organization & Household but it makes sense to do for individuals too.
2765 * @param int $version
2767 * @dataProvider versionThreeAndFour
2769 public function testCreateAlterSortName($version) {
2770 $this->_apiversion
= $version;
2771 $organizationID = $this->organizationCreate(['organization_name' => 'The Justice League', 'sort_name' => 'Justice League, The']);
2772 $organization = $this->callAPISuccessGetSingle('Contact', ['return' => ['sort_name', 'display_name'], 'id' => $organizationID]);
2773 $this->assertEquals('Justice League, The', $organization['sort_name']);
2774 $this->assertEquals('The Justice League', $organization['display_name']);
2775 $this->hookClass
->setHook('civicrm_pre', [$this, 'killTheJusticeLeague']);
2776 $this->organizationCreate(['id' => $organizationID, 'sort_name' => 'Justice League, The']);
2777 $organization = $this->callAPISuccessGetSingle('Contact', ['return' => ['sort_name', 'display_name', 'is_deceased'], 'id' => $organizationID]);
2778 $this->assertEquals('Steppenwolf wuz here', $organization['display_name']);
2779 $this->assertEquals('Steppenwolf wuz here', $organization['sort_name']);
2780 $this->assertEquals(1, $organization['is_deceased']);
2782 $householdID = $this->householdCreate();
2783 $household = $this->callAPISuccessGetSingle('Contact', ['return' => ['sort_name', 'display_name'], 'id' => $householdID]);
2784 $this->assertEquals('Steppenwolf wuz here', $household['display_name']);
2785 $this->assertEquals('Steppenwolf wuz here', $household['sort_name']);
2789 * Implements hook_pre().
2791 public function killTheJusticeLeague($op, $entity, $id, &$params) {
2792 $params['sort_name'] = 'Steppenwolf wuz here';
2793 $params['display_name'] = 'Steppenwolf wuz here';
2794 $params['is_deceased'] = 1;
2798 * Test Single Entity format.
2800 * @param int $version
2802 * @dataProvider versionThreeAndFour
2804 public function testContactGetSingleEntityArray($version) {
2805 $this->_apiversion
= $version;
2806 $contactID = $this->individualCreate(['first_name' => 'Test', 'last_name' => 'Contact']);
2807 $description = "This demonstrates use of the 'format.single_entity_array' param.
2808 This param causes the only contact to be returned as an array without the other levels.
2809 It will be ignored if there is not exactly 1 result";
2810 $subfile = "GetSingleContact";
2811 $result = $this->callAPIAndDocument('Contact', 'GetSingle', ['id' => $contactID], __FUNCTION__
, __FILE__
, $description, $subfile);
2812 $this->assertEquals('Mr. Test Contact II', $result['display_name']);
2813 $this->callAPISuccess('Contact', 'Delete', ['id' => $contactID]);
2817 * Test Single Entity format.
2819 * @param int $version
2821 * @dataProvider versionThreeAndFour
2823 public function testContactGetFormatCountOnly($version) {
2824 $this->_apiversion
= $version;
2825 $contactID = $this->individualCreate(['first_name' => 'Test', 'last_name' => 'Contact']);
2826 $description = "This demonstrates use of the 'getCount' action.
2827 This param causes the count of the only function to be returned as an integer.";
2828 $params = ['id' => $contactID];
2829 $result = $this->callAPIAndDocument('Contact', 'GetCount', $params, __FUNCTION__
, __FILE__
, $description,
2831 $this->assertEquals('1', $result);
2832 $this->callAPISuccess('Contact', 'Delete', $params);
2836 * Test id only format.
2838 * @param int $version
2840 * @dataProvider versionThreeAndFour
2842 public function testContactGetFormatIDOnly($version) {
2843 $this->_apiversion
= $version;
2844 $contactID = $this->individualCreate(['first_name' => 'Test', 'last_name' => 'Contact']);
2845 $description = "This demonstrates use of the 'format.id_only' param.
2846 This param causes the id of the only entity to be returned as an integer.
2847 It will be ignored if there is not exactly 1 result";
2848 $subfile = "FormatOnlyID";
2849 $params = ['id' => $contactID, 'format.only_id' => 1];
2850 $result = $this->callAPIAndDocument('Contact', 'Get', $params, __FUNCTION__
, __FILE__
, $description, $subfile);
2851 $this->assertEquals($contactID, $result);
2852 $this->callAPISuccess('Contact', 'Delete', $params);
2856 * Test id only format.
2858 * @param int $version
2860 * @dataProvider versionThreeAndFour
2862 public function testContactGetFormatSingleValue($version) {
2863 $this->_apiversion
= $version;
2864 $contactID = $this->individualCreate(['first_name' => 'Test', 'last_name' => 'Contact']);
2865 $description = "This demonstrates use of the 'format.single_value' param.
2866 This param causes only a single value of the only entity to be returned as an string.
2867 It will be ignored if there is not exactly 1 result";
2868 $subFile = "FormatSingleValue";
2869 $params = ['id' => $contactID, 'return' => 'display_name'];
2870 $result = $this->callAPIAndDocument('Contact', 'getvalue', $params, __FUNCTION__
, __FILE__
, $description, $subFile);
2871 $this->assertEquals('Mr. Test Contact II', $result);
2872 $this->callAPISuccess('Contact', 'Delete', $params);
2876 * Test that permissions are respected when creating contacts.
2878 * @param int $version
2880 * @dataProvider versionThreeAndFour
2882 public function testContactCreationPermissions($version) {
2883 $this->_apiversion
= $version;
2885 'contact_type' => 'Individual',
2886 'first_name' => 'Foo',
2887 'last_name' => 'Bear',
2888 'check_permissions' => TRUE,
2890 $config = CRM_Core_Config
::singleton();
2891 $config->userPermissionClass
->permissions
= ['access CiviCRM'];
2892 $result = $this->callAPIFailure('contact', 'create', $params);
2893 $this->assertContains('failed', $result['error_message'], 'lacking permissions should not be enough to create a contact');
2895 $config->userPermissionClass
->permissions
= ['access CiviCRM', 'add contacts', 'import contacts'];
2896 $this->callAPISuccess('contact', 'create', $params);
2900 * Test that delete with skip undelete respects permissions.
2903 public function testContactDeletePermissions() {
2904 $contactID = $this->individualCreate();
2905 CRM_Core_Config
::singleton()->userPermissionClass
->permissions
= ['access CiviCRM'];
2906 $this->callAPIFailure('Contact', 'delete', [
2908 'check_permissions' => 1,
2909 'skip_undelete' => 1,
2911 $this->callAPISuccess('Contact', 'delete', [
2913 'check_permissions' => 0,
2914 'skip_undelete' => 1,
2919 * Test update with check permissions set.
2921 * @param int $version
2923 * @dataProvider versionThreeAndFour
2925 public function testContactUpdatePermissions($version) {
2926 $this->_apiversion
= $version;
2928 'contact_type' => 'Individual',
2929 'first_name' => 'Foo',
2930 'last_name' => 'Bear',
2931 'check_permissions' => TRUE,
2933 $result = $this->callAPISuccess('contact', 'create', $params);
2934 $config = CRM_Core_Config
::singleton();
2936 'id' => $result['id'],
2937 'contact_type' => 'Individual',
2938 'last_name' => 'Bar',
2939 'check_permissions' => TRUE,
2942 $config->userPermissionClass
->permissions
= ['access CiviCRM'];
2943 $result = $this->callAPIFailure('contact', 'update', $params);
2944 $this->assertEquals('Permission denied to modify contact record', $result['error_message']);
2946 $config->userPermissionClass
->permissions
= [
2949 'view all contacts',
2950 'edit all contacts',
2953 $this->callAPISuccess('contact', 'update', $params);
2957 * Test contact proximity api.
2959 public function testContactProximity() {
2960 // first create a contact with a SF location with a specific
2962 $contactID = $this->organizationCreate();
2964 // now create the address
2966 'street_address' => '123 Main Street',
2967 'city' => 'San Francisco',
2969 'country_id' => 1228,
2970 'state_province_id' => 1004,
2971 'geo_code_1' => '37.79',
2972 'geo_code_2' => '-122.40',
2973 'location_type_id' => 1,
2974 'contact_id' => $contactID,
2977 $result = $this->callAPISuccess('address', 'create', $params);
2978 $this->assertEquals(1, $result['count']);
2980 // now do a proximity search with a close enough geocode and hope to match
2981 // that specific contact only!
2984 'longitude' => -122.3,
2988 $result = $this->callAPISuccess('contact', 'proximity', $proxParams);
2989 $this->assertEquals(1, $result['count']);
2993 * Test that Ajax API permission is sufficient to access getquick api.
2995 * (note that getquick api is required for autocomplete & has ACL permissions applied)
2997 public function testGetquickPermissionCRM13744() {
2998 CRM_Core_Config
::singleton()->userPermissionClass
->permissions
= ['access CiviEvent'];
2999 $this->callAPIFailure('contact', 'getquick', ['name' => 'b', 'check_permissions' => TRUE]);
3000 CRM_Core_Config
::singleton()->userPermissionClass
->permissions
= ['access CiviCRM'];
3001 $this->callAPISuccess('contact', 'getquick', ['name' => 'b', 'check_permissions' => TRUE]);
3002 CRM_Core_Config
::singleton()->userPermissionClass
->permissions
= ['access AJAX API'];
3003 $this->callAPISuccess('contact', 'getquick', ['name' => 'b', 'check_permissions' => TRUE]);
3007 * Test that getquick returns contacts with an exact first name match first.
3009 * The search string 'b' & 'bob' both return ordered by sort_name if includeOrderByClause
3010 * is true (default) but if it is false then matches are returned in ID order.
3012 * @dataProvider getSearchSortOptions
3014 public function testGetQuickExactFirst($searchParameters, $settings, $firstContact, $secondContact = NULL) {
3015 $this->getQuickSearchSampleData();
3016 $this->callAPISuccess('Setting', 'create', $settings);
3017 $result = $this->callAPISuccess('contact', 'getquick', $searchParameters);
3018 $this->assertEquals($firstContact, $result['values'][0]['sort_name']);
3019 $this->assertEquals($secondContact, $result['values'][1]['sort_name']);
3020 $this->callAPISuccess('Setting', 'create', ['includeWildCardInName' => TRUE, 'includeOrderByClause' => TRUE]);
3023 public function getSearchSortOptions() {
3024 $firstAlphabeticalContactBySortName = 'A Bobby, Bobby';
3025 $secondAlphabeticalContactBySortName = 'Aadvark, Bob';
3026 $secondAlphabeticalContactWithEmailBySortName = 'Bob, Bob';
3027 $firstAlphabeticalContactFirstNameBob = 'Aadvark, Bob';
3028 $secondAlphabeticalContactFirstNameBob = 'Bob, Bob';
3029 $firstByIDContactFirstNameBob = 'Bob, Bob';
3030 $secondByIDContactFirstNameBob = 'K Bobby, Bob';
3031 $firstContactByID = 'Bob, Bob';
3032 $secondContactByID = 'E Bobby, Bobby';
3033 $bobLikeEmail = 'A Bobby, Bobby';
3036 'empty_search_basic' => [
3037 'search_parameters' => ['name' => '%'],
3038 'settings' => ['includeWildCardInName' => TRUE, 'includeOrderByClause' => TRUE],
3039 'first_contact' => $firstAlphabeticalContactBySortName,
3040 'second_contact' => $secondAlphabeticalContactBySortName,
3042 'empty_search_basic_no_wildcard' => [
3043 'search_parameters' => ['name' => '%'],
3044 'settings' => ['includeWildCardInName' => FALSE, 'includeOrderByClause' => TRUE],
3045 'first_contact' => $firstAlphabeticalContactBySortName,
3046 'second_contact' => $secondAlphabeticalContactBySortName,
3048 'single_letter_search_basic' => [
3049 'search_parameters' => ['name' => 'b'],
3050 'settings' => ['includeWildCardInName' => TRUE, 'includeOrderByClause' => TRUE],
3051 'first_contact' => $firstAlphabeticalContactBySortName,
3052 'second_contact' => $secondAlphabeticalContactBySortName,
3054 'bob_search_basic' => [
3055 'search_parameters' => ['name' => 'bob'],
3056 'settings' => ['includeWildCardInName' => TRUE, 'includeOrderByClause' => TRUE],
3057 'first_contact' => $firstAlphabeticalContactBySortName,
3058 'second_contact' => $secondAlphabeticalContactBySortName,
3060 // This test has been disabled as is proving to be problematic to reproduce due to MySQL sorting issues between different versions
3061 // 'bob_search_no_orderby' => array(
3062 // 'search_parameters' => array('name' => 'bob'),
3063 // 'settings' => array('includeWildCardInName' => TRUE, 'includeOrderByClause' => FALSE),
3064 // 'first_contact' => $firstContactByID,
3065 // 'second_contact' => $secondContactByID,
3067 'bob_search_no_wildcard' => [
3068 'search_parameters' => ['name' => 'bob'],
3069 'settings' => ['includeWildCardInName' => FALSE, 'includeOrderByClause' => TRUE],
3070 'second_contact' => $bobLikeEmail,
3071 'first_contact' => $secondAlphabeticalContactFirstNameBob,
3073 // This should be the same as just no wildcard as if we had an exactMatch while searching by
3074 // sort name it would rise to the top CRM-19547
3075 'bob_search_no_wildcard_no_orderby' => [
3076 'search_parameters' => ['name' => 'bob'],
3077 'settings' => ['includeWildCardInName' => FALSE, 'includeOrderByClause' => TRUE],
3078 'second_contact' => $bobLikeEmail,
3079 'first_contact' => $secondAlphabeticalContactFirstNameBob,
3081 'first_name_search_basic' => [
3082 'search_parameters' => ['name' => 'bob', 'field_name' => 'first_name'],
3083 'settings' => ['includeWildCardInName' => TRUE, 'includeOrderByClause' => TRUE],
3084 'first_contact' => $firstAlphabeticalContactFirstNameBob,
3085 'second_contact' => $secondAlphabeticalContactFirstNameBob,
3087 'first_name_search_no_wildcard' => [
3088 'search_parameters' => ['name' => 'bob', 'field_name' => 'first_name'],
3089 'settings' => ['includeWildCardInName' => FALSE, 'includeOrderByClause' => TRUE],
3090 'first_contact' => $firstAlphabeticalContactFirstNameBob,
3091 'second_contact' => $secondAlphabeticalContactFirstNameBob,
3093 // This test has been disabled as is proving to be problematic to reproduce due to MySQL sorting issues between different versions
3094 //'first_name_search_no_orderby' => array(
3095 // 'search_parameters' => array('name' => 'bob', 'field_name' => 'first_name'),
3096 // 'settings' => array('includeWildCardInName' => TRUE, 'includeOrderByClause' => FALSE),
3097 // 'first_contact' => $firstByIDContactFirstNameBob,
3098 // 'second_contact' => $secondByIDContactFirstNameBob,
3100 'email_search_basic' => [
3101 'search_parameters' => ['name' => 'bob', 'field_name' => 'email', 'table_name' => 'eml'],
3102 'settings' => ['includeWildCardInName' => FALSE, 'includeOrderByClause' => TRUE],
3103 'first_contact' => $firstAlphabeticalContactBySortName,
3104 'second_contact' => $secondAlphabeticalContactWithEmailBySortName,
3110 * Test that getquick returns contacts with an exact first name match first.
3112 public function testGetQuickEmail() {
3113 $this->getQuickSearchSampleData();
3114 $loggedInContactID = $this->createLoggedInUser();
3115 $result = $this->callAPISuccess('contact', 'getquick', [
3119 'A Bobby, Bobby :: bob@bobby.com',
3120 'Bob, Bob :: bob@bob.com',
3122 'H Bobby, Bobby :: bob@h.com',
3124 $this->callAPISuccessGetValue('Contact', ['id' => $loggedInContactID, 'return' => 'last_name']) . ', Logged In :: anthony_anderson@civicrm.org',
3126 $this->assertEquals(6, $result['count']);
3127 foreach ($expectedData as $index => $value) {
3128 $this->assertEquals($value, $result['values'][$index]['data']);
3130 $result = $this->callAPISuccess('contact', 'getquick', [
3134 'H Bobby, Bobby :: bob@h.com',
3136 foreach ($expectedData as $index => $value) {
3137 $this->assertEquals($value, $result['values'][$index]['data']);
3139 $this->callAPISuccess('Setting', 'create', ['includeWildCardInName' => FALSE]);
3140 $result = $this->callAPISuccess('contact', 'getquick', [
3143 $this->callAPISuccess('Setting', 'create', ['includeWildCardInName' => TRUE]);
3144 $this->assertEquals(0, $result['count']);
3148 * Test that getquick returns contacts with an exact first name match first.
3150 public function testGetQuickEmailACL() {
3151 $this->getQuickSearchSampleData();
3152 $loggedInContactID = $this->createLoggedInUser();
3153 CRM_Core_Config
::singleton()->userPermissionClass
->permissions
= [];
3154 $result = $this->callAPISuccess('contact', 'getquick', [
3157 $this->assertEquals(0, $result['count']);
3159 $this->hookClass
->setHook('civicrm_aclWhereClause', [$this, 'aclWhereNoBobH']);
3160 CRM_Contact_BAO_Contact_Permission
::cache($loggedInContactID, CRM_Core_Permission
::VIEW
, TRUE);
3161 $result = $this->callAPISuccess('contact', 'getquick', [
3165 // Without the acl it would be 6 like the previous email getquick test.
3166 $this->assertEquals(5, $result['count']);
3168 'A Bobby, Bobby :: bob@bobby.com',
3169 'Bob, Bob :: bob@bob.com',
3172 $this->callAPISuccessGetValue('Contact', ['id' => $loggedInContactID, 'return' => 'last_name']) . ', Logged In :: anthony_anderson@civicrm.org',
3174 foreach ($expectedData as $index => $value) {
3175 $this->assertEquals($value, $result['values'][$index]['data']);
3180 * Test that getquick returns contacts with an exact first name match first.
3182 public function testGetQuickExternalID() {
3183 $this->getQuickSearchSampleData();
3184 $result = $this->callAPISuccess('contact', 'getquick', [
3186 'field_name' => 'external_identifier',
3187 'table_name' => 'cc',
3189 $this->assertEquals(0, $result['count']);
3190 $result = $this->callAPISuccess('contact', 'getquick', [
3192 'field_name' => 'external_identifier',
3193 'table_name' => 'cc',
3195 $this->assertEquals(1, $result['count']);
3196 $this->assertEquals('Bob, Bob', $result['values'][0]['sort_name']);
3200 * Test that getquick returns contacts with an exact first name match first.
3202 public function testGetQuickID() {
3203 $max = CRM_Core_DAO
::singleValueQuery("SELECT max(id) FROM civicrm_contact");
3204 $this->getQuickSearchSampleData();
3205 $result = $this->callAPISuccess('contact', 'getquick', [
3207 'field_name' => 'id',
3208 'table_name' => 'cc',
3210 $this->assertEquals(1, $result['count']);
3211 $this->assertEquals('E Bobby, Bobby', $result['values'][0]['sort_name']);
3212 $result = $this->callAPISuccess('contact', 'getquick', [
3214 'field_name' => 'contact_id',
3215 'table_name' => 'cc',
3217 $this->assertEquals(1, $result['count']);
3218 $this->assertEquals('E Bobby, Bobby', $result['values'][0]['sort_name']);
3222 * Test that getquick returns contacts with an exact first name match first.
3224 * Depending on the setting the sort name sort might click in next or not - test!
3226 public function testGetQuickFirstName() {
3227 $this->getQuickSearchSampleData();
3228 $this->callAPISuccess('Setting', 'create', ['includeOrderByClause' => TRUE]);
3229 $result = $this->callAPISuccess('contact', 'getquick', [
3231 'field_name' => 'first_name',
3232 'table_name' => 'cc',
3241 foreach ($expected as $index => $value) {
3242 $this->assertEquals($value, $result['values'][$index]['sort_name']);
3244 $this->callAPISuccess('Setting', 'create', ['includeOrderByClause' => FALSE]);
3245 $result = $this->callAPISuccess('contact', 'getquick', ['name' => 'bob']);
3246 $this->assertEquals('Bob, Bob', $result['values'][0]['sort_name']);
3247 // This test has been disabled as is proving to be problematic to reproduce due to MySQL sorting issues between different versions
3248 //$this->assertEquals('E Bobby, Bobby', $result['values'][1]['sort_name']);
3252 * Test that getquick applies ACLs.
3254 public function testGetQuickFirstNameACLs() {
3255 $this->getQuickSearchSampleData();
3256 $userID = $this->createLoggedInUser();
3257 $this->callAPISuccess('Setting', 'create', ['includeOrderByClause' => TRUE, 'search_autocomplete_count' => 15]);
3258 CRM_Core_Config
::singleton()->userPermissionClass
->permissions
= [];
3259 $result = $this->callAPISuccess('contact', 'getquick', [
3261 'field_name' => 'first_name',
3262 'table_name' => 'cc',
3264 $this->assertEquals(0, $result['count']);
3266 $this->hookClass
->setHook('civicrm_aclWhereClause', [$this, 'aclWhereNoBobH']);
3267 CRM_Contact_BAO_Contact_Permission
::cache($userID, CRM_Core_Permission
::VIEW
, TRUE);
3268 $result = $this->callAPISuccess('contact', 'getquick', [
3270 'field_name' => 'first_name',
3271 'table_name' => 'cc',
3273 $this->assertEquals('K Bobby, Bob', $result['values'][2]['sort_name']);
3274 // Without the ACL 9 would be bob@h.com.
3275 $this->assertEquals('I Bobby, Bobby', $result['values'][10]['sort_name']);
3279 * Full results returned.
3281 * @implements CRM_Utils_Hook::aclWhereClause
3283 * @param string $type
3284 * @param array $tables
3285 * @param array $whereTables
3286 * @param int $contactID
3287 * @param string $where
3289 public function aclWhereNoBobH($type, &$tables, &$whereTables, &$contactID, &$where) {
3290 $where = " (email <> 'bob@h.com' OR email IS NULL) ";
3291 $whereTables['civicrm_email'] = "LEFT JOIN civicrm_email e ON contact_a.id = e.contact_id";
3295 * Test that getquick returns contacts with an exact last name match first.
3297 public function testGetQuickLastName() {
3298 $this->getQuickSearchSampleData();
3299 $this->callAPISuccess('Setting', 'create', ['includeOrderByClause' => TRUE]);
3300 $result = $this->callAPISuccess('contact', 'getquick', [
3302 'field_name' => 'last_name',
3303 'table_name' => 'cc',
3311 foreach ($expected as $index => $value) {
3312 $this->assertEquals($value, $result['values'][$index]['sort_name']);
3314 $this->callAPISuccess('Setting', 'create', ['includeOrderByClause' => FALSE]);
3315 $result = $this->callAPISuccess('contact', 'getquick', ['name' => 'bob']);
3316 $this->assertEquals('Bob, Bob :: bob@bob.com', $result['values'][0]['data']);
3320 * Test that getquick returns contacts by city.
3322 public function testGetQuickCity() {
3323 $this->getQuickSearchSampleData();
3324 $result = $this->callAPISuccess('contact', 'getquick', [
3326 'field_name' => 'city',
3327 'table_name' => 'sts',
3329 $this->assertEquals('B Bobby, Bobby :: Toronto', $result['values'][0]['data']);
3330 $result = $this->callAPISuccess('contact', 'getquick', [
3332 'field_name' => 'city',
3333 'table_name' => 'sts',
3335 $this->assertEquals('B Bobby, Bobby :: Toronto', $result['values'][0]['data']);
3336 $this->assertEquals('C Bobby, Bobby :: Whanganui', $result['values'][1]['data']);
3340 * Set up some sample data for testing quicksearch.
3342 public function getQuickSearchSampleData() {
3344 ['first_name' => 'Bob', 'last_name' => 'Bob', 'external_identifier' => 'abc', 'email' => 'bob@bob.com'],
3345 ['first_name' => 'Bobby', 'last_name' => 'E Bobby', 'external_identifier' => 'abcd'],
3347 'first_name' => 'Bobby',
3348 'last_name' => 'B Bobby',
3349 'external_identifier' => 'bcd',
3350 'api.address.create' => [
3351 'street_address' => 'Sesame Street',
3352 'city' => 'Toronto',
3353 'location_type_id' => 1,
3357 'first_name' => 'Bobby',
3358 'last_name' => 'C Bobby',
3359 'external_identifier' => 'bcde',
3360 'api.address.create' => [
3361 'street_address' => 'Te huarahi',
3362 'city' => 'Whanganui',
3363 'location_type_id' => 1,
3366 ['first_name' => 'Bobby', 'last_name' => 'D Bobby', 'external_identifier' => 'efg'],
3367 ['first_name' => 'Bobby', 'last_name' => 'A Bobby', 'external_identifier' => 'hij', 'email' => 'bob@bobby.com'],
3368 ['first_name' => 'Bobby', 'last_name' => 'F Bobby', 'external_identifier' => 'klm'],
3369 ['first_name' => 'Bobby', 'last_name' => 'G Bobby', 'external_identifier' => 'nop'],
3370 ['first_name' => 'Bobby', 'last_name' => 'H Bobby', 'external_identifier' => 'qrs', 'email' => 'bob@h.com'],
3371 ['first_name' => 'Bobby', 'last_name' => 'I Bobby'],
3372 ['first_name' => 'Bobby', 'last_name' => 'J Bobby'],
3373 ['first_name' => 'Bob', 'last_name' => 'K Bobby', 'external_identifier' => 'bcdef'],
3374 ['first_name' => 'Bob', 'last_name' => 'Aadvark'],
3376 foreach ($contacts as $type => $contact) {
3377 $contact['contact_type'] = 'Individual';
3378 $this->callAPISuccess('Contact', 'create', $contact);
3383 * Test get ref api - gets a list of references to an entity.
3385 public function testGetReferenceCounts() {
3386 $result = $this->callAPISuccess('Contact', 'create', [
3387 'first_name' => 'Testily',
3388 'last_name' => 'McHaste',
3389 'contact_type' => 'Individual',
3390 'api.Address.replace' => [
3393 'api.Email.replace' => [
3396 'email' => 'spam@dev.null',
3398 'location_type_id' => 1,
3402 'api.Phone.replace' => [
3405 'phone' => '234-567-0001',
3407 'location_type_id' => 1,
3410 'phone' => '234-567-0002',
3412 'location_type_id' => 1,
3418 //$dao = new CRM_Contact_BAO_Contact();
3419 //$dao->id = $result['id'];
3420 //$this->assertTrue((bool) $dao->find(TRUE));
3422 //$refCounts = $dao->getReferenceCounts();
3423 //$this->assertTrue(is_array($refCounts));
3424 //$refCountsIdx = CRM_Utils_Array::index(array('name'), $refCounts);
3426 $refCounts = $this->callAPISuccess('Contact', 'getrefcount', [
3427 'id' => $result['id'],
3429 $refCountsIdx = CRM_Utils_Array
::index(['name'], $refCounts['values']);
3431 $this->assertEquals(1, $refCountsIdx['sql:civicrm_email:contact_id']['count']);
3432 $this->assertEquals('civicrm_email', $refCountsIdx['sql:civicrm_email:contact_id']['table']);
3433 $this->assertEquals(2, $refCountsIdx['sql:civicrm_phone:contact_id']['count']);
3434 $this->assertEquals('civicrm_phone', $refCountsIdx['sql:civicrm_phone:contact_id']['table']);
3435 $this->assertTrue(!isset($refCountsIdx['sql:civicrm_address:contact_id']));
3439 * Test the use of sql operators.
3441 * @param int $version
3443 * @dataProvider versionThreeAndFour
3445 public function testSQLOperatorsOnContactAPI($version) {
3446 $this->_apiversion
= $version;
3447 $this->individualCreate();
3448 $this->organizationCreate();
3449 $this->householdCreate();
3450 $contacts = $this->callAPISuccess('contact', 'get', ['legal_name' => ['IS NOT NULL' => TRUE]]);
3451 $this->assertEquals($contacts['count'], CRM_Core_DAO
::singleValueQuery('select count(*) FROM civicrm_contact WHERE legal_name IS NOT NULL'));
3452 $contacts = $this->callAPISuccess('contact', 'get', ['legal_name' => ['IS NULL' => TRUE]]);
3453 $this->assertEquals($contacts['count'], CRM_Core_DAO
::singleValueQuery('select count(*) FROM civicrm_contact WHERE legal_name IS NULL'));
3457 * CRM-14743 - test api respects search operators.
3459 * @param int $version
3461 * @dataProvider versionThreeAndFour
3463 public function testGetModifiedDateByOperators($version) {
3464 $this->_apiversion
= $version;
3465 $preExistingContactCount = CRM_Core_DAO
::singleValueQuery('select count(*) FROM civicrm_contact');
3466 $contact1 = $this->individualCreate();
3467 $sql = "UPDATE civicrm_contact SET created_date = '2012-01-01', modified_date = '2013-01-01' WHERE id = " . $contact1;
3468 CRM_Core_DAO
::executeQuery($sql);
3469 $contact2 = $this->individualCreate();
3470 $sql = "UPDATE civicrm_contact SET created_date = '2012-02-01', modified_date = '2013-02-01' WHERE id = " . $contact2;
3471 CRM_Core_DAO
::executeQuery($sql);
3472 $contact3 = $this->householdCreate();
3473 $sql = "UPDATE civicrm_contact SET created_date = '2012-03-01', modified_date = '2013-03-01' WHERE id = " . $contact3;
3474 CRM_Core_DAO
::executeQuery($sql);
3475 $contacts = $this->callAPISuccess('contact', 'get', ['modified_date' => ['<' => '2014-01-01']]);
3476 $this->assertEquals($contacts['count'], 3);
3477 $contacts = $this->callAPISuccess('contact', 'get', ['modified_date' => ['>' => '2014-01-01']]);
3478 $this->assertEquals($contacts['count'], $preExistingContactCount);
3482 * CRM-14743 - test api respects search operators.
3484 * @param int $version
3486 * @dataProvider versionThreeAndFour
3488 public function testGetCreatedDateByOperators($version) {
3489 $this->_apiversion
= $version;
3490 $preExistingContactCount = CRM_Core_DAO
::singleValueQuery('select count(*) FROM civicrm_contact');
3491 $contact1 = $this->individualCreate();
3492 $sql = "UPDATE civicrm_contact SET created_date = '2012-01-01' WHERE id = " . $contact1;
3493 CRM_Core_DAO
::executeQuery($sql);
3494 $contact2 = $this->individualCreate();
3495 $sql = "UPDATE civicrm_contact SET created_date = '2012-02-01' WHERE id = " . $contact2;
3496 CRM_Core_DAO
::executeQuery($sql);
3497 $contact3 = $this->householdCreate();
3498 $sql = "UPDATE civicrm_contact SET created_date = '2012-03-01' WHERE id = " . $contact3;
3499 CRM_Core_DAO
::executeQuery($sql);
3500 $contacts = $this->callAPISuccess('contact', 'get', ['created_date' => ['<' => '2014-01-01']]);
3501 $this->assertEquals($contacts['count'], 3);
3502 $contacts = $this->callAPISuccess('contact', 'get', ['created_date' => ['>' => '2014-01-01']]);
3503 $this->assertEquals($contacts['count'], $preExistingContactCount);
3507 * CRM-14263 check that API is not affected by search profile related bug.
3509 public function testReturnCityProfile() {
3510 $contactID = $this->individualCreate();
3511 CRM_Core_Config
::singleton()->defaultSearchProfileID
= 1;
3512 $this->callAPISuccess('address', 'create', [
3513 'contact_id' => $contactID,
3514 'city' => 'Cool City',
3515 'location_type_id' => 1,
3517 $result = $this->callAPISuccess('contact', 'get', ['city' => 'Cool City', 'return' => 'contact_type']);
3518 $this->assertEquals(1, $result['count']);
3522 * CRM-15443 - ensure getlist api does not return deleted contacts.
3524 public function testGetlistExcludeConditions() {
3526 $contact = $this->individualCreate(['last_name' => $name]);
3527 $this->individualCreate(['last_name' => $name, 'is_deceased' => 1]);
3528 $this->individualCreate(['last_name' => $name, 'is_deleted' => 1]);
3529 // We should get all but the deleted contact.
3530 $result = $this->callAPISuccess('contact', 'getlist', ['input' => $name]);
3531 $this->assertEquals(2, $result['count']);
3532 // Force-exclude the deceased contact.
3533 $result = $this->callAPISuccess('contact', 'getlist', [
3535 'params' => ['is_deceased' => 0],
3537 $this->assertEquals(1, $result['count']);
3538 $this->assertEquals($contact, $result['values'][0]['id']);
3542 * Test contact getactions.
3544 public function testGetActions() {
3545 $description = "Getting the available actions for an entity.";
3546 $result = $this->callAPIAndDocument($this->_entity
, 'getactions', [], __FUNCTION__
, __FILE__
, $description);
3570 foreach ($expected as $action) {
3571 $this->assertTrue(in_array($action, $result['values']), "Expected action $action");
3573 foreach ($deprecated as $action) {
3574 $this->assertArrayKeyExists($action, $result['deprecated']);
3579 * Test the duplicate check function.
3581 public function testDuplicateCheck() {
3583 'first_name' => 'Harry',
3584 'last_name' => 'Potter',
3585 'email' => 'harry@hogwarts.edu',
3586 'contact_type' => 'Individual',
3588 $this->callAPISuccess('Contact', 'create', $harry);
3589 $result = $this->callAPISuccess('Contact', 'duplicatecheck', [
3593 $this->assertEquals(1, $result['count']);
3594 $result = $this->callAPISuccess('Contact', 'duplicatecheck', [
3596 'first_name' => 'Harry',
3597 'last_name' => 'Potter',
3598 'email' => 'no5@privet.drive',
3599 'contact_type' => 'Individual',
3602 $this->assertEquals(0, $result['count']);
3603 $this->callAPIFailure('Contact', 'create', array_merge($harry, ['dupe_check' => 1]));
3607 * Test the duplicate check function.
3609 public function testDuplicateCheckRuleNotReserved() {
3611 'first_name' => 'Harry',
3612 'last_name' => 'Potter',
3613 'email' => 'harry@hogwarts.edu',
3614 'contact_type' => 'Individual',
3616 $defaultRule = $this->callAPISuccess('RuleGroup', 'getsingle', ['used' => 'Unsupervised', 'is_reserved' => 1]);
3617 $this->callAPISuccess('RuleGroup', 'create', ['id' => $defaultRule['id'], 'is_reserved' => 0]);
3618 $this->callAPISuccess('Contact', 'create', $harry);
3619 $result = $this->callAPISuccess('Contact', 'duplicatecheck', [
3623 $this->assertEquals(1, $result['count']);
3624 $this->callAPISuccess('RuleGroup', 'create', ['id' => $defaultRule['id'], 'is_reserved' => 1]);
3628 * Test variants on retrieving contact by type.
3630 public function testGetByContactType() {
3631 $individual = $this->callAPISuccess('Contact', 'create', [
3632 'email' => 'individual@test.com',
3633 'contact_type' => 'Individual',
3635 $household = $this->callAPISuccess('Contact', 'create', [
3636 'household_name' => 'household@test.com',
3637 'contact_type' => 'Household',
3639 $organization = $this->callAPISuccess('Contact', 'create', [
3640 'organization_name' => 'organization@test.com',
3641 'contact_type' => 'Organization',
3643 // Test with id - getsingle will throw an exception if not found
3644 $this->callAPISuccess('Contact', 'getsingle', [
3645 'id' => $individual['id'],
3646 'contact_type' => 'Individual',
3648 $this->callAPISuccess('Contact', 'getsingle', [
3649 'id' => $individual['id'],
3650 'contact_type' => ['IN' => ['Individual']],
3653 $this->callAPISuccess('Contact', 'getsingle', [
3654 'id' => $organization['id'],
3655 'contact_type' => ['IN' => ['Individual', 'Organization']],
3658 $result = $this->callAPISuccess('Contact', 'get', [
3659 'contact_type' => ['IN' => ['Individual', 'Organization']],
3660 'options' => ['limit' => 0],
3663 $this->assertContains($organization['id'], array_keys($result['values']));
3664 $this->assertContains($individual['id'], array_keys($result['values']));
3665 $this->assertNotContains($household['id'], array_keys($result['values']));
3667 $result = $this->callAPISuccess('Contact', 'get', [
3668 'contact_type' => 'Household',
3669 'options' => ['limit' => 0],
3672 $this->assertNotContains($organization['id'], array_keys($result['values']));
3673 $this->assertNotContains($individual['id'], array_keys($result['values']));
3674 $this->assertContains($household['id'], array_keys($result['values']));
3678 * Test merging 2 contacts.
3680 * Someone kindly bequethed us the legacy of mixed up use of main_id & other_id
3681 * in the params for contact.merge api.
3683 * This test protects that legacy.
3685 public function testMergeBizzareOldParams() {
3686 $this->createLoggedInUser();
3687 $otherContact = $this->callAPISuccess('contact', 'create', $this->_params
);
3688 $mainContact = $this->callAPISuccess('contact', 'create', $this->_params
);
3689 $this->callAPISuccess('contact', 'merge', [
3690 'main_id' => $mainContact['id'],
3691 'other_id' => $otherContact['id'],
3693 $contacts = $this->callAPISuccess('contact', 'get', $this->_params
);
3694 $this->assertEquals($otherContact['id'], $contacts['id']);
3698 * Test merging 2 contacts.
3700 public function testMerge() {
3701 $this->createLoggedInUser();
3702 $otherContact = $this->callAPISuccess('contact', 'create', $this->_params
);
3703 $retainedContact = $this->callAPISuccess('contact', 'create', $this->_params
);
3704 $this->callAPISuccess('contact', 'merge', [
3705 'to_keep_id' => $retainedContact['id'],
3706 'to_remove_id' => $otherContact['id'],
3707 'auto_flip' => FALSE,
3710 $contacts = $this->callAPISuccess('contact', 'get', $this->_params
);
3711 $this->assertEquals($retainedContact['id'], $contacts['id']);
3712 $activity = $this->callAPISuccess('Activity', 'getsingle', [
3713 'target_contact_id' => $retainedContact['id'],
3714 'activity_type_id' => 'Contact Merged',
3716 $this->assertEquals(date('Y-m-d'), date('Y-m-d', strtotime($activity['activity_date_time'])));
3717 $activity2 = $this->callAPISuccess('Activity', 'getsingle', [
3718 'target_contact_id' => $otherContact['id'],
3719 'activity_type_id' => 'Contact Deleted by Merge',
3721 $this->assertEquals($activity['id'], $activity2['parent_id']);
3722 $this->assertEquals('Normal', civicrm_api3('option_value', 'getvalue', [
3723 'value' => $activity['priority_id'],
3724 'return' => 'label',
3725 'option_group_id' => 'priority',
3731 * Test merging 2 contacts with custom fields.
3733 * @throws \Exception
3735 public function testMergeCustomFields() {
3736 $contact1 = $this->individualCreate();
3737 // Not sure this is quite right but it does get it into the file table
3738 $file = $this->callAPISuccess('Attachment', 'create', [
3739 'name' => 'header.txt',
3740 'mime_type' => 'text/plain',
3741 'description' => 'My test description',
3742 'content' => 'My test content',
3743 'entity_table' => 'civicrm_contact',
3744 'entity_id' => $contact1,
3747 $this->createCustomGroupWithFieldsOfAllTypes();
3748 $fileField = $this->getCustomFieldName('file');
3749 $linkField = $this->getCustomFieldName('link');
3750 $dateField = $this->getCustomFieldName('select_date');
3751 $selectField = $this->getCustomFieldName('select_string');
3752 $countryField = $this->getCustomFieldName('country');
3754 $countriesByName = array_flip(CRM_Core_PseudoConstant
::country(FALSE, FALSE));
3755 $customFieldValues = [
3756 // @todo fix the fatal bug on this & uncomment - see dev/core#723
3757 $fileField => $file['id'],
3758 $linkField => 'http://example.org',
3759 $dateField => '2018-01-01 17:10:56',
3760 $selectField => 'G',
3761 // Currently broken.
3762 //$countryField => $countriesByName['New Zealand'],
3764 $this->callAPISuccess('Contact', 'create', array_merge([
3766 ], $customFieldValues));
3768 $contact2 = $this->individualCreate();
3769 $this->callAPISuccess('contact', 'merge', [
3770 'to_keep_id' => $contact2,
3771 'to_remove_id' => $contact1,
3772 'auto_flip' => FALSE,
3774 $contact = $this->callAPISuccessGetSingle('Contact', ['id' => $contact2, 'return' => array_keys($customFieldValues)]);
3775 $this->assertEquals($contact2, CRM_Core_DAO
::singleValueQuery('SELECT entity_id FROM civicrm_entity_file WHERE file_id = ' . $file['id']));
3776 foreach ($customFieldValues as $key => $value) {
3777 $this->assertEquals($value, $contact[$key]);
3782 * Test retrieving merged contacts.
3784 * The goal here is to start with a contact deleted by merged and find out the contact that is the current version of them.
3786 * @throws \CRM_Core_Exception
3788 public function testMergedGet() {
3789 $this->contactIDs
[] = $this->individualCreate();
3790 $this->contactIDs
[] = $this->individualCreate();
3791 $this->contactIDs
[] = $this->individualCreate();
3792 $this->contactIDs
[] = $this->individualCreate();
3794 // First do an 'unnatural merge' - they 'like to merge into the lowest but this will mean that contact 0 merged to contact [3].
3795 // When the batch merge runs.... the new lowest contact is contact[1]. All contacts will merge into that contact,
3796 // including contact[3], resulting in only 3 existing at the end. For each contact the correct answer to 'who did I eventually
3797 // wind up being should be [1]
3798 $this->callAPISuccess('Contact', 'merge', ['to_remove_id' => $this->contactIDs
[0], 'to_keep_id' => $this->contactIDs
[3]]);
3800 $this->callAPISuccess('Job', 'process_batch_merge', []);
3801 foreach ($this->contactIDs
as $contactID) {
3802 if ($contactID === $this->contactIDs
[1]) {
3805 $result = $this->callAPIAndDocument('Contact', 'getmergedto', ['sequential' => 1, 'contact_id' => $contactID], __FUNCTION__
, __FILE__
);
3806 $this->assertEquals(1, $result['count']);
3807 $this->assertEquals($this->contactIDs
[1], $result['values'][0]['id']);
3810 $result = $this->callAPIAndDocument('Contact', 'getmergedfrom', ['contact_id' => $this->contactIDs
[1]], __FUNCTION__
, __FILE__
)['values'];
3811 $mergedContactIds = array_merge(array_diff($this->contactIDs
, [$this->contactIDs
[1]]));
3812 $this->assertEquals($mergedContactIds, array_keys($result));
3816 * Test merging 2 contacts with delete to trash off.
3818 * We are checking that there is no error due to attempting to add an activity for the
3823 public function testMergeNoTrash() {
3824 $this->createLoggedInUser();
3825 $this->callAPISuccess('Setting', 'create', ['contact_undelete' => FALSE]);
3826 $otherContact = $this->callAPISuccess('contact', 'create', $this->_params
);
3827 $retainedContact = $this->callAPISuccess('contact', 'create', $this->_params
);
3828 $this->callAPISuccess('contact', 'merge', [
3829 'to_keep_id' => $retainedContact['id'],
3830 'to_remove_id' => $otherContact['id'],
3831 'auto_flip' => FALSE,
3833 $this->callAPISuccess('Setting', 'create', ['contact_undelete' => TRUE]);
3837 * Ensure format with return=group shows comma-separated group IDs.
3841 public function testContactGetReturnGroup() {
3842 // Set up a contact, asser that they were created.
3844 'contact_type' => 'Individual',
3845 'first_name' => 'Test',
3846 'last_name' => 'Groupmember',
3847 'email' => 'test@example.org',
3849 $create_contact = $this->callApiSuccess('Contact', 'create', $contact_params);
3850 $this->assertEquals(0, $create_contact['is_error']);
3851 $this->assertInternalType('int', $create_contact['id']);
3853 $created_contact_id = $create_contact['id'];
3855 // Set up multiple groups, add the contact to the groups.
3856 $test_groups = ['Test group A', 'Test group B'];
3857 foreach ($test_groups as $title) {
3858 // Use this contact as group owner, since we know they exist.
3861 'created_id' => $created_contact_id,
3863 $create_group = $this->callApiSuccess('Group', 'create', $group_params);
3864 $this->assertEquals(0, $create_group['is_error']);
3865 $this->assertInternalType('int', $create_group['id']);
3867 $created_group_ids[] = $create_group['id'];
3869 // Add contact to the new group.
3870 $group_contact_params = [
3871 'contact_id' => $created_contact_id,
3872 'group_id' => $create_group['id'],
3874 $create_group_contact = $this->callApiSuccess('GroupContact', 'create', $group_contact_params);
3875 $this->assertEquals(0, $create_group_contact['is_error']);
3876 $this->assertInternalType('int', $create_group_contact['added']);
3879 // Use the Contact,get API to retrieve the contact
3880 $contact_get_params = [
3881 'id' => $created_contact_id,
3882 'return' => 'group',
3884 $contact_get = $this->callApiSuccess('Contact', 'get', $contact_get_params);
3885 $this->assertInternalType('array', $contact_get['values'][$created_contact_id]);
3886 $this->assertInternalType('string', $contact_get['values'][$created_contact_id]['groups']);
3888 // Ensure they are shown as being in each created group.
3889 $contact_group_ids = explode(',', $contact_get['values'][$created_contact_id]['groups']);
3890 foreach ($created_group_ids as $created_group_id) {
3891 $this->assertContains($created_group_id, $contact_group_ids);
3896 * CRM-20144 Verify that passing title of group works as well as id
3897 * Tests the following formats
3898 * contact.get group='title1'
3899 * contact.get group=id1
3901 public function testContactGetWithGroupTitle() {
3902 // Set up a contact, asser that they were created.
3904 'contact_type' => 'Individual',
3905 'first_name' => 'Test2',
3906 'last_name' => 'Groupmember',
3907 'email' => 'test@example.org',
3909 $create_contact = $this->callApiSuccess('Contact', 'create', $contact_params);
3910 $created_contact_id = $create_contact['id'];
3911 // Set up multiple groups, add the contact to the groups.
3912 $test_groups = ['Test group C', 'Test group D'];
3913 foreach ($test_groups as $title) {
3916 'created_id' => $created_contact_id,
3918 $create_group = $this->callApiSuccess('Group', 'create', $group_params);
3919 $created_group_id = $create_group['id'];
3921 // Add contact to the new group.
3922 $group_contact_params = [
3923 'contact_id' => $created_contact_id,
3924 'group_id' => $create_group['id'],
3926 $this->callApiSuccess('GroupContact', 'create', $group_contact_params);
3927 $contact_get = $this->callAPISuccess('contact', 'get', ['group' => $title, 'return' => 'group']);
3928 $this->assertEquals(1, $contact_get['count']);
3929 $this->assertEquals($created_contact_id, $contact_get['id']);
3930 $contact_groups = explode(',', $contact_get['values'][$created_contact_id]['groups']);
3931 $this->assertContains((string) $create_group['id'], $contact_groups);
3932 $contact_get2 = $this->callAPISuccess('contact', 'get', ['group' => $created_group_id, 'return' => 'group']);
3933 $this->assertEquals($created_contact_id, $contact_get2['id']);
3934 $contact_groups2 = explode(',', $contact_get2['values'][$created_contact_id]['groups']);
3935 $this->assertContains((string) $create_group['id'], $contact_groups2);
3936 $this->callAPISuccess('group', 'delete', ['id' => $created_group_id]);
3938 $this->callAPISuccess('contact', 'delete', ['id' => $created_contact_id, 'skip_undelete' => TRUE]);
3942 * CRM-20144 Verify that passing title of group works as well as id
3943 * Tests the following formats
3944 * contact.get group=array('title1', title1)
3945 * contact.get group=array('IN' => array('title1', 'title2)
3947 public function testContactGetWithGroupTitleMultipleGroups() {
3948 $description = "Get all from group and display contacts.";
3949 $subFile = "GroupFilterUsingContactAPI";
3950 // Set up a contact, asser that they were created.
3952 'contact_type' => 'Individual',
3953 'first_name' => 'Test2',
3954 'last_name' => 'Groupmember',
3955 'email' => 'test@example.org',
3957 $create_contact = $this->callApiSuccess('Contact', 'create', $contact_params);
3958 $created_contact_id = $create_contact['id'];
3959 $createdGroupsTitles = $createdGroupsIds = [];
3960 // Set up multiple groups, add the contact to the groups.
3961 $test_groups = ['Test group C', 'Test group D'];
3962 foreach ($test_groups as $title) {
3965 'created_id' => $created_contact_id,
3967 $create_group = $this->callApiSuccess('Group', 'create', $group_params);
3968 $created_group_id = $create_group['id'];
3969 $createdGroupsIds[] = $create_group['id'];
3970 $createdGroupTitles[] = $title;
3971 // Add contact to the new group.
3972 $group_contact_params = [
3973 'contact_id' => $created_contact_id,
3974 'group_id' => $create_group['id'],
3976 $create_group_contact = $this->callApiSuccess('GroupContact', 'create', $group_contact_params);
3978 $contact_get = $this->callAPISuccess('contact', 'get', ['group' => $createdGroupTitles, 'return' => 'group']);
3979 $this->assertEquals(1, $contact_get['count']);
3980 $this->assertEquals($created_contact_id, $contact_get['id']);
3981 $contact_groups = explode(',', $contact_get['values'][$created_contact_id]['groups']);
3982 foreach ($createdGroupsIds as $id) {
3983 $this->assertContains((string) $id, $contact_groups);
3985 $contact_get2 = $this->callAPIAndDocument('contact', 'get', ['group' => ['IN' => $createdGroupTitles]], __FUNCTION__
, __FILE__
, $description, $subFile);
3986 $contact_get2 = $this->callAPISuccess('contact', 'get', ['group' => ['IN' => $createdGroupTitles], 'return' => 'group']);
3987 $this->assertEquals($created_contact_id, $contact_get2['id']);
3988 $contact_groups2 = explode(',', $contact_get2['values'][$created_contact_id]['groups']);
3989 foreach ($createdGroupsIds as $id) {
3990 $this->assertContains((string) $id, $contact_groups2);
3992 foreach ($createdGroupsIds as $id) {
3993 $this->callAPISuccess('group', 'delete', ['id' => $id]);
3995 $this->callAPISuccess('contact', 'delete', ['id' => $created_contact_id, 'skip_undelete' => TRUE]);
3999 * CRM-20144 Verify that passing title of group works as well as id
4000 * Tests the following formats
4001 * contact.get group=array('title1' => 1)
4002 * contact.get group=array('titke1' => 1, 'title2' => 1)
4003 * contact.get group=array('id1' => 1)
4004 * contact.get group=array('id1' => 1, id2 => 1)
4006 public function testContactGetWithGroupTitleMultipleGroupsLegacyFormat() {
4007 // Set up a contact, asser that they were created.
4009 'contact_type' => 'Individual',
4010 'first_name' => 'Test2',
4011 'last_name' => 'Groupmember',
4012 'email' => 'test@example.org',
4014 $create_contact = $this->callApiSuccess('Contact', 'create', $contact_params);
4015 $created_contact_id = $create_contact['id'];
4016 $createdGroupsTitles = $createdGroupsIds = [];
4017 // Set up multiple groups, add the contact to the groups.
4018 $test_groups = ['Test group C', 'Test group D'];
4019 foreach ($test_groups as $title) {
4022 'created_id' => $created_contact_id,
4024 $create_group = $this->callApiSuccess('Group', 'create', $group_params);
4025 $created_group_id = $create_group['id'];
4026 $createdGroupsIds[] = $create_group['id'];
4027 $createdGroupTitles[] = $title;
4028 // Add contact to the new group.
4029 $group_contact_params = [
4030 'contact_id' => $created_contact_id,
4031 'group_id' => $create_group['id'],
4033 $create_group_contact = $this->callApiSuccess('GroupContact', 'create', $group_contact_params);
4035 $contact_get = $this->callAPISuccess('contact', 'get', ['group' => [$createdGroupTitles[0] => 1], 'return' => 'group']);
4036 $this->assertEquals(1, $contact_get['count']);
4037 $this->assertEquals($created_contact_id, $contact_get['id']);
4038 $contact_groups = explode(',', $contact_get['values'][$created_contact_id]['groups']);
4039 foreach ($createdGroupsIds as $id) {
4040 $this->assertContains((string) $id, $contact_groups);
4042 $contact_get2 = $this->callAPISuccess('contact', 'get', ['group' => [$createdGroupTitles[0] => 1, $createdGroupTitles[1] => 1], 'return' => 'group']);
4043 $this->assertEquals(1, $contact_get2['count']);
4044 $this->assertEquals($created_contact_id, $contact_get2['id']);
4045 $contact_groups2 = explode(',', $contact_get2['values'][$created_contact_id]['groups']);
4046 foreach ($createdGroupsIds as $id) {
4047 $this->assertContains((string) $id, $contact_groups2);
4049 $contact_get3 = $this->callAPISuccess('contact', 'get', ['group' => [$createdGroupsIds[0] => 1], 'return' => 'group']);
4050 $this->assertEquals($created_contact_id, $contact_get3['id']);
4051 $contact_groups3 = explode(',', $contact_get3['values'][$created_contact_id]['groups']);
4052 foreach ($createdGroupsIds as $id) {
4053 $this->assertContains((string) $id, $contact_groups3);
4055 $contact_get4 = $this->callAPISuccess('contact', 'get', ['group' => [$createdGroupsIds[0] => 1, $createdGroupsIds[1] => 1], 'return' => 'group']);
4056 $this->assertEquals($created_contact_id, $contact_get4['id']);
4057 $contact_groups4 = explode(',', $contact_get4['values'][$created_contact_id]['groups']);
4058 foreach ($createdGroupsIds as $id) {
4059 $this->assertContains((string) $id, $contact_groups4);
4061 foreach ($createdGroupsIds as $id) {
4062 $this->callAPISuccess('group', 'delete', ['id' => $id]);
4064 $this->callAPISuccess('contact', 'delete', ['id' => $created_contact_id, 'skip_undelete' => TRUE]);
4068 * Test the prox_distance functionality works.
4070 * This is primarily testing functionality in the BAO_Query object that 'happens to be'
4071 * accessible via the api.
4073 public function testContactGetProximity() {
4074 CRM_Core_Config
::singleton()->geocodeMethod
= 'CRM_Utils_MockGeocoder';
4075 $this->individualCreate();
4076 $contactID = $this->individualCreate();
4077 $this->callAPISuccess('Address', 'create', [
4078 'contact_id' => $contactID,
4080 'city' => 'Whangarei',
4081 'street_address' => 'Dent St',
4082 'geo_code_1' => '-35.8743325',
4083 'geo_code_2' => '174.4567136',
4084 'location_type_id' => 'Home',
4086 $contact = $this->callAPISuccess('Contact', 'get', [
4087 'prox_distance' => 100,
4088 'prox_geo_code_1' => '-35.72192',
4089 'prox_geo_code_2' => '174.32034',
4091 $this->assertEquals(1, $contact['count']);
4092 $this->assertEquals($contactID, $contact['id']);
4095 public function testLoggedInUserAPISupportToken() {
4096 $description = "Get contact id of the current logged in user";
4097 $subFile = "ContactIDOfLoggedInUserContactAPI";
4098 $cid = $this->createLoggedInUser();
4099 $contact = $this->callAPIAndDocument('contact', 'get', ['id' => 'user_contact_id'], __FUNCTION__
, __FILE__
, $description, $subFile);
4100 $this->assertEquals($cid, $contact['id']);
4107 protected function putGroupContactCacheInClearableState($groupID, $contact) {
4108 // We need to force the situation where there is invalid data in the cache and it
4109 // is due to be cleared.
4110 CRM_Core_DAO
::executeQuery("
4111 INSERT INTO civicrm_group_contact_cache (group_id, contact_id)
4112 VALUES ({$groupID}, {$contact['id']})
4114 CRM_Core_DAO
::executeQuery("UPDATE civicrm_group SET cache_date = '2017-01-01'");
4115 // Reset so it does not skip.
4116 Civi
::$statics['CRM_Contact_BAO_GroupContactCache']['is_refresh_init'] = FALSE;
4120 * CRM-21041 Test if 'communication style' is set to site default if not passed.
4122 * @param int $version
4124 * @dataProvider versionThreeAndFour
4125 * @throws \CRM_Core_Exception
4127 public function testCreateCommunicationStyleUnset($version) {
4128 $this->_apiversion
= $version;
4129 $this->callAPISuccess('Contact', 'create', [
4130 'first_name' => 'John',
4131 'last_name' => 'Doe',
4132 'contact_type' => 'Individual',
4134 $result = $this->callAPISuccessGetSingle('Contact', ['last_name' => 'Doe']);
4135 $this->assertEquals(1, $result['communication_style_id']);
4139 * CRM-21041 Test if 'communication style' is set if value is passed.
4141 * @throws \CRM_Core_Exception
4142 * @throws \CiviCRM_API3_Exception
4144 public function testCreateCommunicationStylePassed() {
4145 $this->callAPISuccess('Contact', 'create', [
4146 'first_name' => 'John',
4147 'last_name' => 'Doe',
4148 'contact_type' => 'Individual',
4149 'communication_style_id' => 'Familiar',
4151 $result = $this->callAPISuccessGetSingle('Contact', ['last_name' => 'Doe']);
4153 'option_group_id' => 'communication_style',
4154 'label' => 'Familiar',
4155 'return' => 'value',
4157 $optionResult = civicrm_api3('OptionValue', 'get', $params);
4158 $communicationStyle = reset($optionResult['values']);
4159 $this->assertEquals($communicationStyle['value'], $result['communication_style_id']);
4163 * Test that creating a contact with various contact greetings works.
4166 public function testContactGreetingsCreate() {
4167 $contact = $this->callAPISuccess('Contact', 'create', ['first_name' => 'Alan', 'last_name' => 'MouseMouse', 'contact_type' => 'Individual']);
4168 $contact = $this->callAPISuccessGetSingle('Contact', ['id' => $contact['id'], 'return' => 'postal_greeting']);
4169 $this->assertEquals('Dear Alan', $contact['postal_greeting_display']);
4171 $contact = $this->callAPISuccess('Contact', 'create', ['id' => $contact['id'], 'postal_greeting_id' => 2]);
4172 $contact = $this->callAPISuccessGetSingle('Contact', ['id' => $contact['id'], 'return' => 'postal_greeting']);
4173 $this->assertEquals('Dear Alan MouseMouse', $contact['postal_greeting_display']);
4175 $contact = $this->callAPISuccess('Contact', 'create', ['organization_name' => 'Alan\'s Show', 'contact_type' => 'Organization']);
4176 $contact = $this->callAPISuccessGetSingle('Contact', ['id' => $contact['id'], 'return' => 'postal_greeting, addressee, email_greeting']);
4177 $this->assertEquals('', $contact['postal_greeting_display']);
4178 $this->assertEquals('', $contact['email_greeting_display']);
4179 $this->assertEquals('Alan\'s Show', $contact['addressee_display']);
4183 * Test that creating a contact with various contact greetings works.
4185 public function testContactGreetingsCreateWithCustomField() {
4186 $ids = $this->entityCustomGroupWithSingleFieldCreate(__FUNCTION__
, __FILE__
);
4187 $contact = $this->callAPISuccess('Contact', 'create', ['first_name' => 'Alan', 'contact_type' => 'Individual', 'custom_' . $ids['custom_field_id'] => 'Mice']);
4189 // Change postal greeting to involve a custom field.
4190 $postalOption = $this->callAPISuccessGetSingle('OptionValue', ['option_group_id' => 'postal_greeting', 'filter' => 1, 'is_default' => 1]);
4191 $this->callAPISuccess('OptionValue', 'create', [
4192 'id' => $postalOption['id'],
4193 'name' => 'Dear {contact.first_name} {contact.custom_' . $ids['custom_field_id'] . '}',
4194 'label' => 'Dear {contact.first_name} {contact.custom_' . $ids['custom_field_id'] . '}',
4197 // Update contact & see if postal greeting now reflects the new string.
4198 $this->callAPISuccess('Contact', 'create', ['id' => $contact['id'], 'last_name' => 'MouseyMousey']);
4199 $contact = $this->callAPISuccessGetSingle('Contact', ['id' => $contact['id'], 'return' => 'postal_greeting']);
4200 $this->assertEquals('Dear Alan Mice', $contact['postal_greeting_display']);
4202 // Set contact to have no postal greeting & check it is correct.
4203 $this->callAPISuccess('Contact', 'create', ['id' => $contact['id'], 'postal_greeting_id' => 'null']);
4204 $contact = $this->callAPISuccessGetSingle('Contact', ['id' => $contact['id'], 'return' => 'postal_greeting']);
4205 $this->assertEquals('', $contact['postal_greeting_display']);
4208 $this->callAPISuccess('OptionValue', 'create', ['id' => $postalOption['id'], 'name' => 'Dear {contact.first_name}']);
4209 $this->customFieldDelete($ids['custom_field_id']);
4210 $this->customGroupDelete($ids['custom_group_id']);
4214 * Test getunique api call for Contact entity
4216 public function testContactGetUnique() {
4217 $result = $this->callAPIAndDocument($this->_entity
, 'getunique', [], __FUNCTION__
, __FILE__
);
4218 $this->assertEquals(1, $result['count']);
4219 $this->assertEquals(['external_identifier'], $result['values']['UI_external_identifier']);
4223 * API test to retrieve contact from group having different group title and name.
4225 public function testContactGetFromGroup() {
4226 $groupId = $this->groupCreate([
4227 'name' => 'Test_Group',
4229 'title' => 'New Test Group Created',
4230 'description' => 'New Test Group Created',
4232 'visibility' => 'User and User Admin Only',
4234 $contact = $this->callAPISuccess('contact', 'create', $this->_params
);
4235 $groupContactCreateParams = [
4236 'contact_id' => $contact['id'],
4237 'group_id' => $groupId,
4238 'status' => 'Pending',
4240 $groupContact = $this->callAPISuccess('groupContact', 'create', $groupContactCreateParams);
4241 $groupGetContact = $this->CallAPISuccess('groupContact', 'get', $groupContactCreateParams);
4242 $this->CallAPISuccess('Contact', 'getcount', [
4243 'group' => "Test_Group",
4248 * Test the related contacts filter.
4250 * @throws \Exception
4252 public function testSmartGroupsForRelatedContacts() {
4253 $rtype1 = $this->callAPISuccess('relationship_type', 'create', [
4254 "name_a_b" => uniqid() . " Child of",
4255 "name_b_a" => uniqid() . " Parent of",
4257 $rtype2 = $this->callAPISuccess('relationship_type', 'create', [
4258 "name_a_b" => uniqid() . " Household Member of",
4259 "name_b_a" => uniqid() . " Household Member is",
4261 $h1 = $this->householdCreate();
4262 $c1 = $this->individualCreate(['last_name' => 'Adams']);
4263 $c2 = $this->individualCreate(['last_name' => 'Adams']);
4264 $this->callAPISuccess('relationship', 'create', [
4265 'contact_id_a' => $c1,
4266 'contact_id_b' => $c2,
4269 'relationship_type_id' => $rtype1['id'],
4271 $this->callAPISuccess('relationship', 'create', [
4272 'contact_id_a' => $c1,
4273 'contact_id_b' => $h1,
4275 // Household Member of
4276 'relationship_type_id' => $rtype2['id'],
4278 $this->callAPISuccess('relationship', 'create', [
4279 'contact_id_a' => $c2,
4280 'contact_id_b' => $h1,
4282 // Household Member of
4283 'relationship_type_id' => $rtype2['id'],
4289 'display_relationship_type' => $rtype1['id'] . '_a_b',
4290 'sort_name' => 'Adams',
4293 $g1ID = $this->smartGroupCreate($ssParams, ['name' => uniqid(), 'title' => uniqid()]);
4296 // Household Member of
4297 'display_relationship_type' => $rtype2['id'] . '_a_b',
4300 $g2ID = $this->smartGroupCreate($ssParams, ['name' => uniqid(), 'title' => uniqid()]);
4303 // Household Member is
4304 'display_relationship_type' => $rtype2['id'] . '_b_a',
4307 // the reverse of g2 which adds another layer for overlap at related contact filter
4308 $g3ID = $this->smartGroupCreate($ssParams, ['name' => uniqid(), 'title' => uniqid()]);
4309 CRM_Contact_BAO_GroupContactCache
::loadAll();
4310 $g1Contacts = $this->callAPISuccess('contact', 'get', ['group' => $g1ID]);
4311 $g2Contacts = $this->callAPISuccess('contact', 'get', ['group' => $g2ID]);
4312 $g3Contacts = $this->callAPISuccess('contact', 'get', ['group' => $g3ID]);
4313 $this->assertTrue($g1Contacts['count'] == 1);
4314 $this->assertTrue($g2Contacts['count'] == 2);
4315 $this->assertTrue($g3Contacts['count'] == 1);
4319 * Test creating a note from the contact.create API call when only passing the note as a string.
4321 public function testCreateNoteinCreate() {
4322 $loggedInContactID = $this->createLoggedInUser();
4323 $this->_params
['note'] = "Test note created by API Call as a String";
4324 $contact = $this->callAPISuccess('Contact', 'create', $this->_params
);
4325 $note = $this->callAPISuccess('Note', 'get', ['contact_id' => $loggedInContactID]);
4326 $this->assertEquals($note['values'][$note['id']]['note'], "Test note created by API Call as a String");
4327 $note = $this->callAPISuccess('Note', 'get', ['entity_id' => $contact['id']]);
4328 $this->assertEquals($note['values'][$note['id']]['note'], "Test note created by API Call as a String");
4329 $this->callAPISuccess('Contact', 'delete', ['id' => $contact['id'], 'skip_undelete' => TRUE]);
4333 * Test Creating a note from the contact.create api call when passing the note params as an array.
4335 public function testCreateNoteinCreateArrayFormat() {
4336 $contact1 = $this->callAPISuccess('Contact', 'create', ['first_name' => 'Alan', 'last_name' => 'MouseMouse', 'contact_type' => 'Individual']);
4337 $this->_params
['note'] = [['note' => "Test note created by API Call as array", 'contact_id' => $contact1['id']]];
4338 $contact2 = $this->callAPISuccess('Contact', 'create', $this->_params
);
4339 $note = $this->callAPISuccess('Note', 'get', ['contact_id' => $contact1['id']]);
4340 $this->assertEquals($note['values'][$note['id']]['note'], "Test note created by API Call as array");
4341 $note = $this->callAPISuccess('Note', 'get', ['entity_id' => $contact2['id']]);
4342 $this->assertEquals($note['values'][$note['id']]['note'], "Test note created by API Call as array");
4346 * Verify that passing tag IDs to Contact.get works
4348 * Tests the following formats
4349 * - Contact.get tag='id1'
4350 * - Contact.get tag='id1,id2'
4351 * - Contact.get tag='id1, id2'
4353 public function testContactGetWithTag() {
4354 $contact = $this->callApiSuccess('Contact', 'create', [
4355 'contact_type' => 'Individual',
4356 'first_name' => 'Test',
4357 'last_name' => 'Tagged',
4358 'email' => 'test@example.org',
4361 foreach (['Tag A', 'Tag B'] as $name) {
4362 $tags[] = $this->callApiSuccess('Tag', 'create', [
4367 // assign contact to "Tag B"
4368 $this->callApiSuccess('EntityTag', 'create', [
4369 'entity_table' => 'civicrm_contact',
4370 'entity_id' => $contact['id'],
4371 'tag_id' => $tags[1]['id'],
4374 // test format Contact.get tag='id1'
4375 $contact_get = $this->callAPISuccess('Contact', 'get', [
4376 'tag' => $tags[1]['id'],
4379 $this->assertEquals(1, $contact_get['count']);
4380 $this->assertEquals($contact['id'], $contact_get['id']);
4381 $this->assertEquals('Tag B', $contact_get['values'][$contact['id']]['tags']);
4383 // test format Contact.get tag='id1,id2'
4384 $contact_get = $this->callAPISuccess('Contact', 'get', [
4385 'tag' => $tags[0]['id'] . ',' . $tags[1]['id'],
4388 $this->assertEquals(1, $contact_get['count']);
4389 $this->assertEquals($contact['id'], $contact_get['id']);
4390 $this->assertEquals('Tag B', $contact_get['values'][$contact['id']]['tags']);
4392 // test format Contact.get tag='id1, id2'
4393 $contact_get = $this->callAPISuccess('Contact', 'get', [
4394 'tag' => $tags[0]['id'] . ', ' . $tags[1]['id'],
4397 $this->assertEquals(1, $contact_get['count']);
4398 $this->assertEquals($contact['id'], $contact_get['id']);
4399 $this->assertEquals('Tag B', $contact_get['values'][$contact['id']]['tags']);
4401 foreach ($tags as $tag) {
4402 $this->callAPISuccess('Tag', 'delete', ['id' => $tag['id']]);
4404 $this->callAPISuccess('Contact', 'delete', [
4405 'id' => $contact['id'],
4406 'skip_undelete' => TRUE,