2 // $Id: Contact.php 45502 2013-02-08 13:32:55Z kurund $
6 +--------------------------------------------------------------------+
7 | CiviCRM version 4.3 |
8 +--------------------------------------------------------------------+
9 | Copyright CiviCRM LLC (c) 2004-2013 |
10 +--------------------------------------------------------------------+
11 | This file is a part of CiviCRM. |
13 | CiviCRM is free software; you can copy, modify, and distribute it |
14 | under the terms of the GNU Affero General Public License |
15 | Version 3, 19 November 2007 and the CiviCRM Licensing Exception. |
17 | CiviCRM is distributed in the hope that it will be useful, but |
18 | WITHOUT ANY WARRANTY; without even the implied warranty of |
19 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
20 | See the GNU Affero General Public License for more details. |
22 | You should have received a copy of the GNU Affero General Public |
23 | License and the CiviCRM Licensing Exception along |
24 | with this program; if not, contact CiviCRM LLC |
25 | at info[AT]civicrm[DOT]org. If you have questions about the |
26 | GNU Affero General Public License or the licensing of CiviCRM, |
27 | see the CiviCRM license FAQ at http://civicrm.org/licensing |
28 +--------------------------------------------------------------------+
32 * new version of civicrm apis. See blog post at
33 * http://civicrm.org/node/131
36 * @package CiviCRM_APIv2
37 * @subpackage API_Contact
38 * @copyright CiviCRM LLC (c) 2004-2013
39 * $Id: Contact.php 45502 2013-02-08 13:32:55Z kurund $
44 * Include common API util functions
46 require_once 'api/v2/utils.php';
47 require_once 'CRM/Contact/BAO/Contact.php';
52 * @param array $params (reference ) input parameters
54 * Allowed @params array keys are:
55 * {@schema Contact/Contact.xml}
56 * {@schema Core/Address.xml}}
58 * @return array (reference ) contact_id of created or updated contact
63 function civicrm_contact_create(&$params) {
64 // call update and tell it to create a new contact
65 _civicrm_initialize();
66 $errorScope = CRM_Core_TemporaryErrorScope
::useException();
68 civicrm_api_check_permission(__FUNCTION__
, $params, TRUE);
70 return civicrm_contact_update($params, $create_new);
73 return civicrm_create_error($e->getMessage());
79 * @todo Serious FIXMES in the code! File issues.
81 function civicrm_contact_update(&$params, $create_new = FALSE) {
82 _civicrm_initialize();
84 civicrm_api_check_permission(__FUNCTION__
, $params, TRUE);
87 return civicrm_create_error($e->getMessage());
89 require_once 'CRM/Utils/Array.php';
90 $entityId = CRM_Utils_Array
::value('contact_id', $params, NULL);
91 if (!CRM_Utils_Array
::value('contact_type', $params) &&
94 $params['contact_type'] = CRM_Contact_BAO_Contact
::getContactType($entityId);
96 $dupeCheck = CRM_Utils_Array
::value('dupe_check', $params, FALSE);
97 $values = civicrm_contact_check_params($params, $dupeCheck);
103 // Make sure nothing is screwed up before we create a new contact
104 if (!empty($entityId)) {
105 return civicrm_create_error('Cannot create new contact when contact_id is present');
107 if (empty($params['contact_type'])) {
108 return civicrm_create_error('Contact Type not specified');
111 // If we get here, we're ready to create a new contact
112 if (($email = CRM_Utils_Array
::value('email', $params)) && !is_array($params['email'])) {
113 require_once 'CRM/Core/BAO/LocationType.php';
114 $defLocType = CRM_Core_BAO_LocationType
::getDefault();
115 $params['email'] = array(
116 1 => array('email' => $email,
118 'location_type_id' => ($defLocType->id
) ?
$defLocType->id
: 1,
124 if ($homeUrl = CRM_Utils_Array
::value('home_url', $params)) {
125 require_once 'CRM/Core/PseudoConstant.php';
126 $websiteTypes = CRM_Core_PseudoConstant
::websiteType();
127 $params['website'] = array(1 => array('website_type_id' => key($websiteTypes),
132 // FIXME: Some legacy support cruft, should get rid of this in 3.1
134 'individual_prefix' => 'prefix',
135 'prefix' => 'prefix_id',
136 'individual_suffix' => 'suffix',
137 'suffix' => 'suffix_id',
138 'gender' => 'gender_id',
141 foreach ($change as $field => $changeAs) {
142 if (array_key_exists($field, $params)) {
143 $params[$changeAs] = $params[$field];
144 unset($params[$field]);
147 // End legacy support cruft
149 if (isset($params['suffix_id']) &&
150 !(is_numeric($params['suffix_id']))
152 $params['suffix_id'] = array_search($params['suffix_id'], CRM_Core_PseudoConstant
::individualSuffix());
155 if (isset($params['prefix_id']) &&
156 !(is_numeric($params['prefix_id']))
158 $params['prefix_id'] = array_search($params['prefix_id'], CRM_Core_PseudoConstant
::individualPrefix());
161 if (isset($params['gender_id'])
162 && !(is_numeric($params['gender_id']))
164 $params['gender_id'] = array_search($params['gender_id'], CRM_Core_PseudoConstant
::gender());
167 $error = _civicrm_greeting_format_params($params);
168 if (civicrm_error($error)) {
174 if (!($csType = CRM_Utils_Array
::value('contact_sub_type', $params)) &&
177 require_once 'CRM/Contact/BAO/Contact.php';
178 $csType = CRM_Contact_BAO_Contact
::getContactSubType($entityId);
181 $customValue = civicrm_contact_check_custom_params($params, $csType);
186 _civicrm_custom_format_params($params, $values, $params['contact_type'], $entityId);
188 $params = array_merge($params, $values);
190 $contact = &_civicrm_contact_update($params, $entityId);
192 if (is_a($contact, 'CRM_Core_Error')) {
193 return civicrm_create_error($contact->_errors
[0]['message']);
197 $values['contact_id'] = $contact->id
;
198 $values['is_error'] = 0;
205 * Add or update a contact. If a dupe is found, check for
206 * ignoreDupe flag to ignore or return error
208 * @deprecated deprecated since version 2.2.3; use civicrm_contact_create or civicrm_contact_update instead
210 * @param array $params (reference ) input parameters
212 * @return array (reference ) contact_id of created or updated contact
216 function &civicrm_contact_add(&$params) {
217 _civicrm_initialize();
219 $contactID = CRM_Utils_Array
::value('contact_id', $params);
221 if (!empty($contactID)) {
222 $result = civicrm_contact_update($params);
225 $result = civicrm_contact_create($params);
231 * Validate the addressee or email or postal greetings
233 * @param $params Associative array of property name/value
234 * pairs to insert in new contact.
236 * @return array (reference ) null on success, error message otherwise
240 function _civicrm_greeting_format_params(&$params) {
241 $greetingParams = array('', '_id', '_custom');
243 'email', 'postal', 'addressee') as $key) {
244 $greeting = '_greeting';
245 if ($key == 'addressee') {
249 $formatParams = FALSE;
250 // unset display value from params.
251 if (isset($params["{$key}{$greeting}_display"])) {
252 unset($params["{$key}{$greeting}_display"]);
255 // check if greetings are present in present
256 foreach ($greetingParams as $greetingValues) {
257 if (array_key_exists("{$key}{$greeting}{$greetingValues}", $params)) {
258 $formatParams = TRUE;
263 if (!$formatParams) {
269 if (CRM_Utils_Array
::value('contact_type', $params) == 'Organization' && $key != 'addressee') {
270 return civicrm_create_error(ts('You cannot use email/postal greetings for contact type %1.',
271 array(1 => $params['contact_type'])
277 'contact_type' => $params['contact_type'],
278 'greeting_type' => "{$key}{$greeting}",
281 $greetings = CRM_Core_PseudoConstant
::greeting($filter);
282 $greetingId = CRM_Utils_Array
::value("{$key}{$greeting}_id", $params);
283 $greetingVal = CRM_Utils_Array
::value("{$key}{$greeting}", $params);
284 $customGreeting = CRM_Utils_Array
::value("{$key}{$greeting}_custom", $params);
286 if (!$greetingId && $greetingVal) {
287 $params["{$key}{$greeting}_id"] = CRM_Utils_Array
::key($params["{$key}{$greeting}"], $greetings);
290 if ($customGreeting && $greetingId &&
291 ($greetingId != array_search('Customized', $greetings))
293 return civicrm_create_error(ts('Provide either %1 greeting id and/or %1 greeting or custom %1 greeting',
298 if ($greetingVal && $greetingId &&
299 ($greetingId != CRM_Utils_Array
::key($greetingVal, $greetings))
301 return civicrm_create_error(ts('Mismatch in %1 greeting id and %1 greeting',
308 if (!array_key_exists($greetingId, $greetings)) {
309 return civicrm_create_error(ts('Invalid %1 greeting Id', array(1 => $key)));
312 if (!$customGreeting && ($greetingId == array_search('Customized', $greetings))) {
313 return civicrm_create_error(ts('Please provide a custom value for %1 greeting',
318 elseif ($greetingVal) {
320 if (!in_array($greetingVal, $greetings)) {
321 return civicrm_create_error(ts('Invalid %1 greeting', array(1 => $key)));
324 $greetingId = CRM_Utils_Array
::key($greetingVal, $greetings);
327 if ($customGreeting) {
328 $greetingId = CRM_Utils_Array
::key('Customized', $greetings);
331 $customValue = $params['contact_id'] ? CRM_Core_DAO
::getFieldValue('CRM_Contact_DAO_Contact',
332 $params['contact_id'],
333 "{$key}{$greeting}_custom"
336 if (array_key_exists("{$key}{$greeting}_id", $params) && empty($params["{$key}{$greeting}_id"])) {
339 elseif (array_key_exists("{$key}{$greeting}", $params) && empty($params["{$key}{$greeting}"])) {
342 elseif ($customValue && array_key_exists("{$key}{$greeting}_custom", $params)
343 && empty($params["{$key}{$greeting}_custom"])
348 $params["{$key}{$greeting}_id"] = $greetingId;
350 if (!$customValue && !$customGreeting && array_key_exists("{$key}{$greeting}_custom", $params)) {
351 unset($params["{$key}{$greeting}_custom"]);
355 $params["{$key}{$greeting}_id"] = '';
356 $params["{$key}{$greeting}_custom"] = '';
359 if (isset($params["{$key}{$greeting}"])) {
360 unset($params["{$key}{$greeting}"]);
366 * Retrieve one or more contacts, given a set of search params
368 * @param mixed[] (reference ) input parameters
369 * @param bool follow the pre-2.2.3 behavior of this function
371 * @return array (reference ) array of properties, if error an array with an error id and error message
375 function civicrm_contact_get(&$params, $deprecated_behavior = FALSE) {
376 _civicrm_initialize();
378 if ($deprecated_behavior) {
379 return _civicrm_contact_get_deprecated($params);
382 // fix for CRM-7384 cater for soft deleted contacts
383 $params['contact_is_deleted'] = 0;
384 if (isset($params['showAll'])) {
385 if (strtolower($params['showAll']) == "active") {
386 $params['contact_is_deleted'] = 0;
388 if (strtolower($params['showAll']) == "trash") {
389 $params['contact_is_deleted'] = 1;
391 if (strtolower($params['showAll']) == "all" && isset($params['contact_is_deleted'])) {
392 unset($params['contact_is_deleted']);
396 $inputParams = array();
397 $returnProperties = array();
398 $otherVars = array('sort', 'offset', 'rowCount', 'smartGroupCache');
403 $smartGroupCache = FALSE;
404 foreach ($params as $n => $v) {
405 if (substr($n, 0, 6) == 'return') {
406 $returnProperties[substr($n, 7)] = $v;
408 elseif (in_array($n, $otherVars)) {
412 $inputParams[$n] = $v;
416 if (empty($returnProperties)) {
417 $returnProperties = NULL;
420 require_once 'CRM/Contact/BAO/Query.php';
421 $newParams = CRM_Contact_BAO_Query
::convertFormValues($inputParams);
422 list($contacts, $options) = CRM_Contact_BAO_Query
::apiQuery($newParams,
434 * Retrieve a specific contact, given a set of search params
436 * @deprecated deprecated since version 2.2.3
438 * @param array $params (reference ) input parameters
440 * @return array (reference ) array of properties, if error an array with an error id and error message
444 function _civicrm_contact_get_deprecated(&$params) {
446 if (empty($params)) {
447 return civicrm_create_error(ts('No input parameters present'));
450 if (!is_array($params)) {
451 return civicrm_create_error(ts('Input parameters is not an array'));
454 $contacts = &civicrm_contact_search($params);
455 if (civicrm_error($contacts)) {
459 if (count($contacts) != 1 &&
460 !CRM_Utils_Array
::value('returnFirst', $params)
462 return civicrm_create_error(ts('%1 contacts matching input params', array(1 => count($contacts))));
464 elseif (count($contacts) == 0) {
465 return civicrm_create_error(ts('No contacts match the input params'));
468 $contacts = array_values($contacts);
473 * Delete a contact with given contact id
475 * @param array $params (reference ) input parameters, contact_id element required
477 * @return boolean true if success, else false
481 function civicrm_contact_delete(&$params) {
482 require_once 'CRM/Contact/BAO/Contact.php';
484 $contactID = CRM_Utils_Array
::value('contact_id', $params);
486 return civicrm_create_error(ts('Could not find contact_id in input parameters'));
489 $session = CRM_Core_Session
::singleton();
490 if ($contactID == $session->get('userID')) {
491 return civicrm_create_error(ts('This contact record is linked to the currently logged in user account - and cannot be deleted.'));
493 $restore = CRM_Utils_Array
::value('restore', $params) ?
$params['restore'] : FALSE;
494 $skipUndelete = CRM_Utils_Array
::value('skip_undelete', $params) ?
$params['skip_undelete'] : FALSE;
495 if (CRM_Contact_BAO_Contact
::deleteContact($contactID, $restore, $skipUndelete)) {
496 return civicrm_create_success();
499 return civicrm_create_error(ts('Could not delete contact'));
504 * Retrieve a set of contacts, given a set of input params
506 * @deprecated deprecated since version 2.2.3
508 * @param array $params (reference ) input parameters
509 * @param array $returnProperties Which properties should be included in the
510 * returned Contact object. If NULL, the default
511 * set of properties will be included.
513 * @return array (reference ) array of contacts, if error an array with an error id and error message
517 function &civicrm_contact_search(&$params) {
518 _civicrm_initialize();
520 $inputParams = $returnProperties = array();
521 $otherVars = array('sort', 'offset', 'rowCount', 'smartGroupCache');
526 $smartGroupCache = FALSE;
527 foreach ($params as $n => $v) {
528 if (substr($n, 0, 6) == 'return') {
529 $returnProperties[substr($n, 7)] = $v;
531 elseif (in_array($n, $otherVars)) {
535 $inputParams[$n] = $v;
539 // explicitly suppress all deleted contacts
540 // this is fixed in api v3
542 $inputParams['contact_is_deleted'] = 0;
544 if (empty($returnProperties)) {
545 $returnProperties = NULL;
548 require_once 'CRM/Contact/BAO/Query.php';
549 $newParams = CRM_Contact_BAO_Query
::convertFormValues($inputParams);
550 list($contacts, $options) = CRM_Contact_BAO_Query
::apiQuery($newParams,
562 * Ensure that we have the right input parameters
564 * @todo We also need to make sure we run all the form rules on the params list
565 * to ensure that the params are valid
567 * @param array $params Associative array of property name/value
568 * pairs to insert in new contact.
569 * @param boolean $dupeCheck Should we check for duplicate contacts
570 * @param boolean $dupeErrorArray Should we return values of error
571 * object in array foramt
572 * @param boolean $requiredCheck Should we check if required params
573 * are present in params array
574 * @param int $dedupeRuleGroupID - the dedupe rule ID to use if present
576 * @return null on success, error message otherwise
579 function civicrm_contact_check_params(&$params,
581 $dupeErrorArray = FALSE,
582 $requiredCheck = TRUE,
583 $dedupeRuleGroupID = NULL
585 if ($requiredCheck) {
587 'Individual' => array(
588 array('first_name', 'last_name'),
591 'Household' => array(
594 'Organization' => array(
599 // cannot create a contact with empty params
600 if (empty($params)) {
601 return civicrm_create_error('Input Parameters empty');
604 if (!array_key_exists('contact_type', $params)) {
605 return civicrm_create_error('Contact Type not specified');
608 // contact_type has a limited number of valid values
609 $fields = CRM_Utils_Array
::value($params['contact_type'], $required);
610 if ($fields == NULL) {
611 return civicrm_create_error("Invalid Contact Type: {$params['contact_type']}");
614 if ($csType = CRM_Utils_Array
::value('contact_sub_type', $params)) {
615 if (!(CRM_Contact_BAO_ContactType
::isExtendsContactType($csType, $params['contact_type']))) {
616 return civicrm_create_error("Invalid or Mismatched Contact SubType: " . implode(', ', (array)$csType));
620 if (!CRM_Utils_Array
::value('contact_id', $params)) {
623 foreach ($fields as $field) {
624 if (is_array($field)) {
626 foreach ($field as $element) {
627 if (!CRM_Utils_Array
::value($element, $params)) {
635 if (CRM_Utils_Array
::value($field, $params)) {
645 return civicrm_create_error("Required fields not found for {$params['contact_type']} : $error");
651 // check for record already existing
652 require_once 'CRM/Dedupe/Finder.php';
653 $dedupeParams = CRM_Dedupe_Finder
::formatParams($params, $params['contact_type']);
656 // setting 'check_permission' here means that the dedupe checking will be carried out even if the
657 // person does not have permission to carry out de-dupes
658 // this is similar to the front end form
659 if (isset($params['check_permission'])) {
660 $dedupeParams['check_permission'] = $fields['check_permission'];
664 CRM_Dedupe_Finder
::dupesByParams($dedupeParams,
665 $params['contact_type'],
673 if ($dupeErrorArray) {
674 $error = CRM_Core_Error
::createError("Found matching contacts: $ids",
675 CRM_Core_Error
::DUPLICATE_CONTACT
,
678 return civicrm_create_error($error->pop());
681 return civicrm_create_error("Found matching contacts: $ids", array($ids));
685 //check for organisations with same name
686 if (CRM_Utils_Array
::value('current_employer', $params)) {
687 $organizationParams = array();
688 $organizationParams['organization_name'] = $params['current_employer'];
690 require_once 'CRM/Dedupe/Finder.php';
691 $dedupParams = CRM_Dedupe_Finder
::formatParams($organizationParams, 'Organization');
693 $dedupParams['check_permission'] = FALSE;
694 $dupeIds = CRM_Dedupe_Finder
::dupesByParams($dedupParams, 'Organization', 'Fuzzy');
696 // check for mismatch employer name and id
697 if (CRM_Utils_Array
::value('employer_id', $params)
698 && !in_array($params['employer_id'], $dupeIds)
700 return civicrm_create_error('Employer name and Employer id Mismatch');
703 // show error if multiple organisation with same name exist
704 if (!CRM_Utils_Array
::value('employer_id', $params)
705 && (count($dupeIds) > 1)
707 return civicrm_create_error('Found more than one Organisation with same Name.');
715 * @todo What does this do? If it's still useful, figure out where it should live and what it should be named.
717 * @deprecated deprecated since version 2.2.3
719 function civicrm_replace_contact_formatted($contactId, &$params, &$fields) {
720 //$contact = civcrm_get_contact(array('contact_id' => $contactId));
722 $delContact = array('contact_id' => $contactId);
724 civicrm_contact_delete($delContact);
726 $cid = CRM_Contact_BAO_Contact
::createProfileContact($params, $fields,
728 $params['contact_type']
730 return civicrm_create_success($cid);
734 * Takes an associative array and creates a contact object and all the associated
735 * derived objects (i.e. individual, location, email, phone etc)
737 * @param array $params (reference ) an assoc array of name/value pairs
738 * @param int $contactID if present the contact with that ID is updated
740 * @return object CRM_Contact_BAO_Contact object
744 function _civicrm_contact_update(&$params, $contactID = NULL) {
745 require_once 'CRM/Core/Transaction.php';
746 $transaction = new CRM_Core_Transaction();
749 $params['contact_id'] = $contactID;
751 require_once 'CRM/Contact/BAO/Contact.php';
753 $contact = CRM_Contact_BAO_Contact
::create($params);
755 $transaction->commit();
761 * @todo Move this to ContactFormat.php
764 function civicrm_contact_format_create(&$params) {
765 _civicrm_initialize();
767 CRM_Core_DAO
::freeResult();
769 // return error if we have no params
770 if (empty($params)) {
771 return civicrm_create_error('Input Parameters empty');
774 $error = _civicrm_required_formatted_contact($params);
775 if (civicrm_error($error)) {
779 $error = _civicrm_validate_formatted_contact($params);
780 if (civicrm_error($error)) {
784 //get the prefix id etc if exists
785 require_once 'CRM/Contact/BAO/Contact.php';
786 CRM_Contact_BAO_Contact
::resolveDefaults($params, TRUE);
788 require_once 'CRM/Import/Parser.php';
789 if (CRM_Utils_Array
::value('onDuplicate', $params) != CRM_Import_Parser
::DUPLICATE_NOCHECK
) {
790 CRM_Core_Error
::reset();
791 $error = _civicrm_duplicate_formatted_contact($params);
792 if (civicrm_error($error)) {
797 $contact = CRM_Contact_BAO_Contact
::create($params,
798 CRM_Utils_Array
::value('fixAddress', $params)
801 _civicrm_object_to_array($contact, $contactArray);
802 return $contactArray;
806 * Returns the number of Contact objects which match the search criteria specified in $params.
808 * @deprecated deprecated since version 2.2.3; civicrm_contact_get now returns a record_count value
810 * @param array $params
815 function civicrm_contact_search_count(&$params) {
816 // convert the params to new format
817 require_once 'CRM/Contact/Form/Search.php';
818 $newP = CRM_Contact_BAO_Query
::convertFormValues($params);
819 $query = new CRM_Contact_BAO_Query($newP);
820 return $query->searchQuery(0, 0, NULL, TRUE);
824 * Ensure that we have the right input parameters for custom data
826 * @param array $params Associative array of property name/value
827 * pairs to insert in new contact.
828 * @param string $csType contact subtype if exists/passed.
830 * @return null on success, error message otherwise
833 function civicrm_contact_check_custom_params($params, $csType = NULL) {
834 empty($csType) ?
$onlyParent = TRUE : $onlyParent = FALSE;
836 require_once 'CRM/Core/BAO/CustomField.php';
837 $customFields = CRM_Core_BAO_CustomField
::getFields($params['contact_type'], FALSE, FALSE, $csType, NULL, $onlyParent);
839 foreach ($params as $key => $value) {
840 if ($customFieldID = CRM_Core_BAO_CustomField
::getKeyID($key)) {
841 /* check if it's a valid custom field id */
844 if (!array_key_exists($customFieldID, $customFields)) {
846 $errorMsg = ts("Invalid Custom Field Contact Type: {$params['contact_type']}");
848 $errorMsg .= ts(" or Mismatched SubType: " . implode(', ', (array)$csType));
850 return civicrm_create_error($errorMsg);