drupal-civicrm/sites/all/modules/civicrm/CRM/Contact/BAO/Contact.php

3537 lines
113 KiB
PHP
Raw Normal View History

2018-01-14 15:10:16 +02:00
<?php
/*
+--------------------------------------------------------------------+
| CiviCRM version 4.7 |
+--------------------------------------------------------------------+
| Copyright CiviCRM LLC (c) 2004-2017 |
+--------------------------------------------------------------------+
| This file is a part of CiviCRM. |
| |
| CiviCRM is free software; you can copy, modify, and distribute it |
| under the terms of the GNU Affero General Public License |
| Version 3, 19 November 2007 and the CiviCRM Licensing Exception. |
| |
| CiviCRM is distributed in the hope that it will be useful, but |
| WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
| See the GNU Affero General Public License for more details. |
| |
| You should have received a copy of the GNU Affero General Public |
| License and the CiviCRM Licensing Exception along |
| with this program; if not, contact CiviCRM LLC |
| at info[AT]civicrm[DOT]org. If you have questions about the |
| GNU Affero General Public License or the licensing of CiviCRM, |
| see the CiviCRM license FAQ at http://civicrm.org/licensing |
+--------------------------------------------------------------------+
*/
/**
*
* @package CRM
* @copyright CiviCRM LLC (c) 2004-2017
*/
class CRM_Contact_BAO_Contact extends CRM_Contact_DAO_Contact {
/**
* SQL function used to format the phone_numeric field via trigger.
* @see self::triggerInfo()
*
* Note that this is also used by the 4.3 upgrade script.
* @see CRM_Upgrade_Incremental_php_FourThree
*/
const DROP_STRIP_FUNCTION_43 = "DROP FUNCTION IF EXISTS civicrm_strip_non_numeric";
const CREATE_STRIP_FUNCTION_43 = "
CREATE FUNCTION civicrm_strip_non_numeric(input VARCHAR(255) CHARACTER SET utf8)
RETURNS VARCHAR(255) CHARACTER SET utf8
DETERMINISTIC
NO SQL
BEGIN
DECLARE output VARCHAR(255) CHARACTER SET utf8 DEFAULT '';
DECLARE iterator INT DEFAULT 1;
WHILE iterator < (LENGTH(input) + 1) DO
IF SUBSTRING(input, iterator, 1) IN ('0', '1', '2', '3', '4', '5', '6', '7', '8', '9') THEN
SET output = CONCAT(output, SUBSTRING(input, iterator, 1));
END IF;
SET iterator = iterator + 1;
END WHILE;
RETURN output;
END";
/**
* The types of communication preferences.
*
* @var array
*/
static $_commPrefs = array(
'do_not_phone',
'do_not_email',
'do_not_mail',
'do_not_sms',
'do_not_trade',
);
/**
* Types of greetings.
*
* @var array
*/
static $_greetingTypes = array(
'addressee',
'email_greeting',
'postal_greeting',
);
/**
* Static field for all the contact information that we can potentially import.
*
* @var array
*/
static $_importableFields = array();
/**
* Static field for all the contact information that we can potentially export.
*
* @var array
*/
static $_exportableFields = NULL;
/**
* Class constructor.
*/
public function __construct() {
parent::__construct();
}
/**
* Takes an associative array and creates a contact object.
*
* The function extracts all the params it needs to initialize the create a
* contact object. the params array could contain additional unused name/value
* pairs
*
* @param array $params
* (reference) an assoc array of name/value pairs.
*
* @return CRM_Contact_BAO_Contact|CRM_Core_Error|NULL
* Created or updated contact object or error object.
* (error objects are being phased out in favour of exceptions)
*/
public static function add(&$params) {
$contact = new CRM_Contact_DAO_Contact();
if (empty($params)) {
return NULL;
}
// Fix for validate contact sub type CRM-5143.
if (isset($params['contact_sub_type'])) {
if (empty($params['contact_sub_type'])) {
$params['contact_sub_type'] = 'null';
}
else {
if (!CRM_Contact_BAO_ContactType::isExtendsContactType($params['contact_sub_type'],
$params['contact_type'], TRUE
)
) {
// we'll need to fix tests to handle this
// CRM-7925
CRM_Core_Error::fatal(ts('The Contact Sub Type does not match the Contact type for this record'));
}
$params['contact_sub_type'] = CRM_Utils_Array::implodePadded($params['contact_sub_type']);
}
}
else {
// Reset the value.
// CRM-101XX.
$params['contact_sub_type'] = 'null';
}
// Fixed contact source.
if (isset($params['contact_source'])) {
$params['source'] = $params['contact_source'];
}
if (isset($params['preferred_communication_method']) && is_array($params['preferred_communication_method'])) {
CRM_Utils_Array::formatArrayKeys($params['preferred_communication_method']);
$contact->preferred_communication_method = CRM_Utils_Array::implodePadded($params['preferred_communication_method']);
unset($params['preferred_communication_method']);
}
$allNull = $contact->copyValues($params);
$contact->id = CRM_Utils_Array::value('contact_id', $params);
if ($contact->contact_type == 'Individual') {
$allNull = FALSE;
// Format individual fields.
CRM_Contact_BAO_Individual::format($params, $contact);
}
elseif ($contact->contact_type == 'Household') {
if (isset($params['household_name'])) {
$allNull = FALSE;
$contact->display_name = $contact->sort_name = CRM_Utils_Array::value('household_name', $params, '');
}
}
elseif ($contact->contact_type == 'Organization') {
if (isset($params['organization_name'])) {
$allNull = FALSE;
$contact->display_name = $contact->sort_name = CRM_Utils_Array::value('organization_name', $params, '');
}
}
if (strlen($contact->display_name) > 128) {
$contact->display_name = substr($contact->display_name, 0, 128);
}
if (strlen($contact->sort_name) > 128) {
$contact->sort_name = substr($contact->sort_name, 0, 128);
}
$privacy = CRM_Utils_Array::value('privacy', $params);
if ($privacy &&
is_array($privacy) &&
!empty($privacy)
) {
$allNull = FALSE;
foreach (self::$_commPrefs as $name) {
$contact->$name = CRM_Utils_Array::value($name, $privacy, FALSE);
}
}
// Since hash was required, make sure we have a 0 value for it (CRM-1063).
// @todo - does this mean we can remove this block?
// Fixed in 1.5 by making hash optional, only do this in create mode, not update.
if ((!array_key_exists('hash', $contact) || !$contact->hash) && !$contact->id) {
$allNull = FALSE;
$contact->hash = md5(uniqid(rand(), TRUE));
}
// Even if we don't need $employerId, it's important to call getFieldValue() before
// the contact is saved because we want the existing value to be cached.
// createCurrentEmployerRelationship() needs the old value not the updated one. CRM-10788
$employerId = empty($contact->id) ? NULL : CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact', $contact->id, 'employer_id');
if (!$allNull) {
$contact->save();
CRM_Core_BAO_Log::register($contact->id,
'civicrm_contact',
$contact->id
);
}
if ($contact->contact_type == 'Individual' && (isset($params['current_employer']) || isset($params['employer_id']))) {
// Create current employer.
$newEmployer = !empty($params['employer_id']) ? $params['employer_id'] : CRM_Utils_Array::value('current_employer', $params);
$newContact = FALSE;
if (empty($params['contact_id'])) {
$newContact = TRUE;
}
if ($newEmployer) {
CRM_Contact_BAO_Contact_Utils::createCurrentEmployerRelationship($contact->id, $newEmployer, $employerId, $newContact);
}
else {
if ($employerId) {
CRM_Contact_BAO_Contact_Utils::clearCurrentEmployer($contact->id, $employerId);
}
}
}
// Update cached employer name.
if ($contact->contact_type == 'Organization') {
CRM_Contact_BAO_Contact_Utils::updateCurrentEmployer($contact->id);
}
return $contact;
}
/**
* Create contact.
*
* takes an associative array and creates a contact object and all the associated
* derived objects (i.e. individual, location, email, phone etc)
*
* This function is invoked from within the web form layer and also from the api layer
*
* @param array $params
* (reference ) an assoc array of name/value pairs.
* @param bool $fixAddress
* If we need to fix address.
* @param bool $invokeHooks
* If we need to invoke hooks.
*
* @param bool $skipDelete
* Unclear parameter, passed to website create
*
* @todo explain this parameter
*
* @throws Exception
* @return CRM_Contact_BAO_Contact|CRM_Core_Error
* Created or updated contribution object. We are deprecating returning an error in
* favour of exceptions
*/
public static function &create(&$params, $fixAddress = TRUE, $invokeHooks = TRUE, $skipDelete = FALSE) {
$contact = NULL;
if (empty($params['contact_type']) && empty($params['contact_id'])) {
return $contact;
}
$isEdit = TRUE;
if ($invokeHooks) {
if (!empty($params['contact_id'])) {
CRM_Utils_Hook::pre('edit', $params['contact_type'], $params['contact_id'], $params);
}
else {
CRM_Utils_Hook::pre('create', $params['contact_type'], NULL, $params);
$isEdit = FALSE;
}
}
$config = CRM_Core_Config::singleton();
// CRM-6942: set preferred language to the current language if its unset (and were creating a contact).
if (empty($params['contact_id'])) {
// A case could be made for checking isset rather than empty but this is more consistent with previous behaviour.
if (empty($params['preferred_language']) && ($language = CRM_Core_I18n::getContactDefaultLanguage()) != FALSE) {
$params['preferred_language'] = $language;
}
// CRM-9739: set greeting & addressee if unset and were creating a contact.
foreach (self::$_greetingTypes as $greeting) {
if (empty($params[$greeting . '_id'])) {
if ($defaultGreetingTypeId
= CRM_Contact_BAO_Contact_Utils::defaultGreeting($params['contact_type'], $greeting)
) {
$params[$greeting . '_id'] = $defaultGreetingTypeId;
}
}
}
}
$transaction = new CRM_Core_Transaction();
$contact = self::add($params);
if (!$contact) {
// Not dying here is stupid, since we get into weird situation and into a bug that
// is impossible to figure out for the user or for us
// CRM-7925
CRM_Core_Error::fatal();
}
$params['contact_id'] = $contact->id;
if (Civi::settings()->get('is_enabled')) {
// Enabling multisite causes the contact to be added to the domain group.
$domainGroupID = CRM_Core_BAO_Domain::getGroupId();
if (!empty($domainGroupID)) {
if (!empty($params['group']) && is_array($params['group'])) {
$params['group'][$domainGroupID] = 1;
}
else {
$params['group'] = array($domainGroupID => 1);
}
}
}
if (array_key_exists('group', $params)) {
$contactIds = array($params['contact_id']);
foreach ($params['group'] as $groupId => $flag) {
if ($flag == 1) {
CRM_Contact_BAO_GroupContact::addContactsToGroup($contactIds, $groupId);
}
elseif ($flag == -1) {
CRM_Contact_BAO_GroupContact::removeContactsFromGroup($contactIds, $groupId);
}
}
}
// Add location Block data.
$blocks = CRM_Core_BAO_Location::create($params, $fixAddress);
foreach ($blocks as $name => $value) {
$contact->$name = $value;
}
if (!empty($params['updateBlankLocInfo'])) {
$skipDelete = TRUE;
}
//add website
CRM_Core_BAO_Website::create($params['website'], $contact->id, $skipDelete);
$userID = CRM_Core_Session::singleton()->get('userID');
// add notes
if (!empty($params['note'])) {
if (is_array($params['note'])) {
foreach ($params['note'] as $note) {
$contactId = $contact->id;
if (isset($note['contact_id'])) {
$contactId = $note['contact_id'];
}
//if logged in user, overwrite contactId
if ($userID) {
$contactId = $userID;
}
$noteParams = array(
'entity_id' => $contact->id,
'entity_table' => 'civicrm_contact',
'note' => $note['note'],
'subject' => CRM_Utils_Array::value('subject', $note),
'contact_id' => $contactId,
);
CRM_Core_BAO_Note::add($noteParams, CRM_Core_DAO::$_nullArray);
}
}
else {
$contactId = $contact->id;
if (isset($note['contact_id'])) {
$contactId = $note['contact_id'];
}
//if logged in user, overwrite contactId
if ($userID) {
$contactId = $userID;
}
$noteParams = array(
'entity_id' => $contact->id,
'entity_table' => 'civicrm_contact',
'note' => $params['note'],
'subject' => CRM_Utils_Array::value('subject', $params),
'contact_id' => $contactId,
);
CRM_Core_BAO_Note::add($noteParams, CRM_Core_DAO::$_nullArray);
}
}
// update the UF user_unique_id if that has changed
CRM_Core_BAO_UFMatch::updateUFName($contact->id);
if (!empty($params['custom']) &&
is_array($params['custom'])
) {
CRM_Core_BAO_CustomValueTable::store($params['custom'], 'civicrm_contact', $contact->id);
}
// make a civicrm_subscription_history entry only on contact create (CRM-777)
if (empty($params['contact_id'])) {
$subscriptionParams = array(
'contact_id' => $contact->id,
'status' => 'Added',
'method' => 'Admin',
);
CRM_Contact_BAO_SubscriptionHistory::create($subscriptionParams);
}
$transaction->commit();
// CRM-6367: fetch the right label for contact types display
$contact->contact_type_display = CRM_Core_DAO::getFieldValue(
'CRM_Contact_DAO_ContactType',
$contact->contact_type,
'label',
'name'
);
CRM_Contact_BAO_Contact_Utils::clearContactCaches();
if ($invokeHooks) {
if ($isEdit) {
CRM_Utils_Hook::post('edit', $params['contact_type'], $contact->id, $contact);
}
else {
CRM_Utils_Hook::post('create', $params['contact_type'], $contact->id, $contact);
}
}
// process greetings CRM-4575, cache greetings
self::processGreetings($contact);
return $contact;
}
/**
* Get the display name and image of a contact.
*
* @param int $id
* The contactId.
*
* @param bool $includeTypeInReturnParameters
* Should type be part of the returned array?
*
* @return array
* the displayName and contactImage for this contact
*/
public static function getDisplayAndImage($id, $includeTypeInReturnParameters = FALSE) {
//CRM-14276 added the * on the civicrm_contact table so that we have all the contact info available
$sql = "
SELECT civicrm_contact.*,
civicrm_email.email as email
FROM civicrm_contact
LEFT JOIN civicrm_email ON civicrm_email.contact_id = civicrm_contact.id
AND civicrm_email.is_primary = 1
WHERE civicrm_contact.id = " . CRM_Utils_Type::escape($id, 'Integer');
$dao = new CRM_Core_DAO();
$dao->query($sql);
if ($dao->fetch()) {
$image = CRM_Contact_BAO_Contact_Utils::getImage($dao->contact_sub_type ?
$dao->contact_sub_type : $dao->contact_type, FALSE, $id
);
$imageUrl = CRM_Contact_BAO_Contact_Utils::getImage($dao->contact_sub_type ?
$dao->contact_sub_type : $dao->contact_type, TRUE, $id
);
// use email if display_name is empty
if (empty($dao->display_name)) {
$displayName = $dao->email;
}
else {
$displayName = $dao->display_name;
}
CRM_Utils_Hook::alterDisplayName($displayName, $id, $dao);
return $includeTypeInReturnParameters ? array(
$displayName,
$image,
$dao->contact_type,
$dao->contact_sub_type,
$imageUrl,
) : array($displayName, $image, $imageUrl);
}
return NULL;
}
/**
* Add billing fields to the params if appropriate.
*
* If we have ANY name fields then we want to ignore all the billing name fields. However, if we
* don't then we should set the name fields to the filling fields AND add the preserveDBName
* parameter (which will tell the BAO only to set those fields if none already exist.
*
* We specifically don't want to set first name from billing and last name form an on-page field. Mixing &
* matching is best done by hipsters.
*
* @param array $params
*/
public static function addBillingNameFieldsIfOtherwiseNotSet(&$params) {
$nameFields = array('first_name', 'middle_name', 'last_name', 'nick_name', 'prefix_id', 'suffix_id');
foreach ($nameFields as $field) {
if (!empty($params[$field])) {
return;
}
}
// There are only 3 - we can iterate through them twice :-)
foreach ($nameFields as $field) {
if (!empty($params['billing_' . $field])) {
$params[$field] = $params['billing_' . $field];
}
$params['preserveDBName'] = TRUE;
}
}
/**
* Create last viewed link to recently updated contact.
*
* @param array $crudLinkSpec
* - action: int, CRM_Core_Action::UPDATE or CRM_Core_Action::VIEW [default: VIEW]
* - entity_table: string, eg "civicrm_contact"
* - entity_id: int
*
* @return array|NULL
* NULL if unavailable, or
* [path: string, query: string, title: string]
* @see CRM_Utils_System::createDefaultCrudLink
*/
public function createDefaultCrudLink($crudLinkSpec) {
switch ($crudLinkSpec['action']) {
case CRM_Core_Action::VIEW:
$result = array(
'title' => $this->display_name,
'path' => 'civicrm/contact/view',
'query' => array(
'reset' => 1,
'cid' => $this->id,
),
);
return $result;
case CRM_Core_Action::UPDATE:
$result = array(
'title' => $this->display_name,
'path' => 'civicrm/contact/add',
'query' => array(
'reset' => 1,
'action' => 'update',
'cid' => $this->id,
),
);
return $result;
}
return NULL;
}
/**
* Get the values for pseudoconstants for name->value and reverse.
*
* @param array $defaults
* (reference) the default values, some of which need to be resolved.
* @param bool $reverse
* True if we want to resolve the values in the reverse direction (value -> name).
*/
public static function resolveDefaults(&$defaults, $reverse = FALSE) {
// Hack for birth_date.
if (!empty($defaults['birth_date'])) {
if (is_array($defaults['birth_date'])) {
$defaults['birth_date'] = CRM_Utils_Date::format($defaults['birth_date'], '-');
}
}
CRM_Utils_Array::lookupValue($defaults, 'prefix', CRM_Core_PseudoConstant::get('CRM_Contact_DAO_Contact', 'prefix_id'), $reverse);
CRM_Utils_Array::lookupValue($defaults, 'suffix', CRM_Core_PseudoConstant::get('CRM_Contact_DAO_Contact', 'suffix_id'), $reverse);
CRM_Utils_Array::lookupValue($defaults, 'gender', CRM_Core_PseudoConstant::get('CRM_Contact_DAO_Contact', 'gender_id'), $reverse);
CRM_Utils_Array::lookupValue($defaults, 'communication_style', CRM_Core_PseudoConstant::get('CRM_Contact_DAO_Contact', 'communication_style_id'), $reverse);
//lookup value of email/postal greeting, addressee, CRM-4575
foreach (self::$_greetingTypes as $greeting) {
$filterCondition = array(
'contact_type' => CRM_Utils_Array::value('contact_type', $defaults),
'greeting_type' => $greeting,
);
CRM_Utils_Array::lookupValue($defaults, $greeting,
CRM_Core_PseudoConstant::greeting($filterCondition), $reverse
);
}
$blocks = array('address', 'im', 'phone');
foreach ($blocks as $name) {
if (!array_key_exists($name, $defaults) || !is_array($defaults[$name])) {
continue;
}
foreach ($defaults[$name] as $count => & $values) {
//get location type id.
CRM_Utils_Array::lookupValue($values, 'location_type', CRM_Core_PseudoConstant::get('CRM_Core_DAO_Address', 'location_type_id'), $reverse);
if ($name == 'address') {
// FIXME: lookupValue doesn't work for vcard_name
if (!empty($values['location_type_id'])) {
$vcardNames = CRM_Core_PseudoConstant::get('CRM_Core_DAO_Address', 'location_type_id', array('labelColumn' => 'vcard_name'));
$values['vcard_name'] = $vcardNames[$values['location_type_id']];
}
if (!CRM_Utils_Array::lookupValue($values,
'country',
CRM_Core_PseudoConstant::country(),
$reverse
) &&
$reverse
) {
CRM_Utils_Array::lookupValue($values,
'country',
CRM_Core_PseudoConstant::countryIsoCode(),
$reverse
);
}
// CRM-7597
// if we find a country id above, we need to restrict it to that country
// rather than the list of all countries
if (!empty($values['country_id'])) {
$stateProvinceList = CRM_Core_PseudoConstant::stateProvinceForCountry($values['country_id']);
}
else {
$stateProvinceList = CRM_Core_PseudoConstant::stateProvince();
}
if (!CRM_Utils_Array::lookupValue($values,
'state_province',
$stateProvinceList,
$reverse
) &&
$reverse
) {
if (!empty($values['country_id'])) {
$stateProvinceList = CRM_Core_PseudoConstant::stateProvinceForCountry($values['country_id'], 'abbreviation');
}
else {
$stateProvinceList = CRM_Core_PseudoConstant::stateProvinceAbbreviation();
}
CRM_Utils_Array::lookupValue($values,
'state_province',
$stateProvinceList,
$reverse
);
}
if (!empty($values['state_province_id'])) {
$countyList = CRM_Core_PseudoConstant::countyForState($values['state_province_id']);
}
else {
$countyList = CRM_Core_PseudoConstant::county();
}
CRM_Utils_Array::lookupValue($values,
'county',
$countyList,
$reverse
);
}
if ($name == 'im') {
CRM_Utils_Array::lookupValue($values,
'provider',
CRM_Core_PseudoConstant::get('CRM_Core_DAO_IM', 'provider_id'),
$reverse
);
}
if ($name == 'phone') {
CRM_Utils_Array::lookupValue($values,
'phone_type',
CRM_Core_PseudoConstant::get('CRM_Core_DAO_Phone', 'phone_type_id'),
$reverse
);
}
// Kill the reference.
unset($values);
}
}
}
/**
* Fetch object based on array of properties.
*
* @param array $params
* (reference ) an assoc array of name/value pairs.
* @param array $defaults
* (reference ) an assoc array to hold the name / value pairs.
* in a hierarchical manner
* @param bool $microformat
* For location in microformat.
*
* @return CRM_Contact_BAO_Contact
*/
public static function &retrieve(&$params, &$defaults, $microformat = FALSE) {
if (array_key_exists('contact_id', $params)) {
$params['id'] = $params['contact_id'];
}
elseif (array_key_exists('id', $params)) {
$params['contact_id'] = $params['id'];
}
$contact = self::getValues($params, $defaults);
unset($params['id']);
//get the block information for this contact
$entityBlock = array('contact_id' => $params['contact_id']);
$blocks = CRM_Core_BAO_Location::getValues($entityBlock, $microformat);
$defaults = array_merge($defaults, $blocks);
foreach ($blocks as $block => $value) {
$contact->$block = $value;
}
if (!isset($params['noNotes'])) {
$contact->notes = CRM_Core_BAO_Note::getValues($params, $defaults);
}
if (!isset($params['noRelationships'])) {
$contact->relationship = CRM_Contact_BAO_Relationship::getValues($params, $defaults);
}
if (!isset($params['noGroups'])) {
$contact->groupContact = CRM_Contact_BAO_GroupContact::getValues($params, $defaults);
}
if (!isset($params['noWebsite'])) {
$contact->website = CRM_Core_BAO_Website::getValues($params, $defaults);
}
return $contact;
}
/**
* Get the display name of a contact.
*
* @param int $id
* Id of the contact.
*
* @return null|string
* display name of the contact if found
*/
public static function displayName($id) {
$displayName = NULL;
if ($id) {
$displayName = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact', $id, 'display_name');
}
return $displayName;
}
/**
* Delete a contact and all its associated records.
*
* @param int $id
* Id of the contact to delete.
* @param bool $restore
* Whether to actually restore, not delete.
* @param bool $skipUndelete
* Whether to force contact delete or not.
* @param bool $checkPermissions
*
* @return bool
* Was contact deleted?
*/
public static function deleteContact($id, $restore = FALSE, $skipUndelete = FALSE, $checkPermissions = TRUE) {
if (!$id) {
return FALSE;
}
// If trash is disabled in system settings then we always skip
if (!Civi::settings()->get('contact_undelete')) {
$skipUndelete = TRUE;
}
// make sure we have edit permission for this contact
// before we delete
if ($checkPermissions && (($skipUndelete && !CRM_Core_Permission::check('delete contacts')) ||
($restore && !CRM_Core_Permission::check('access deleted contacts')))
) {
return FALSE;
}
// CRM-12929
// Restrict contact to be delete if contact has financial trxns
$error = NULL;
if ($skipUndelete && CRM_Financial_BAO_FinancialItem::checkContactPresent(array($id), $error)) {
return FALSE;
}
// make sure this contact_id does not have any membership types
$membershipTypeID = CRM_Core_DAO::getFieldValue('CRM_Member_DAO_MembershipType',
$id,
'id',
'member_of_contact_id'
);
if ($membershipTypeID) {
return FALSE;
}
$contact = new CRM_Contact_DAO_Contact();
$contact->id = $id;
if (!$contact->find(TRUE)) {
return FALSE;
}
$contactType = $contact->contact_type;
// currently we only clear employer cache.
// we are now deleting inherited membership if any.
if ($contact->contact_type == 'Organization') {
$action = $restore ? CRM_Core_Action::ENABLE : CRM_Core_Action::DISABLE;
$relationshipDtls = CRM_Contact_BAO_Relationship::getRelationship($id);
if (!empty($relationshipDtls)) {
foreach ($relationshipDtls as $rId => $details) {
CRM_Contact_BAO_Relationship::disableEnableRelationship($rId, $action);
}
}
CRM_Contact_BAO_Contact_Utils::clearAllEmployee($id);
}
if ($restore) {
return self::contactTrashRestore($contact, TRUE);
}
// start a new transaction
$transaction = new CRM_Core_Transaction();
if ($skipUndelete) {
CRM_Utils_Hook::pre('delete', $contactType, $id, CRM_Core_DAO::$_nullArray);
//delete billing address if exists.
CRM_Contribute_BAO_Contribution::deleteAddress(NULL, $id);
// delete the log entries since we dont have triggers enabled as yet
$logDAO = new CRM_Core_DAO_Log();
$logDAO->entity_table = 'civicrm_contact';
$logDAO->entity_id = $id;
$logDAO->delete();
// delete contact participants CRM-12155
CRM_Event_BAO_Participant::deleteContactParticipant($id);
// delete contact contributions CRM-12155
CRM_Contribute_BAO_Contribution::deleteContactContribution($id);
// do activity cleanup, CRM-5604
CRM_Activity_BAO_Activity::cleanupActivity($id);
// delete all notes related to contact
CRM_Core_BAO_Note::cleanContactNotes($id);
// delete cases related to contact
$contactCases = CRM_Case_BAO_Case::retrieveCaseIdsByContactId($id);
if (!empty($contactCases)) {
foreach ($contactCases as $caseId) {
//check if case is associate with other contact or not.
$caseContactId = CRM_Case_BAO_Case::getCaseClients($caseId);
if (count($caseContactId) <= 1) {
CRM_Case_BAO_Case::deleteCase($caseId);
}
}
}
$contact->delete();
}
else {
self::contactTrashRestore($contact);
}
//delete the contact id from recently view
CRM_Utils_Recent::delContact($id);
self::updateContactCache($id, empty($restore));
// delete any dupe cache entry
CRM_Core_BAO_PrevNextCache::deleteItem($id);
$transaction->commit();
if ($skipUndelete) {
CRM_Utils_Hook::post('delete', $contactType, $contact->id, $contact);
}
// also reset the DB_DO global array so we can reuse the memory
// http://issues.civicrm.org/jira/browse/CRM-4387
CRM_Core_DAO::freeResult();
return TRUE;
}
/**
* Action to update any caches relating to a recently update contact.
*
* I was going to call this from delete as well as from create to ensure the delete is being
* done whenever a contact is set to is_deleted=1 BUT I found create is already over-aggressive in
* that regard so adding it to delete seems to be enough to remove it from CRM_Contact_BAO_Contact_Permission
* where the call involved a subquery that was locking the table.
*
* @param int $contactID
* @param bool $isTrashed
*/
public static function updateContactCache($contactID, $isTrashed = FALSE) {
if ($isTrashed) {
CRM_Contact_BAO_GroupContactCache::removeContact($contactID);
// This has been moved to here from CRM_Contact_BAO_Contact_Permission as that was causing
// a table-locking query. It still seems a bit inadequate as it assumes the acl users can't see deleted
// but this should not cause any change as long as contacts are not being trashed outside the
// main functions for that.
CRM_Core_DAO::executeQuery('DELETE FROM civicrm_acl_contact_cache WHERE contact_id = %1', array(1 => array($contactID, 'Integer')));
}
else {
CRM_Contact_BAO_GroupContactCache::opportunisticCacheFlush();
}
}
/**
* Delete the image of a contact.
*
* @param int $id
* Id of the contact.
*
* @return bool
* Was contact image deleted?
*/
public static function deleteContactImage($id) {
if (!$id) {
return FALSE;
}
$query = "
UPDATE civicrm_contact
SET image_URL=NULL
WHERE id={$id}; ";
CRM_Core_DAO::executeQuery($query);
return TRUE;
}
/**
* Return proportional height and width of the image.
*
* @param int $imageWidth
* Width of image.
*
* @param int $imageHeight
* Height of image.
*
* @return array
* Thumb dimension of image
*/
public static function getThumbSize($imageWidth, $imageHeight) {
$thumbWidth = 100;
if ($imageWidth && $imageHeight) {
$imageRatio = $imageWidth / $imageHeight;
}
else {
$imageRatio = 1;
}
if ($imageRatio > 1) {
$imageThumbWidth = $thumbWidth;
$imageThumbHeight = round($thumbWidth / $imageRatio);
}
else {
$imageThumbHeight = $thumbWidth;
$imageThumbWidth = round($thumbWidth * $imageRatio);
}
return array($imageThumbWidth, $imageThumbHeight);
}
/**
* Validate type of contact image.
*
* @param array $params
* @param string $imageIndex
* Index of image field.
* @param string $statusMsg
* Status message to be set after operation.
* @param string $opType
* Type of operation like fatal, bounce etc.
*
* @return bool
* true if valid image extension
*/
public static function processImageParams(
&$params,
$imageIndex = 'image_URL',
$statusMsg = NULL,
$opType = 'status'
) {
$mimeType = array(
'image/jpeg',
'image/jpg',
'image/png',
'image/bmp',
'image/p-jpeg',
'image/gif',
'image/x-png',
);
if (in_array($params[$imageIndex]['type'], $mimeType)) {
$photo = basename($params[$imageIndex]['name']);
$params[$imageIndex] = CRM_Utils_System::url('civicrm/contact/imagefile', 'photo=' . $photo, TRUE, NULL, TRUE, TRUE);
return TRUE;
}
else {
unset($params[$imageIndex]);
if (!$statusMsg) {
$statusMsg = ts('Image could not be uploaded due to invalid type extension.');
}
if ($opType == 'status') {
CRM_Core_Session::setStatus($statusMsg, 'Sorry', 'error');
}
// FIXME: additional support for fatal, bounce etc could be added.
return FALSE;
}
}
/**
* Extract contact id from url for deleting contact image.
*/
public static function processImage() {
$action = CRM_Utils_Request::retrieve('action', 'String');
$cid = CRM_Utils_Request::retrieve('cid', 'Positive');
// retrieve contact id in case of Profile context
$id = CRM_Utils_Request::retrieve('id', 'Positive');
$cid = $cid ? $cid : $id;
if ($action & CRM_Core_Action::DELETE) {
if (CRM_Utils_Request::retrieve('confirmed', 'Boolean')) {
CRM_Contact_BAO_Contact::deleteContactImage($cid);
CRM_Core_Session::setStatus(ts('Contact image deleted successfully'), ts('Image Deleted'), 'success');
$session = CRM_Core_Session::singleton();
$toUrl = $session->popUserContext();
CRM_Utils_System::redirect($toUrl);
}
}
}
/**
* Function to set is_delete true or restore deleted contact.
*
* @param CRM_Contact_DAO_Contact $contact
* Contact DAO object.
* @param bool $restore
* True to set the is_delete = 1 else false to restore deleted contact,
* i.e. is_delete = 0
*
* @return bool
*/
public static function contactTrashRestore($contact, $restore = FALSE) {
$updateParams = array(
'id' => $contact->id,
'is_deleted' => $restore ? 0 : 1,
);
CRM_Utils_Hook::pre('update', $contact->contact_type, $contact->id, $updateParams);
$params = array(1 => array($contact->id, 'Integer'));
if (!$restore) {
$query = "DELETE FROM civicrm_uf_match WHERE contact_id = %1";
CRM_Core_DAO::executeQuery($query, $params);
}
$contact->copyValues($updateParams);
$contact->save();
CRM_Utils_Hook::post('update', $contact->contact_type, $contact->id, $contact);
return TRUE;
}
/**
* Get contact type for a contact.
*
* @param int $id
* Id of the contact whose contact type is needed.
*
* @return string
* contact_type if $id found else null ""
*/
public static function getContactType($id) {
return CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact', $id, 'contact_type');
}
/**
* Get contact sub type for a contact.
*
* @param int $id
* Id of the contact whose contact sub type is needed.
*
* @param string $implodeDelimiter
*
* @return string
* contact_sub_type if $id found else null ""
*/
public static function getContactSubType($id, $implodeDelimiter = NULL) {
$subtype = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact', $id, 'contact_sub_type');
if (!$subtype) {
return $implodeDelimiter ? NULL : array();
}
$subtype = CRM_Utils_Array::explodePadded($subtype);
if ($implodeDelimiter) {
$subtype = implode($implodeDelimiter, $subtype);
}
return $subtype;
}
/**
* Get pair of contact-type and sub-type for a contact.
*
* @param int $id
* Id of the contact whose contact sub/contact type is needed.
*
* @return array
*/
public static function getContactTypes($id) {
$params = array('id' => $id);
$details = array();
$contact = CRM_Core_DAO::commonRetrieve('CRM_Contact_DAO_Contact',
$params,
$details,
array('contact_type', 'contact_sub_type')
);
if ($contact) {
$contactTypes = array();
if ($contact->contact_sub_type) {
$contactTypes = CRM_Utils_Array::explodePadded($contact->contact_sub_type);
}
array_unshift($contactTypes, $contact->contact_type);
return $contactTypes;
}
else {
CRM_Core_Error::fatal();
}
}
/**
* Combine all the importable fields from the lower levels object.
*
* The ordering is important, since currently we do not have a weight
* scheme. Adding weight is super important
*
* @param int|string $contactType contact Type
* @param bool $status
* Status is used to manipulate first title.
* @param bool $showAll
* If true returns all fields (includes disabled fields).
* @param bool $isProfile
* If its profile mode.
* @param bool $checkPermission
* If false, do not include permissioning clause (for custom data).
*
* @param bool $withMultiCustomFields
*
* @return array
* array of importable Fields
*/
public static function importableFields(
$contactType = 'Individual',
$status = FALSE,
$showAll = FALSE,
$isProfile = FALSE,
$checkPermission = TRUE,
$withMultiCustomFields = FALSE
) {
if (empty($contactType)) {
$contactType = 'All';
}
$cacheKeyString = "importableFields $contactType";
$cacheKeyString .= $status ? '_1' : '_0';
$cacheKeyString .= $showAll ? '_1' : '_0';
$cacheKeyString .= $isProfile ? '_1' : '_0';
$cacheKeyString .= $checkPermission ? '_1' : '_0';
$fields = CRM_Utils_Array::value($cacheKeyString, self::$_importableFields);
if (!$fields) {
// check if we can retrieve from database cache
$fields = CRM_Core_BAO_Cache::getItem('contact fields', $cacheKeyString);
}
if (!$fields) {
$fields = CRM_Contact_DAO_Contact::import();
// get the fields thar are meant for contact types
if (in_array($contactType, array(
'Individual',
'Household',
'Organization',
'All',
))) {
$fields = array_merge($fields, CRM_Core_OptionValue::getFields('', $contactType));
}
$locationFields = array_merge(CRM_Core_DAO_Address::import(),
CRM_Core_DAO_Phone::import(),
CRM_Core_DAO_Email::import(),
CRM_Core_DAO_IM::import(TRUE),
CRM_Core_DAO_OpenID::import()
);
$locationFields = array_merge($locationFields,
CRM_Core_BAO_CustomField::getFieldsForImport('Address',
FALSE,
FALSE,
FALSE,
FALSE
)
);
foreach ($locationFields as $key => $field) {
$locationFields[$key]['hasLocationType'] = TRUE;
}
$fields = array_merge($fields, $locationFields);
$fields = array_merge($fields, CRM_Contact_DAO_Contact::import());
$fields = array_merge($fields, CRM_Core_DAO_Note::import());
//website fields
$fields = array_merge($fields, CRM_Core_DAO_Website::import());
$fields['url']['hasWebsiteType'] = TRUE;
if ($contactType != 'All') {
$fields = array_merge($fields,
CRM_Core_BAO_CustomField::getFieldsForImport($contactType,
$showAll,
TRUE,
FALSE,
FALSE,
$withMultiCustomFields
)
);
//unset the fields, which are not related to their
//contact type.
$commonValues = array(
'Individual' => array(
'household_name',
'legal_name',
'sic_code',
'organization_name',
),
'Household' => array(
'first_name',
'middle_name',
'last_name',
'formal_title',
'job_title',
'gender_id',
'prefix_id',
'suffix_id',
'birth_date',
'organization_name',
'legal_name',
'legal_identifier',
'sic_code',
'home_URL',
'is_deceased',
'deceased_date',
),
'Organization' => array(
'first_name',
'middle_name',
'last_name',
'formal_title',
'job_title',
'gender_id',
'prefix_id',
'suffix_id',
'birth_date',
'household_name',
'is_deceased',
'deceased_date',
),
);
foreach ($commonValues[$contactType] as $value) {
unset($fields[$value]);
}
}
else {
foreach (array('Individual', 'Household', 'Organization') as $type) {
$fields = array_merge($fields,
CRM_Core_BAO_CustomField::getFieldsForImport($type,
$showAll,
FALSE,
FALSE,
FALSE,
$withMultiCustomFields
)
);
}
}
if ($isProfile) {
$fields = array_merge($fields, array(
'group' => array(
'title' => ts('Group(s)'),
'name' => 'group',
),
'tag' => array(
'title' => ts('Tag(s)'),
'name' => 'tag',
),
'note' => array(
'title' => ts('Note(s)'),
'name' => 'note',
),
'communication_style_id' => array(
'title' => ts('Communication Style'),
'name' => 'communication_style_id',
),
));
}
//Sorting fields in alphabetical order(CRM-1507)
$fields = CRM_Utils_Array::crmArraySortByField($fields, 'title');
CRM_Core_BAO_Cache::setItem($fields, 'contact fields', $cacheKeyString);
}
self::$_importableFields[$cacheKeyString] = $fields;
if (!$isProfile) {
if (!$status) {
$fields = array_merge(array('do_not_import' => array('title' => ts('- do not import -'))),
self::$_importableFields[$cacheKeyString]
);
}
else {
$fields = array_merge(array('' => array('title' => ts('- Contact Fields -'))),
self::$_importableFields[$cacheKeyString]
);
}
}
return $fields;
}
/**
* Combine all the exportable fields from the lower levels object.
*
* Currently we are using importable fields as exportable fields
*
* @param int|string $contactType contact Type
* @param bool $status
* True while exporting primary contacts.
* @param bool $export
* True when used during export.
* @param bool $search
* True when used during search, might conflict with export param?.
*
* @param bool $withMultiRecord
*
* @return array
* array of exportable Fields
*/
public static function &exportableFields($contactType = 'Individual', $status = FALSE, $export = FALSE, $search = FALSE, $withMultiRecord = FALSE, $checkPermissions = TRUE) {
if (empty($contactType)) {
$contactType = 'All';
}
$cacheKeyString = "exportableFields $contactType";
$cacheKeyString .= $export ? '_1' : '_0';
$cacheKeyString .= $status ? '_1' : '_0';
$cacheKeyString .= $search ? '_1' : '_0';
//CRM-14501 it turns out that the impact of permissioning here is sometimes inconsistent. The field that
//calculates custom fields takes into account the logged in user & caches that for all users
//as an interim fix we will cache the fields by contact
$cacheKeyString .= '_' . CRM_Core_Session::getLoggedInContactID();
if (!self::$_exportableFields || !CRM_Utils_Array::value($cacheKeyString, self::$_exportableFields)) {
if (!self::$_exportableFields) {
self::$_exportableFields = array();
}
// check if we can retrieve from database cache
$fields = CRM_Core_BAO_Cache::getItem('contact fields', $cacheKeyString);
if (!$fields) {
$fields = CRM_Contact_DAO_Contact::export();
// The fields are meant for contact types.
if (in_array($contactType, array(
'Individual',
'Household',
'Organization',
'All',
)
)) {
$fields = array_merge($fields, CRM_Core_OptionValue::getFields('', $contactType));
}
// add current employer for individuals
$fields = array_merge($fields, array(
'current_employer' =>
array(
'name' => 'organization_name',
'title' => ts('Current Employer'),
),
));
$locationType = array(
'location_type' => array(
'name' => 'location_type',
'where' => 'civicrm_location_type.name',
'title' => ts('Location Type'),
),
);
$IMProvider = array(
'im_provider' => array(
'name' => 'im_provider',
'where' => 'civicrm_im.provider_id',
'title' => ts('IM Provider'),
),
);
$locationFields = array_merge($locationType,
CRM_Core_DAO_Address::export(),
CRM_Core_DAO_Phone::export(),
CRM_Core_DAO_Email::export(),
$IMProvider,
CRM_Core_DAO_IM::export(TRUE),
CRM_Core_DAO_OpenID::export()
);
$locationFields = array_merge($locationFields,
CRM_Core_BAO_CustomField::getFieldsForImport('Address')
);
foreach ($locationFields as $key => $field) {
$locationFields[$key]['hasLocationType'] = TRUE;
}
$fields = array_merge($fields, $locationFields);
//add world region
$fields = array_merge($fields,
CRM_Core_DAO_Worldregion::export()
);
$fields = array_merge($fields,
CRM_Contact_DAO_Contact::export()
);
//website fields
$fields = array_merge($fields, CRM_Core_DAO_Website::export());
if ($contactType != 'All') {
$fields = array_merge($fields,
CRM_Core_BAO_CustomField::getFieldsForImport($contactType, $status, FALSE, $search, $checkPermissions, $withMultiRecord)
);
}
else {
foreach (array(
'Individual',
'Household',
'Organization',
) as $type) {
$fields = array_merge($fields,
CRM_Core_BAO_CustomField::getFieldsForImport($type, FALSE, FALSE, $search, $checkPermissions, $withMultiRecord)
);
}
}
$fields['current_employer_id']['title'] = ts('Current Employer ID');
//fix for CRM-791
if ($export) {
$fields = array_merge($fields, array(
'groups' => array(
'title' => ts('Group(s)'),
'name' => 'groups',
),
'tags' => array(
'title' => ts('Tag(s)'),
'name' => 'tags',
),
'notes' => array(
'title' => ts('Note(s)'),
'name' => 'notes',
),
));
}
else {
$fields = array_merge($fields, array(
'group' => array(
'title' => ts('Group(s)'),
'name' => 'group',
),
'tag' => array(
'title' => ts('Tag(s)'),
'name' => 'tag',
),
'note' => array(
'title' => ts('Note(s)'),
'name' => 'note',
),
));
}
//Sorting fields in alphabetical order(CRM-1507)
foreach ($fields as $k => $v) {
$sortArray[$k] = CRM_Utils_Array::value('title', $v);
}
$fields = array_merge($sortArray, $fields);
//unset the field which are not related to their contact type.
if ($contactType != 'All') {
$commonValues = array(
'Individual' => array(
'household_name',
'legal_name',
'sic_code',
'organization_name',
'email_greeting_custom',
'postal_greeting_custom',
'addressee_custom',
),
'Household' => array(
'first_name',
'middle_name',
'last_name',
'formal_title',
'job_title',
'gender_id',
'prefix_id',
'suffix_id',
'birth_date',
'organization_name',
'legal_name',
'legal_identifier',
'sic_code',
'home_URL',
'is_deceased',
'deceased_date',
'current_employer',
'email_greeting_custom',
'postal_greeting_custom',
'addressee_custom',
'prefix_id',
'suffix_id',
),
'Organization' => array(
'first_name',
'middle_name',
'last_name',
'formal_title',
'job_title',
'gender_id',
'prefix_id',
'suffix_id',
'birth_date',
'household_name',
'email_greeting_custom',
'postal_greeting_custom',
'prefix_id',
'suffix_id',
'gender_id',
'addressee_custom',
'is_deceased',
'deceased_date',
'current_employer',
),
);
foreach ($commonValues[$contactType] as $value) {
unset($fields[$value]);
}
}
CRM_Core_BAO_Cache::setItem($fields, 'contact fields', $cacheKeyString);
}
self::$_exportableFields[$cacheKeyString] = $fields;
}
if (!$status) {
$fields = self::$_exportableFields[$cacheKeyString];
}
else {
$fields = array_merge(array('' => array('title' => ts('- Contact Fields -'))),
self::$_exportableFields[$cacheKeyString]
);
}
return $fields;
}
/**
* Get the all contact details (Hierarchical).
*
* @param int $contactId
* Contact id.
* @param array $fields
* Fields array.
*
* @return array
* Contact details
*/
public static function getHierContactDetails($contactId, &$fields) {
$params = array(array('contact_id', '=', $contactId, 0, 0));
$options = array();
$returnProperties = self::makeHierReturnProperties($fields, $contactId);
// We don't know the contents of return properties, but we need the lower
// level ids of the contact so add a few fields.
$returnProperties['first_name'] = 1;
$returnProperties['organization_name'] = 1;
$returnProperties['household_name'] = 1;
$returnProperties['contact_type'] = 1;
$returnProperties['contact_sub_type'] = 1;
return list($query, $options) = CRM_Contact_BAO_Query::apiQuery($params, $returnProperties, $options);
}
/**
* Given a set of flat profile style field names, create a hierarchy.
*
* This is for the query to use, create the right sql.
*
* @param $fields
* @param int $contactId
* Contact id.
*
* @return array
* A hierarchical property tree if appropriate
*/
public static function &makeHierReturnProperties($fields, $contactId = NULL) {
$locationTypes = CRM_Core_PseudoConstant::get('CRM_Core_DAO_Address', 'location_type_id');
$returnProperties = array();
$multipleFields = array('website' => 'url');
foreach ($fields as $name => $dontCare) {
if (strpos($name, '-') !== FALSE) {
list($fieldName, $id, $type) = CRM_Utils_System::explode('-', $name, 3);
if (!in_array($fieldName, $multipleFields)) {
if ($id == 'Primary') {
$locationTypeName = 1;
}
else {
$locationTypeName = CRM_Utils_Array::value($id, $locationTypes);
if (!$locationTypeName) {
continue;
}
}
if (empty($returnProperties['location'])) {
$returnProperties['location'] = array();
}
if (empty($returnProperties['location'][$locationTypeName])) {
$returnProperties['location'][$locationTypeName] = array();
$returnProperties['location'][$locationTypeName]['location_type'] = $id;
}
if (in_array($fieldName, array(
'phone',
'im',
'email',
'openid',
'phone_ext',
))) {
if ($type) {
$returnProperties['location'][$locationTypeName][$fieldName . '-' . $type] = 1;
}
else {
$returnProperties['location'][$locationTypeName][$fieldName] = 1;
}
}
elseif (substr($fieldName, 0, 14) === 'address_custom') {
$returnProperties['location'][$locationTypeName][substr($fieldName, 8)] = 1;
}
else {
$returnProperties['location'][$locationTypeName][$fieldName] = 1;
}
}
else {
$returnProperties['website'][$id][$fieldName] = 1;
}
}
else {
$returnProperties[$name] = 1;
}
}
return $returnProperties;
}
/**
* Return the primary location type of a contact.
*
* $params int $contactId contact_id
* $params boolean $isPrimaryExist if true, return primary contact location type otherwise null
* $params boolean $skipDefaultPriamry if true, return primary contact location type otherwise null
*
* @param int $contactId
* @param bool $skipDefaultPriamry
* @param null $block
*
* @return int
* $locationType location_type_id
*/
public static function getPrimaryLocationType($contactId, $skipDefaultPriamry = FALSE, $block = NULL) {
if ($block) {
$entityBlock = array('contact_id' => $contactId);
$blocks = CRM_Core_BAO_Location::getValues($entityBlock);
foreach ($blocks[$block] as $key => $value) {
if (!empty($value['is_primary'])) {
$locationType = CRM_Utils_Array::value('location_type_id', $value);
}
}
}
else {
$query = "
SELECT
IF ( civicrm_email.location_type_id IS NULL,
IF ( civicrm_address.location_type_id IS NULL,
IF ( civicrm_phone.location_type_id IS NULL,
IF ( civicrm_im.location_type_id IS NULL,
IF ( civicrm_openid.location_type_id IS NULL, null, civicrm_openid.location_type_id)
,civicrm_im.location_type_id)
,civicrm_phone.location_type_id)
,civicrm_address.location_type_id)
,civicrm_email.location_type_id) as locationType
FROM civicrm_contact
LEFT JOIN civicrm_email ON ( civicrm_email.is_primary = 1 AND civicrm_email.contact_id = civicrm_contact.id )
LEFT JOIN civicrm_address ON ( civicrm_address.is_primary = 1 AND civicrm_address.contact_id = civicrm_contact.id)
LEFT JOIN civicrm_phone ON ( civicrm_phone.is_primary = 1 AND civicrm_phone.contact_id = civicrm_contact.id)
LEFT JOIN civicrm_im ON ( civicrm_im.is_primary = 1 AND civicrm_im.contact_id = civicrm_contact.id)
LEFT JOIN civicrm_openid ON ( civicrm_openid.is_primary = 1 AND civicrm_openid.contact_id = civicrm_contact.id)
WHERE civicrm_contact.id = %1 ";
$params = array(1 => array($contactId, 'Integer'));
$dao = CRM_Core_DAO::executeQuery($query, $params);
$locationType = NULL;
if ($dao->fetch()) {
$locationType = $dao->locationType;
}
}
if (isset($locationType)) {
return $locationType;
}
elseif ($skipDefaultPriamry) {
// if there is no primary contact location then return null
return NULL;
}
else {
// if there is no primart contact location, then return default
// location type of the system
$defaultLocationType = CRM_Core_BAO_LocationType::getDefault();
return $defaultLocationType->id;
}
}
/**
* Get the display name, primary email and location type of a contact.
*
* @param int $id
* Id of the contact.
*
* @return array
* Array of display_name, email if found, do_not_email or (null,null,null)
*/
public static function getContactDetails($id) {
// check if the contact type
$contactType = self::getContactType($id);
$nameFields = ($contactType == 'Individual') ? "civicrm_contact.first_name, civicrm_contact.last_name, civicrm_contact.display_name" : "civicrm_contact.display_name";
$sql = "
SELECT $nameFields, civicrm_email.email, civicrm_contact.do_not_email, civicrm_email.on_hold, civicrm_contact.is_deceased
FROM civicrm_contact LEFT JOIN civicrm_email ON (civicrm_contact.id = civicrm_email.contact_id)
WHERE civicrm_contact.id = %1
ORDER BY civicrm_email.is_primary DESC";
$params = array(1 => array($id, 'Integer'));
$dao = CRM_Core_DAO::executeQuery($sql, $params);
if ($dao->fetch()) {
if ($contactType == 'Individual') {
if ($dao->first_name || $dao->last_name) {
$name = "{$dao->first_name} {$dao->last_name}";
}
else {
$name = $dao->display_name;
}
}
else {
$name = $dao->display_name;
}
$email = $dao->email;
$doNotEmail = $dao->do_not_email ? TRUE : FALSE;
$onHold = $dao->on_hold ? TRUE : FALSE;
$isDeceased = $dao->is_deceased ? TRUE : FALSE;
return array($name, $email, $doNotEmail, $onHold, $isDeceased);
}
return array(NULL, NULL, NULL, NULL, NULL);
}
/**
* Add/edit/register contacts through profile.
*
* @param array $params
* Array of profile fields to be edited/added.
* @param array $fields
* Array of fields from UFGroup.
* @param int $contactID
* Id of the contact to be edited/added.
* @param int $addToGroupID
* Specifies the default group to which contact is added.
* @param int $ufGroupId
* Uf group id (profile id).
* @param string $ctype
* @param bool $visibility
* Basically lets us know where this request is coming from.
* if via a profile from web, we restrict what groups are changed
*
* @return int
* contact id created/edited
*/
public static function createProfileContact(
&$params,
&$fields,
$contactID = NULL,
$addToGroupID = NULL,
$ufGroupId = NULL,
$ctype = NULL,
$visibility = FALSE
) {
// add ufGroupID to params array ( CRM-2012 )
if ($ufGroupId) {
$params['uf_group_id'] = $ufGroupId;
}
self::addBillingNameFieldsIfOtherwiseNotSet($params);
// If a user has logged in, or accessed via a checksum
// Then deliberately 'blanking' a value in the profile should remove it from their record
$session = CRM_Core_Session::singleton();
$params['updateBlankLocInfo'] = TRUE;
if (($session->get('authSrc') & (CRM_Core_Permission::AUTH_SRC_CHECKSUM + CRM_Core_Permission::AUTH_SRC_LOGIN)) == 0) {
$params['updateBlankLocInfo'] = FALSE;
}
if ($contactID) {
$editHook = TRUE;
CRM_Utils_Hook::pre('edit', 'Profile', $contactID, $params);
}
else {
$editHook = FALSE;
CRM_Utils_Hook::pre('create', 'Profile', NULL, $params);
}
list($data, $contactDetails) = self::formatProfileContactParams($params, $fields, $contactID, $ufGroupId, $ctype);
// manage is_opt_out
if (array_key_exists('is_opt_out', $fields) && array_key_exists('is_opt_out', $params)) {
$wasOptOut = CRM_Utils_Array::value('is_opt_out', $contactDetails, FALSE);
$isOptOut = CRM_Utils_Array::value('is_opt_out', $params, FALSE);
$data['is_opt_out'] = $isOptOut;
// on change, create new civicrm_subscription_history entry
if (($wasOptOut != $isOptOut) && !empty($contactDetails['contact_id'])) {
$shParams = array(
'contact_id' => $contactDetails['contact_id'],
'status' => $isOptOut ? 'Removed' : 'Added',
'method' => 'Web',
);
CRM_Contact_BAO_SubscriptionHistory::create($shParams);
}
}
$contact = self::create($data);
// contact is null if the profile does not have any contact fields
if ($contact) {
$contactID = $contact->id;
}
if (empty($contactID)) {
CRM_Core_Error::fatal('Cannot proceed without a valid contact id');
}
// Process group and tag
if (!empty($fields['group'])) {
$method = 'Admin';
// this for sure means we are coming in via profile since i added it to fix
// removing contacts from user groups -- lobo
if ($visibility) {
$method = 'Web';
}
CRM_Contact_BAO_GroupContact::create($params['group'], $contactID, $visibility, $method);
}
if (!empty($fields['tag'])) {
CRM_Core_BAO_EntityTag::create($params['tag'], 'civicrm_contact', $contactID);
}
//to add profile in default group
if (is_array($addToGroupID)) {
$contactIds = array($contactID);
foreach ($addToGroupID as $groupId) {
CRM_Contact_BAO_GroupContact::addContactsToGroup($contactIds, $groupId);
}
}
elseif ($addToGroupID) {
$contactIds = array($contactID);
CRM_Contact_BAO_GroupContact::addContactsToGroup($contactIds, $addToGroupID);
}
CRM_Contact_BAO_GroupContactCache::opportunisticCacheFlush();
if ($editHook) {
CRM_Utils_Hook::post('edit', 'Profile', $contactID, $params);
}
else {
CRM_Utils_Hook::post('create', 'Profile', $contactID, $params);
}
return $contactID;
}
/**
* Format profile contact parameters.
*
* @param array $params
* @param $fields
* @param int $contactID
* @param int $ufGroupId
* @param null $ctype
* @param bool $skipCustom
*
* @return array
*/
public static function formatProfileContactParams(
&$params,
&$fields,
$contactID = NULL,
$ufGroupId = NULL,
$ctype = NULL,
$skipCustom = FALSE
) {
$data = $contactDetails = array();
// get the contact details (hier)
if ($contactID) {
list($details, $options) = self::getHierContactDetails($contactID, $fields);
$contactDetails = $details[$contactID];
$data['contact_type'] = CRM_Utils_Array::value('contact_type', $contactDetails);
$data['contact_sub_type'] = CRM_Utils_Array::value('contact_sub_type', $contactDetails);
}
else {
//we should get contact type only if contact
if ($ufGroupId) {
$data['contact_type'] = CRM_Core_BAO_UFField::getProfileType($ufGroupId);
//special case to handle profile with only contact fields
if ($data['contact_type'] == 'Contact') {
$data['contact_type'] = 'Individual';
}
elseif (CRM_Contact_BAO_ContactType::isaSubType($data['contact_type'])) {
$data['contact_type'] = CRM_Contact_BAO_ContactType::getBasicType($data['contact_type']);
}
}
elseif ($ctype) {
$data['contact_type'] = $ctype;
}
else {
$data['contact_type'] = 'Individual';
}
}
//fix contact sub type CRM-5125
if (array_key_exists('contact_sub_type', $params) &&
!empty($params['contact_sub_type'])
) {
$data['contact_sub_type'] = CRM_Utils_Array::implodePadded($params['contact_sub_type']);
}
elseif (array_key_exists('contact_sub_type_hidden', $params) &&
!empty($params['contact_sub_type_hidden'])
) {
// if profile was used, and had any subtype, we obtain it from there
//CRM-13596 - add to existing contact types, rather than overwriting
$data_contact_sub_type_arr = CRM_Utils_Array::explodePadded($data['contact_sub_type']);
if (!in_array($params['contact_sub_type_hidden'], $data_contact_sub_type_arr)) {
//CRM-20517 - make sure contact_sub_type gets the correct delimiters
$data['contact_sub_type'] = trim($data['contact_sub_type'], CRM_Core_DAO::VALUE_SEPARATOR);
$data['contact_sub_type'] = CRM_Core_DAO::VALUE_SEPARATOR . $data['contact_sub_type'] . CRM_Utils_Array::implodePadded($params['contact_sub_type_hidden']);
}
}
if ($ctype == 'Organization') {
$data['organization_name'] = CRM_Utils_Array::value('organization_name', $contactDetails);
}
elseif ($ctype == 'Household') {
$data['household_name'] = CRM_Utils_Array::value('household_name', $contactDetails);
}
$locationType = array();
$count = 1;
if ($contactID) {
//add contact id
$data['contact_id'] = $contactID;
$primaryLocationType = self::getPrimaryLocationType($contactID);
}
else {
$defaultLocation = CRM_Core_BAO_LocationType::getDefault();
$defaultLocationId = $defaultLocation->id;
}
$billingLocationTypeId = CRM_Core_BAO_LocationType::getBilling();
$blocks = array('email', 'phone', 'im', 'openid');
$multiplFields = array('url');
// prevent overwritten of formatted array, reset all block from
// params if it is not in valid format (since import pass valid format)
foreach ($blocks as $blk) {
if (array_key_exists($blk, $params) &&
!is_array($params[$blk])
) {
unset($params[$blk]);
}
}
$primaryPhoneLoc = NULL;
$session = CRM_Core_Session::singleton();
foreach ($params as $key => $value) {
list($fieldName, $locTypeId, $typeId) = CRM_Utils_System::explode('-', $key, 3);
if ($locTypeId == 'Primary') {
if ($contactID) {
if (in_array($fieldName, $blocks)) {
$locTypeId = self::getPrimaryLocationType($contactID, FALSE, $fieldName);
}
else {
$locTypeId = self::getPrimaryLocationType($contactID, FALSE, 'address');
}
$primaryLocationType = $locTypeId;
}
else {
$locTypeId = $defaultLocationId;
}
}
if (is_numeric($locTypeId) &&
!in_array($fieldName, $multiplFields) &&
substr($fieldName, 0, 7) != 'custom_'
) {
$index = $locTypeId;
if (is_numeric($typeId)) {
$index .= '-' . $typeId;
}
if (!in_array($index, $locationType)) {
$locationType[$count] = $index;
$count++;
}
$loc = CRM_Utils_Array::key($index, $locationType);
$blockName = in_array($fieldName, $blocks) ? $fieldName : 'address';
$data[$blockName][$loc]['location_type_id'] = $locTypeId;
//set is_billing true, for location type "Billing"
if ($locTypeId == $billingLocationTypeId) {
$data[$blockName][$loc]['is_billing'] = 1;
}
if ($contactID) {
//get the primary location type
if ($locTypeId == $primaryLocationType) {
$data[$blockName][$loc]['is_primary'] = 1;
}
}
elseif ($locTypeId == $defaultLocationId) {
$data[$blockName][$loc]['is_primary'] = 1;
}
if (in_array($fieldName, array('phone'))) {
if ($typeId) {
$data['phone'][$loc]['phone_type_id'] = $typeId;
}
else {
$data['phone'][$loc]['phone_type_id'] = '';
}
$data['phone'][$loc]['phone'] = $value;
//special case to handle primary phone with different phone types
// in this case we make first phone type as primary
if (isset($data['phone'][$loc]['is_primary']) && !$primaryPhoneLoc) {
$primaryPhoneLoc = $loc;
}
if ($loc != $primaryPhoneLoc) {
unset($data['phone'][$loc]['is_primary']);
}
}
elseif ($fieldName == 'phone_ext') {
$data['phone'][$loc]['phone_ext'] = $value;
}
elseif ($fieldName == 'email') {
$data['email'][$loc]['email'] = $value;
if (empty($contactID)) {
$data['email'][$loc]['is_primary'] = 1;
}
}
elseif ($fieldName == 'im') {
if (isset($params[$key . '-provider_id'])) {
$data['im'][$loc]['provider_id'] = $params[$key . '-provider_id'];
}
if (strpos($key, '-provider_id') !== FALSE) {
$data['im'][$loc]['provider_id'] = $params[$key];
}
else {
$data['im'][$loc]['name'] = $value;
}
}
elseif ($fieldName == 'openid') {
$data['openid'][$loc]['openid'] = $value;
}
else {
if ($fieldName === 'state_province') {
// CRM-3393
if (is_numeric($value) && ((int ) $value) >= 1000) {
$data['address'][$loc]['state_province_id'] = $value;
}
elseif (empty($value)) {
$data['address'][$loc]['state_province_id'] = '';
}
else {
$data['address'][$loc]['state_province'] = $value;
}
}
elseif ($fieldName === 'country') {
// CRM-3393
if (is_numeric($value) && ((int ) $value) >= 1000
) {
$data['address'][$loc]['country_id'] = $value;
}
elseif (empty($value)) {
$data['address'][$loc]['country_id'] = '';
}
else {
$data['address'][$loc]['country'] = $value;
}
}
elseif ($fieldName === 'county') {
$data['address'][$loc]['county_id'] = $value;
}
elseif ($fieldName == 'address_name') {
$data['address'][$loc]['name'] = $value;
}
elseif (substr($fieldName, 0, 14) === 'address_custom') {
$data['address'][$loc][substr($fieldName, 8)] = $value;
}
else {
$data['address'][$loc][$fieldName] = $value;
}
}
}
else {
if (substr($key, 0, 4) === 'url-') {
$websiteField = explode('-', $key);
$data['website'][$websiteField[1]]['website_type_id'] = $websiteField[1];
$data['website'][$websiteField[1]]['url'] = $value;
}
elseif (in_array($key, self::$_greetingTypes, TRUE)) {
//save email/postal greeting and addressee values if any, CRM-4575
$data[$key . '_id'] = $value;
}
elseif (!$skipCustom && ($customFieldId = CRM_Core_BAO_CustomField::getKeyID($key))) {
// for autocomplete transfer hidden value instead of label
if ($params[$key] && isset($params[$key . '_id'])) {
$value = $params[$key . '_id'];
}
// we need to append time with date
if ($params[$key] && isset($params[$key . '_time'])) {
$value .= ' ' . $params[$key . '_time'];
}
// if auth source is not checksum / login && $value is blank, do not proceed - CRM-10128
if (($session->get('authSrc') & (CRM_Core_Permission::AUTH_SRC_CHECKSUM + CRM_Core_Permission::AUTH_SRC_LOGIN)) == 0 &&
($value == '' || !isset($value))
) {
continue;
}
$valueId = NULL;
if (!empty($params['customRecordValues'])) {
if (is_array($params['customRecordValues']) && !empty($params['customRecordValues'])) {
foreach ($params['customRecordValues'] as $recId => $customFields) {
if (is_array($customFields) && !empty($customFields)) {
foreach ($customFields as $customFieldName) {
if ($customFieldName == $key) {
$valueId = $recId;
break;
}
}
}
}
}
}
//CRM-13596 - check for contact_sub_type_hidden first
if (array_key_exists('contact_sub_type_hidden', $params)) {
$type = $params['contact_sub_type_hidden'];
}
else {
$type = $data['contact_type'];
if (!empty($data['contact_sub_type'])) {
$type = CRM_Utils_Array::explodePadded($data['contact_sub_type']);
}
}
CRM_Core_BAO_CustomField::formatCustomField($customFieldId,
$data['custom'],
$value,
$type,
$valueId,
$contactID,
FALSE,
FALSE
);
}
elseif ($key == 'edit') {
continue;
}
else {
if ($key == 'location') {
foreach ($value as $locationTypeId => $field) {
foreach ($field as $block => $val) {
if ($block == 'address' && array_key_exists('address_name', $val)) {
$value[$locationTypeId][$block]['name'] = $value[$locationTypeId][$block]['address_name'];
}
}
}
}
if ($key == 'phone' && isset($params['phone_ext'])) {
$data[$key] = $value;
foreach ($value as $cnt => $phoneBlock) {
if ($params[$key][$cnt]['location_type_id'] == $params['phone_ext'][$cnt]['location_type_id']) {
$data[$key][$cnt]['phone_ext'] = CRM_Utils_Array::retrieveValueRecursive($params['phone_ext'][$cnt], 'phone_ext');
}
}
}
elseif (in_array($key,
array(
'nick_name',
'job_title',
'middle_name',
'birth_date',
'gender_id',
'current_employer',
'prefix_id',
'suffix_id',
)) &&
($value == '' || !isset($value)) &&
($session->get('authSrc') & (CRM_Core_Permission::AUTH_SRC_CHECKSUM + CRM_Core_Permission::AUTH_SRC_LOGIN)) == 0 ||
($key == 'current_employer' && empty($params['current_employer']))) {
// CRM-10128: if auth source is not checksum / login && $value is blank, do not fill $data with empty value
// to avoid update with empty values
continue;
}
else {
$data[$key] = $value;
}
}
}
}
if (!isset($data['contact_type'])) {
$data['contact_type'] = 'Individual';
}
//set the values for checkboxes (do_not_email, do_not_mail, do_not_trade, do_not_phone)
$privacy = CRM_Core_SelectValues::privacy();
foreach ($privacy as $key => $value) {
if (array_key_exists($key, $fields)) {
// do not reset values for existing contacts, if fields are added to a profile
if (array_key_exists($key, $params)) {
$data[$key] = $params[$key];
if (empty($params[$key])) {
$data[$key] = 0;
}
}
elseif (!$contactID) {
$data[$key] = 0;
}
}
}
return array($data, $contactDetails);
}
/**
* Find the get contact details.
*
* This function does not respect ACLs for now, which might need to be rectified at some
* stage based on how its used.
*
* @param string $mail
* Primary email address of the contact.
* @param string $ctype
* Contact type.
*
* @return object|null
* $dao contact details
*/
public static function matchContactOnEmail($mail, $ctype = NULL) {
$strtolower = function_exists('mb_strtolower') ? 'mb_strtolower' : 'strtolower';
$mail = $strtolower(trim($mail));
$query = "
SELECT civicrm_contact.id as contact_id,
civicrm_contact.hash as hash,
civicrm_contact.contact_type as contact_type,
civicrm_contact.contact_sub_type as contact_sub_type
FROM civicrm_contact
INNER JOIN civicrm_email ON ( civicrm_contact.id = civicrm_email.contact_id )";
if (Civi::settings()->get('uniq_email_per_site')) {
// try to find a match within a site (multisite).
$groups = CRM_Core_BAO_Domain::getChildGroupIds();
if (!empty($groups)) {
$query .= "
INNER JOIN civicrm_group_contact gc ON
(civicrm_contact.id = gc.contact_id AND gc.status = 'Added' AND gc.group_id IN (" . implode(',', $groups) . "))";
}
}
$query .= "
WHERE civicrm_email.email = %1 AND civicrm_contact.is_deleted=0";
$p = array(1 => array($mail, 'String'));
if ($ctype) {
$query .= " AND civicrm_contact.contact_type = %3";
$p[3] = array($ctype, 'String');
}
$query .= " ORDER BY civicrm_email.is_primary DESC";
$dao = CRM_Core_DAO::executeQuery($query, $p);
if ($dao->fetch()) {
return $dao;
}
return NULL;
}
/**
* Find the contact details associated with an OpenID.
*
* @param string $openId
* OpenId of the contact.
* @param string $ctype
* Contact type.
*
* @return object|null
* $dao contact details
*/
public static function matchContactOnOpenId($openId, $ctype = NULL) {
$strtolower = function_exists('mb_strtolower') ? 'mb_strtolower' : 'strtolower';
$openId = $strtolower(trim($openId));
$query = "
SELECT civicrm_contact.id as contact_id,
civicrm_contact.hash as hash,
civicrm_contact.contact_type as contact_type,
civicrm_contact.contact_sub_type as contact_sub_type
FROM civicrm_contact
INNER JOIN civicrm_openid ON ( civicrm_contact.id = civicrm_openid.contact_id )
WHERE civicrm_openid.openid = %1";
$p = array(1 => array($openId, 'String'));
if ($ctype) {
$query .= " AND civicrm_contact.contact_type = %3";
$p[3] = array($ctype, 'String');
}
$query .= " ORDER BY civicrm_openid.is_primary DESC";
$dao = CRM_Core_DAO::executeQuery($query, $p);
if ($dao->fetch()) {
return $dao;
}
return NULL;
}
/**
* Get primary email of the contact.
*
* @param int $contactID
* Contact id.
*
* @return string
* Email address if present else null
*/
public static function getPrimaryEmail($contactID) {
// fetch the primary email
$query = "
SELECT civicrm_email.email as email
FROM civicrm_contact
LEFT JOIN civicrm_email ON ( civicrm_contact.id = civicrm_email.contact_id )
WHERE civicrm_email.is_primary = 1
AND civicrm_contact.id = %1";
$p = array(1 => array($contactID, 'Integer'));
$dao = CRM_Core_DAO::executeQuery($query, $p);
$email = NULL;
if ($dao->fetch()) {
$email = $dao->email;
}
$dao->free();
return $email;
}
/**
* Function to get primary OpenID of the contact.
*
* @param int $contactID
* Contact id.
*
* @return string
* >openid OpenID if present else null
*/
public static function getPrimaryOpenId($contactID) {
// fetch the primary OpenID
$query = "
SELECT civicrm_openid.openid as openid
FROM civicrm_contact
LEFT JOIN civicrm_openid ON ( civicrm_contact.id = civicrm_openid.contact_id )
WHERE civicrm_contact.id = %1
AND civicrm_openid.is_primary = 1";
$p = array(1 => array($contactID, 'Integer'));
$dao = CRM_Core_DAO::executeQuery($query, $p);
$openId = NULL;
if ($dao->fetch()) {
$openId = $dao->openid;
}
$dao->free();
return $openId;
}
/**
* Fetch the object and store the values in the values array.
*
* @param array $params
* Input parameters to find object.
* @param array $values
* Output values of the object.
*
* @return CRM_Contact_BAO_Contact|null
* The found object or null
*/
public static function getValues(&$params, &$values) {
$contact = new CRM_Contact_BAO_Contact();
$contact->copyValues($params);
if ($contact->find(TRUE)) {
CRM_Core_DAO::storeValues($contact, $values);
$privacy = array();
foreach (self::$_commPrefs as $name) {
if (isset($contact->$name)) {
$privacy[$name] = $contact->$name;
}
}
if (!empty($privacy)) {
$values['privacy'] = $privacy;
}
// communication Prefferance
$preffComm = $comm = array();
$comm = explode(CRM_Core_DAO::VALUE_SEPARATOR,
$contact->preferred_communication_method
);
foreach ($comm as $value) {
$preffComm[$value] = 1;
}
$temp = array('preferred_communication_method' => $contact->preferred_communication_method);
$names = array(
'preferred_communication_method' => array(
'newName' => 'preferred_communication_method_display',
'groupName' => 'preferred_communication_method',
),
);
// @todo This can be figured out from metadata & we can avoid the uncached query.
CRM_Core_OptionGroup::lookupValues($temp, $names, FALSE);
$values['preferred_communication_method'] = $preffComm;
$values['preferred_communication_method_display'] = CRM_Utils_Array::value('preferred_communication_method_display', $temp);
if ($contact->preferred_mail_format) {
$preferredMailingFormat = CRM_Core_SelectValues::pmf();
$values['preferred_mail_format'] = $preferredMailingFormat[$contact->preferred_mail_format];
}
// get preferred languages
if (!empty($contact->preferred_language)) {
$values['preferred_language'] = CRM_Core_PseudoConstant::getLabel('CRM_Contact_DAO_Contact', 'preferred_language', $contact->preferred_language);
}
// Calculating Year difference
if ($contact->birth_date) {
$birthDate = CRM_Utils_Date::customFormat($contact->birth_date, '%Y%m%d');
if ($birthDate < date('Ymd')) {
$age = CRM_Utils_Date::calculateAge($birthDate);
$values['age']['y'] = CRM_Utils_Array::value('years', $age);
$values['age']['m'] = CRM_Utils_Array::value('months', $age);
}
}
$contact->contact_id = $contact->id;
return $contact;
}
return NULL;
}
/**
* Given the component name and returns the count of participation of contact.
*
* @param string $component
* Input component name.
* @param int $contactId
* Input contact id.
* @param string $tableName
* Optional tableName if component is custom group.
*
* @return int
* total number in database
*/
public static function getCountComponent($component, $contactId, $tableName = NULL) {
$object = NULL;
switch ($component) {
case 'tag':
return CRM_Core_BAO_EntityTag::getContactTags($contactId, TRUE);
case 'rel':
$result = CRM_Contact_BAO_Relationship::getRelationship($contactId,
CRM_Contact_BAO_Relationship::CURRENT,
0, 1, 0,
NULL, NULL,
TRUE
);
return $result;
case 'group':
return CRM_Contact_BAO_GroupContact::getContactGroup($contactId, "Added", NULL, TRUE);
case 'log':
if (CRM_Core_BAO_Log::useLoggingReport()) {
return FALSE;
}
return CRM_Core_BAO_Log::getContactLogCount($contactId);
case 'note':
return CRM_Core_BAO_Note::getContactNoteCount($contactId);
case 'contribution':
return CRM_Contribute_BAO_Contribution::contributionCount($contactId);
case 'membership':
return CRM_Member_BAO_Membership::getContactMembershipCount($contactId, TRUE);
case 'participant':
return CRM_Event_BAO_Participant::getContactParticipantCount($contactId);
case 'pledge':
return CRM_Pledge_BAO_Pledge::getContactPledgeCount($contactId);
case 'case':
return CRM_Case_BAO_Case::caseCount($contactId);
case 'grant':
return CRM_Grant_BAO_Grant::getContactGrantCount($contactId);
case 'activity':
$input = array(
'contact_id' => $contactId,
'admin' => FALSE,
'caseId' => NULL,
'context' => 'activity',
);
return CRM_Activity_BAO_Activity::deprecatedGetActivitiesCount($input);
case 'mailing':
$params = array('contact_id' => $contactId);
return CRM_Mailing_BAO_Mailing::getContactMailingsCount($params);
default:
$custom = explode('_', $component);
if ($custom['0'] = 'custom') {
if (!$tableName) {
$tableName = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_CustomGroup', $custom['1'], 'table_name');
}
$queryString = "SELECT count(id) FROM {$tableName} WHERE entity_id = {$contactId}";
return CRM_Core_DAO::singleValueQuery($queryString);
}
}
}
/**
* Process greetings and cache.
*
* @param object $contact
* Contact object after save.
* @param bool $useDefaults
* Use default greeting values.
*/
public static function processGreetings(&$contact, $useDefaults = FALSE) {
if ($useDefaults) {
//retrieve default greetings
$defaultGreetings = CRM_Core_PseudoConstant::greetingDefaults();
$contactDefaults = $defaultGreetings[$contact->contact_type];
}
// The contact object has not always required the
// fields that are required to calculate greetings
// so we need to retrieve it again.
if ($contact->_query !== FALSE) {
$contact->find(TRUE);
}
// store object values to an array
$contactDetails = array();
CRM_Core_DAO::storeValues($contact, $contactDetails);
$contactDetails = array(array($contact->id => $contactDetails));
$emailGreetingString = $postalGreetingString = $addresseeString = NULL;
$updateQueryString = array();
//cache email and postal greeting to greeting display
if ($contact->email_greeting_custom != 'null' && $contact->email_greeting_custom) {
$emailGreetingString = $contact->email_greeting_custom;
}
elseif ($contact->email_greeting_id != 'null' && $contact->email_greeting_id) {
// the filter value for Individual contact type is set to 1
$filter = array(
'contact_type' => $contact->contact_type,
'greeting_type' => 'email_greeting',
);
$emailGreeting = CRM_Core_PseudoConstant::greeting($filter);
$emailGreetingString = $emailGreeting[$contact->email_greeting_id];
$updateQueryString[] = " email_greeting_custom = NULL ";
}
else {
if ($useDefaults) {
reset($contactDefaults['email_greeting']);
$emailGreetingID = key($contactDefaults['email_greeting']);
$emailGreetingString = $contactDefaults['email_greeting'][$emailGreetingID];
$updateQueryString[] = " email_greeting_id = $emailGreetingID ";
$updateQueryString[] = " email_greeting_custom = NULL ";
}
elseif ($contact->email_greeting_custom) {
$updateQueryString[] = " email_greeting_display = NULL ";
}
}
if ($emailGreetingString) {
CRM_Contact_BAO_Contact_Utils::processGreetingTemplate($emailGreetingString,
$contactDetails,
$contact->id,
'CRM_Contact_BAO_Contact'
);
$emailGreetingString = CRM_Core_DAO::escapeString(CRM_Utils_String::stripSpaces($emailGreetingString));
$updateQueryString[] = " email_greeting_display = '{$emailGreetingString}'";
}
//postal greetings
if ($contact->postal_greeting_custom != 'null' && $contact->postal_greeting_custom) {
$postalGreetingString = $contact->postal_greeting_custom;
}
elseif ($contact->postal_greeting_id != 'null' && $contact->postal_greeting_id) {
$filter = array(
'contact_type' => $contact->contact_type,
'greeting_type' => 'postal_greeting',
);
$postalGreeting = CRM_Core_PseudoConstant::greeting($filter);
$postalGreetingString = $postalGreeting[$contact->postal_greeting_id];
$updateQueryString[] = " postal_greeting_custom = NULL ";
}
else {
if ($useDefaults) {
reset($contactDefaults['postal_greeting']);
$postalGreetingID = key($contactDefaults['postal_greeting']);
$postalGreetingString = $contactDefaults['postal_greeting'][$postalGreetingID];
$updateQueryString[] = " postal_greeting_id = $postalGreetingID ";
$updateQueryString[] = " postal_greeting_custom = NULL ";
}
elseif ($contact->postal_greeting_custom) {
$updateQueryString[] = " postal_greeting_display = NULL ";
}
}
if ($postalGreetingString) {
CRM_Contact_BAO_Contact_Utils::processGreetingTemplate($postalGreetingString,
$contactDetails,
$contact->id,
'CRM_Contact_BAO_Contact'
);
$postalGreetingString = CRM_Core_DAO::escapeString(CRM_Utils_String::stripSpaces($postalGreetingString));
$updateQueryString[] = " postal_greeting_display = '{$postalGreetingString}'";
}
// addressee
if ($contact->addressee_custom != 'null' && $contact->addressee_custom) {
$addresseeString = $contact->addressee_custom;
}
elseif ($contact->addressee_id != 'null' && $contact->addressee_id) {
$filter = array(
'contact_type' => $contact->contact_type,
'greeting_type' => 'addressee',
);
$addressee = CRM_Core_PseudoConstant::greeting($filter);
$addresseeString = $addressee[$contact->addressee_id];
$updateQueryString[] = " addressee_custom = NULL ";
}
else {
if ($useDefaults) {
reset($contactDefaults['addressee']);
$addresseeID = key($contactDefaults['addressee']);
$addresseeString = $contactDefaults['addressee'][$addresseeID];
$updateQueryString[] = " addressee_id = $addresseeID ";
$updateQueryString[] = " addressee_custom = NULL ";
}
elseif ($contact->addressee_custom) {
$updateQueryString[] = " addressee_display = NULL ";
}
}
if ($addresseeString) {
CRM_Contact_BAO_Contact_Utils::processGreetingTemplate($addresseeString,
$contactDetails,
$contact->id,
'CRM_Contact_BAO_Contact'
);
$addresseeString = CRM_Core_DAO::escapeString(CRM_Utils_String::stripSpaces($addresseeString));
$updateQueryString[] = " addressee_display = '{$addresseeString}'";
}
if (!empty($updateQueryString)) {
$updateQueryString = implode(',', $updateQueryString);
$queryString = "UPDATE civicrm_contact SET {$updateQueryString} WHERE id = {$contact->id}";
CRM_Core_DAO::executeQuery($queryString);
}
}
/**
* Retrieve loc block ids w/ given condition.
*
* @param int $contactId
* Contact id.
* @param array $criteria
* Key => value pair which should be.
* fulfill by return record ids.
* @param string $condOperator
* Operator use for grouping multiple conditions.
*
* @return array
* loc block ids which fulfill condition.
*/
public static function getLocBlockIds($contactId, $criteria = array(), $condOperator = 'AND') {
$locBlockIds = array();
if (!$contactId) {
return $locBlockIds;
}
foreach (array('Email', 'OpenID', 'Phone', 'Address', 'IM') as $block) {
$name = strtolower($block);
$className = "CRM_Core_DAO_$block";
$blockDAO = new $className();
// build the condition.
if (is_array($criteria)) {
$fields = $blockDAO->fields();
$conditions = array();
foreach ($criteria as $field => $value) {
if (array_key_exists($field, $fields)) {
$cond = "( $field = $value )";
// value might be zero or null.
if (!$value || strtolower($value) == 'null') {
$cond = "( $field = 0 OR $field IS NULL )";
}
$conditions[] = $cond;
}
}
if (!empty($conditions)) {
$blockDAO->whereAdd(implode(" $condOperator ", $conditions));
}
}
$blockDAO->contact_id = $contactId;
$blockDAO->find();
while ($blockDAO->fetch()) {
$locBlockIds[$name][] = $blockDAO->id;
}
$blockDAO->free();
}
return $locBlockIds;
}
/**
* Build context menu items.
*
* @param int $contactId
*
* @return array
* Array of context menu for logged in user.
*/
public static function contextMenu($contactId = NULL) {
$menu = array(
'view' => array(
'title' => ts('View Contact'),
'weight' => 0,
'ref' => 'view-contact',
'class' => 'no-popup',
'key' => 'view',
'permissions' => array('view all contacts'),
),
'add' => array(
'title' => ts('Edit Contact'),
'weight' => 0,
'ref' => 'edit-contact',
'class' => 'no-popup',
'key' => 'add',
'permissions' => array('edit all contacts'),
),
'delete' => array(
'title' => ts('Delete Contact'),
'weight' => 0,
'ref' => 'delete-contact',
'key' => 'delete',
'permissions' => array('access deleted contacts', 'delete contacts'),
),
'contribution' => array(
'title' => ts('Add Contribution'),
'weight' => 5,
'ref' => 'new-contribution',
'key' => 'contribution',
'tab' => 'contribute',
'component' => 'CiviContribute',
'href' => CRM_Utils_System::url('civicrm/contact/view/contribution',
'reset=1&action=add&context=contribution'
),
'permissions' => array(
'access CiviContribute',
'edit contributions',
),
),
'participant' => array(
'title' => ts('Register for Event'),
'weight' => 10,
'ref' => 'new-participant',
'key' => 'participant',
'tab' => 'participant',
'component' => 'CiviEvent',
'href' => CRM_Utils_System::url('civicrm/contact/view/participant', 'reset=1&action=add&context=participant'),
'permissions' => array(
'access CiviEvent',
'edit event participants',
),
),
'activity' => array(
'title' => ts('Record Activity'),
'weight' => 35,
'ref' => 'new-activity',
'key' => 'activity',
'permissions' => array('edit all contacts'),
),
'pledge' => array(
'title' => ts('Add Pledge'),
'weight' => 15,
'ref' => 'new-pledge',
'key' => 'pledge',
'tab' => 'pledge',
'href' => CRM_Utils_System::url('civicrm/contact/view/pledge',
'reset=1&action=add&context=pledge'
),
'component' => 'CiviPledge',
'permissions' => array(
'access CiviPledge',
'edit pledges',
),
),
'membership' => array(
'title' => ts('Add Membership'),
'weight' => 20,
'ref' => 'new-membership',
'key' => 'membership',
'tab' => 'member',
'component' => 'CiviMember',
'href' => CRM_Utils_System::url('civicrm/contact/view/membership',
'reset=1&action=add&context=membership'
),
'permissions' => array(
'access CiviMember',
'edit memberships',
),
),
'case' => array(
'title' => ts('Add Case'),
'weight' => 25,
'ref' => 'new-case',
'key' => 'case',
'tab' => 'case',
'component' => 'CiviCase',
'href' => CRM_Utils_System::url('civicrm/case/add', 'reset=1&action=add&context=case'),
'permissions' => array('add cases'),
),
'grant' => array(
'title' => ts('Add Grant'),
'weight' => 26,
'ref' => 'new-grant',
'key' => 'grant',
'tab' => 'grant',
'component' => 'CiviGrant',
'href' => CRM_Utils_System::url('civicrm/contact/view/grant',
'reset=1&action=add&context=grant'
),
'permissions' => array('edit grants'),
),
'rel' => array(
'title' => ts('Add Relationship'),
'weight' => 30,
'ref' => 'new-relationship',
'key' => 'rel',
'tab' => 'rel',
'href' => CRM_Utils_System::url('civicrm/contact/view/rel',
'reset=1&action=add'
),
'permissions' => array('edit all contacts'),
),
'note' => array(
'title' => ts('Add Note'),
'weight' => 40,
'ref' => 'new-note',
'key' => 'note',
'tab' => 'note',
'class' => 'medium-popup',
'href' => CRM_Utils_System::url('civicrm/contact/view/note',
'reset=1&action=add'
),
'permissions' => array('edit all contacts'),
),
'email' => array(
'title' => ts('Send an Email'),
'weight' => 45,
'ref' => 'new-email',
'key' => 'email',
'permissions' => array('view all contacts'),
),
'group' => array(
'title' => ts('Add to Group'),
'weight' => 50,
'ref' => 'group-add-contact',
'key' => 'group',
'tab' => 'group',
'permissions' => array('edit groups'),
),
'tag' => array(
'title' => ts('Tag Contact'),
'weight' => 55,
'ref' => 'tag-contact',
'key' => 'tag',
'tab' => 'tag',
'permissions' => array('edit all contacts'),
),
);
$menu['otherActions'] = array(
'print' => array(
'title' => ts('Print Summary'),
'description' => ts('Printer-friendly view of this page.'),
'weight' => 5,
'ref' => 'crm-contact-print',
'key' => 'print',
'tab' => 'print',
'href' => CRM_Utils_System::url('civicrm/contact/view/print',
"reset=1&print=1"
),
'class' => 'print',
'icon' => 'crm-i fa-print',
),
'vcard' => array(
'title' => ts('vCard'),
'description' => ts('vCard record for this contact.'),
'weight' => 10,
'ref' => 'crm-contact-vcard',
'key' => 'vcard',
'tab' => 'vcard',
'href' => CRM_Utils_System::url('civicrm/contact/view/vcard',
"reset=1"
),
'class' => 'vcard',
'icon' => 'crm-i fa-list-alt',
),
);
if (CRM_Core_Permission::check('access Contact Dashboard')) {
$menu['otherActions']['dashboard'] = array(
'title' => ts('Contact Dashboard'),
'description' => ts('Contact Dashboard'),
'weight' => 15,
'ref' => 'crm-contact-dashboard',
'key' => 'dashboard',
'tab' => 'dashboard',
'class' => 'dashboard',
// NOTE: As an alternative you can also build url on CMS specific way
// as CRM_Core_Config::singleton()->userSystem->getUserRecordUrl($contactId)
'href' => CRM_Utils_System::url('civicrm/user', "reset=1&id={$contactId}"),
'icon' => 'crm-i fa-tachometer',
);
}
$uid = CRM_Core_BAO_UFMatch::getUFId($contactId);
if ($uid) {
$menu['otherActions']['user-record'] = array(
'title' => ts('User Record'),
'description' => ts('User Record'),
'weight' => 20,
'ref' => 'crm-contact-user-record',
'key' => 'user-record',
'tab' => 'user-record',
'class' => 'user-record',
'href' => CRM_Core_Config::singleton()->userSystem->getUserRecordUrl($contactId),
'icon' => 'crm-i fa-user',
);
}
elseif (CRM_Core_Config::singleton()->userSystem->checkPermissionAddUser()) {
$menu['otherActions']['user-add'] = array(
'title' => ts('Create User Record'),
'description' => ts('Create User Record'),
'weight' => 25,
'ref' => 'crm-contact-user-add',
'key' => 'user-add',
'tab' => 'user-add',
'class' => 'user-add',
'href' => CRM_Utils_System::url('civicrm/contact/view/useradd', 'reset=1&action=add&cid=' . $contactId),
'icon' => 'crm-i fa-user-plus',
);
}
CRM_Utils_Hook::summaryActions($menu, $contactId);
//1. check for component is active.
//2. check for user permissions.
//3. check for acls.
//3. edit and view contact are directly accessible to user.
$aclPermissionedTasks = array(
'view-contact',
'edit-contact',
'new-activity',
'new-email',
'group-add-contact',
'tag-contact',
'delete-contact',
);
$corePermission = CRM_Core_Permission::getPermission();
$contextMenu = array();
foreach ($menu as $key => $values) {
if ($key != 'otherActions') {
// user does not have necessary permissions.
if (!self::checkUserMenuPermissions($aclPermissionedTasks, $corePermission, $values)) {
continue;
}
// build directly accessible action menu.
if (in_array($values['ref'], array(
'view-contact',
'edit-contact',
))) {
$contextMenu['primaryActions'][$key] = array(
'title' => $values['title'],
'ref' => $values['ref'],
'class' => CRM_Utils_Array::value('class', $values),
'key' => $values['key'],
);
continue;
}
// finally get menu item for -more- action widget.
$contextMenu['moreActions'][$values['weight']] = array(
'title' => $values['title'],
'ref' => $values['ref'],
'href' => CRM_Utils_Array::value('href', $values),
'tab' => CRM_Utils_Array::value('tab', $values),
'class' => CRM_Utils_Array::value('class', $values),
'key' => $values['key'],
);
}
else {
foreach ($values as $value) {
// user does not have necessary permissions.
if (!self::checkUserMenuPermissions($aclPermissionedTasks, $corePermission, $value)) {
continue;
}
// finally get menu item for -more- action widget.
$contextMenu['otherActions'][$value['weight']] = array(
'title' => $value['title'],
'ref' => $value['ref'],
'href' => CRM_Utils_Array::value('href', $value),
'tab' => CRM_Utils_Array::value('tab', $value),
'class' => CRM_Utils_Array::value('class', $value),
'icon' => CRM_Utils_Array::value('icon', $value),
'key' => $value['key'],
);
}
}
}
ksort($contextMenu['moreActions']);
ksort($contextMenu['otherActions']);
return $contextMenu;
}
/**
* Check if user has permissions to access items in action menu.
*
* @param array $aclPermissionedTasks
* Array containing ACL related tasks.
* @param string $corePermission
* The permission of the user (edit or view or null).
* @param array $menuOptions
* Array containing params of the menu (title, href, etc).
*
* @return bool
* TRUE if user has all permissions, FALSE if otherwise.
*/
public static function checkUserMenuPermissions($aclPermissionedTasks, $corePermission, $menuOptions) {
$componentName = CRM_Utils_Array::value('component', $menuOptions);
// if component action - make sure component is enable.
if ($componentName && !in_array($componentName, CRM_Core_Config::singleton()->enableComponents)) {
return FALSE;
}
// make sure user has all required permissions.
$hasAllPermissions = FALSE;
$permissions = CRM_Utils_Array::value('permissions', $menuOptions);
if (!is_array($permissions) || empty($permissions)) {
$hasAllPermissions = TRUE;
}
// iterate for required permissions in given permissions array.
if (!$hasAllPermissions) {
$hasPermissions = 0;
foreach ($permissions as $permission) {
if (CRM_Core_Permission::check($permission)) {
$hasPermissions++;
}
}
if (count($permissions) == $hasPermissions) {
$hasAllPermissions = TRUE;
}
// if still user does not have required permissions, check acl.
if (!$hasAllPermissions && $menuOptions['ref'] != 'delete-contact') {
if (in_array($menuOptions['ref'], $aclPermissionedTasks) &&
$corePermission == CRM_Core_Permission::EDIT
) {
$hasAllPermissions = TRUE;
}
elseif (in_array($menuOptions['ref'], array(
'new-email',
))) {
// grant permissions for these tasks.
$hasAllPermissions = TRUE;
}
}
}
return $hasAllPermissions;
}
/**
* Retrieve display name of contact that address is shared.
*
* This is based on $masterAddressId or $contactId .
*
* @param int $masterAddressId
* Master id.
* @param int $contactId
* Contact id.
*
* @return string|null
* the found display name or null.
*/
public static function getMasterDisplayName($masterAddressId = NULL, $contactId = NULL) {
$masterDisplayName = NULL;
$sql = NULL;
if (!$masterAddressId && !$contactId) {
return $masterDisplayName;
}
if ($masterAddressId) {
$sql = "
SELECT display_name from civicrm_contact
LEFT JOIN civicrm_address ON ( civicrm_address.contact_id = civicrm_contact.id )
WHERE civicrm_address.id = " . $masterAddressId;
}
elseif ($contactId) {
$sql = "
SELECT display_name from civicrm_contact cc, civicrm_address add1
LEFT JOIN civicrm_address add2 ON ( add1.master_id = add2.id )
WHERE cc.id = add2.contact_id AND add1.contact_id = " . $contactId;
}
$masterDisplayName = CRM_Core_DAO::singleValueQuery($sql);
return $masterDisplayName;
}
/**
* Get the creation/modification times for a contact.
*
* @param int $contactId
*
* @return array
* Dates - ('created_date' => $, 'modified_date' => $)
*/
public static function getTimestamps($contactId) {
$timestamps = CRM_Core_DAO::executeQuery(
'SELECT created_date, modified_date
FROM civicrm_contact
WHERE id = %1',
array(
1 => array($contactId, 'Integer'),
)
);
if ($timestamps->fetch()) {
return array(
'created_date' => $timestamps->created_date,
'modified_date' => $timestamps->modified_date,
);
}
else {
return NULL;
}
}
/**
* Get a list of triggers for the contact table.
*
* @see hook_civicrm_triggerInfo
* @see CRM_Core_DAO::triggerRebuild
* @see http://issues.civicrm.org/jira/browse/CRM-10554
*
* @param $info
* @param null $tableName
*/
public static function triggerInfo(&$info, $tableName = NULL) {
//during upgrade, first check for valid version and then create triggers
//i.e the columns created_date and modified_date are introduced in 4.3.alpha1 so dont create triggers for older version
if (CRM_Core_Config::isUpgradeMode()) {
$currentVer = CRM_Core_BAO_Domain::version(TRUE);
//if current version is less than 4.3.alpha1 dont create below triggers
if (version_compare($currentVer, '4.3.alpha1') < 0) {
return;
}
}
// Modifications to these records should update the contact timestamps.
\Civi\Core\SqlTrigger\TimestampTriggers::create('civicrm_contact', 'Contact')
->setRelations(array(
array('table' => 'civicrm_address', 'column' => 'contact_id'),
array('table' => 'civicrm_email', 'column' => 'contact_id'),
array('table' => 'civicrm_im', 'column' => 'contact_id'),
array('table' => 'civicrm_phone', 'column' => 'contact_id'),
array('table' => 'civicrm_website', 'column' => 'contact_id'),
)
)
->alterTriggerInfo($info, $tableName);
// Update phone table to populate phone_numeric field
if (!$tableName || $tableName == 'civicrm_phone') {
// Define stored sql function needed for phones
$sqlTriggers = Civi::service('sql_triggers');
$sqlTriggers->enqueueQuery(self::DROP_STRIP_FUNCTION_43);
$sqlTriggers->enqueueQuery(self::CREATE_STRIP_FUNCTION_43);
$info[] = array(
'table' => array('civicrm_phone'),
'when' => 'BEFORE',
'event' => array('INSERT', 'UPDATE'),
'sql' => "\nSET NEW.phone_numeric = civicrm_strip_non_numeric(NEW.phone);\n",
);
}
}
/**
* Check if contact is being used in civicrm_domain based on $contactId.
*
* @param int $contactId
* Contact id.
*
* @return bool
* true if present else false.
*/
public static function checkDomainContact($contactId) {
if (!$contactId) {
return FALSE;
}
$domainId = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_Domain', $contactId, 'id', 'contact_id');
if ($domainId) {
return TRUE;
}
else {
return FALSE;
}
}
/**
* Get options for a given contact field.
*
* @see CRM_Core_DAO::buildOptions
*
* TODO: Should we always assume chainselect? What fn should be responsible for controlling that flow?
* TODO: In context of chainselect, what to return if e.g. a country has no states?
*
* @param string $fieldName
* @param string $context
* @see CRM_Core_DAO::buildOptionsContext
* @param array $props
* whatever is known about this dao object.
*
* @return array|bool
*/
public static function buildOptions($fieldName, $context = NULL, $props = array()) {
$params = array();
// Special logic for fields whose options depend on context or properties
switch ($fieldName) {
case 'contact_sub_type':
if (!empty($props['contact_type'])) {
$params['condition'] = "parent_id = (SELECT id FROM civicrm_contact_type WHERE name='{$props['contact_type']}')";
}
break;
case 'contact_type':
if ($context == 'search') {
// CRM-15495 - EntityRef filters and basic search forms expect this format
// FIXME: Search builder does not
return CRM_Contact_BAO_ContactType::getSelectElements();
}
break;
// The contact api supports some related entities so we'll honor that by fetching their options
case 'group_id':
case 'group':
return CRM_Contact_BAO_GroupContact::buildOptions('group_id', $context, $props);
case 'tag_id':
case 'tag':
$props['entity_table'] = 'civicrm_contact';
return CRM_Core_BAO_EntityTag::buildOptions('tag_id', $context, $props);
case 'state_province_id':
case 'state_province':
case 'state_province_name':
case 'country_id':
case 'country':
case 'county_id':
case 'worldregion':
case 'worldregion_id':
return CRM_Core_BAO_Address::buildOptions($fieldName, 'get', $props);
}
return CRM_Core_PseudoConstant::get(__CLASS__, $fieldName, $params, $context);
}
/**
* Delete a contact-related object that has an 'is_primary' field.
*
* Ensures that is_primary gets assigned to another object if available
* Also calls pre/post hooks
*
* @param string $type
* @param int $id
* @return bool
*/
public static function deleteObjectWithPrimary($type, $id) {
if (!$id || !is_numeric($id)) {
return FALSE;
}
$daoName = "CRM_Core_DAO_$type";
$obj = new $daoName();
$obj->id = $id;
$obj->find();
if ($obj->fetch()) {
CRM_Utils_Hook::pre('delete', $type, $id, CRM_Core_DAO::$_nullArray);
$contactId = $obj->contact_id;
$obj->delete();
}
else {
return FALSE;
}
// is_primary is only relavent if this field belongs to a contact
if ($contactId) {
$dao = new $daoName();
$dao->contact_id = $contactId;
$dao->is_primary = 1;
// Pick another record to be primary (if one isn't already)
if (!$dao->find(TRUE)) {
$dao->is_primary = 0;
$dao->find();
if ($dao->fetch()) {
$dao->is_primary = 1;
$dao->save();
}
}
$dao->free();
}
CRM_Utils_Hook::post('delete', $type, $id, $obj);
$obj->free();
return TRUE;
}
/**
* @inheritDoc
*/
public function addSelectWhereClause() {
// We always return an array with these keys, even if they are empty,
// because this tells the query builder that we have considered these fields for acls
$clauses = array(
'id' => (array) CRM_Contact_BAO_Contact_Permission::cacheSubquery(),
'is_deleted' => CRM_Core_Permission::check('access deleted contacts') ? array() : array('!= 1'),
);
CRM_Utils_Hook::selectWhereClause($this, $clauses);
return $clauses;
}
/**
* Get any existing duplicate contacts based on the input parameters.
*
* @param array $input
* Input parameters to be matched.
* @param string $contactType
* @param string $rule
* - Supervised
* - Unsupervised
* @param $excludedContactIDs
* An array of ids not to be included in the results.
* @param bool $checkPermissions
* @param int $ruleGroupID
* ID of the rule group to be used if an override is desirable.
*
* @return array
*/
public static function getDuplicateContacts($input, $contactType, $rule = 'Unsupervised', $excludedContactIDs = array(), $checkPermissions = TRUE, $ruleGroupID = NULL) {
$dedupeParams = CRM_Dedupe_Finder::formatParams($input, $contactType);
$dedupeParams['check_permission'] = $checkPermissions;
$ids = CRM_Dedupe_Finder::dupesByParams($dedupeParams, $contactType, $rule, $excludedContactIDs, $ruleGroupID);
return $ids;
}
/**
* Get the first duplicate contacts based on the input parameters.
*
* @param array $input
* Input parameters to be matched.
* @param string $contactType
* @param string $rule
* - Supervised
* - Unsupervised
* @param $excludedContactIDs
* An array of ids not to be included in the results.
* @param bool $checkPermissions
* @param int $ruleGroupID
* ID of the rule group to be used if an override is desirable.
*
* @return int|NULL
*/
public static function getFirstDuplicateContact($input, $contactType, $rule = 'Unsupervised', $excludedContactIDs = array(), $checkPermissions = TRUE, $ruleGroupID = NULL) {
$ids = self::getDuplicateContacts($input, $contactType, $rule, $excludedContactIDs, $checkPermissions, $ruleGroupID);
if (empty($ids)) {
return NULL;
}
return $ids[0];
}
/**
* Check if a field is associated with an entity that has a location type.
*
* (ie. is an address, phone, email etc field).
*
* @param string $fieldTitle
* Title of the field (not the name - create a new function for that if required).
*
* @return bool
*/
public static function isFieldHasLocationType($fieldTitle) {
foreach (CRM_Contact_BAO_Contact::importableFields() as $key => $field) {
if ($field['title'] === $fieldTitle) {
return CRM_Utils_Array::value('hasLocationType', $field);
}
}
return FALSE;
}
}