3 +--------------------------------------------------------------------+
4 | Copyright CiviCRM LLC. All rights reserved. |
6 | This work is published under the GNU AGPLv3 license with some |
7 | permitted exceptions and without any warranty. For full license |
8 | and copyright information, see https://civicrm.org/licensing |
9 +--------------------------------------------------------------------+
15 * @copyright CiviCRM LLC https://civicrm.org/licensing
21 class CRM_Core_BAO_UFGroup
extends CRM_Core_DAO_UFGroup
{
23 const PUBLIC_VISIBILITY
= 1,
25 LISTINGS_VISIBILITY
= 4;
28 * Cache the match clause used in this transaction.
32 public static $_matchFields = NULL;
35 * Fetch object based on array of properties.
37 * @param array $params
38 * (reference) an assoc array of name/value pairs.
39 * @param array $defaults
40 * (reference) an assoc array to hold the flattened values.
43 * CRM_Core_DAO_UFGroup object
45 public static function retrieve(&$params, &$defaults) {
46 return CRM_Core_DAO
::commonRetrieve('CRM_Core_DAO_UFGroup', $params, $defaults);
50 * Retrieve the first non-generic contact type
58 public static function getContactType($id) {
60 $validTypes = array_filter(array_keys(CRM_Core_SelectValues
::contactType()));
61 $validSubTypes = CRM_Contact_BAO_ContactType
::subTypeInfo();
63 $typesParts = explode(CRM_Core_DAO
::VALUE_SEPARATOR
, CRM_Core_DAO
::getFieldValue('CRM_Core_DAO_UFGroup', $id, 'group_type'));
64 $types = explode(',', $typesParts[0]);
67 foreach ($types as $type) {
68 if (in_array($type, $validTypes)) {
71 elseif (array_key_exists($type, $validSubTypes)) {
72 $cType = $validSubTypes[$type]['parent'] ??
NULL;
92 public static function getTitle($id) {
93 return CRM_Core_DAO
::getFieldValue('CRM_Core_DAO_UFGroup', $id, 'title');
97 * Update the is_active flag in the db.
100 * Id of the database record.
101 * @param bool $is_active
102 * Value we want to set the is_active field.
105 * true if we found and updated the object, else false
107 public static function setIsActive($id, $is_active) {
108 return CRM_Core_DAO
::setFieldValue('CRM_Core_DAO_UFGroup', $id, 'is_active', $is_active);
112 * Get all the registration fields.
115 * What action are we doing.
119 * @param string $ctype
122 * the fields that are needed for registration
126 public static function getRegistrationFields($action, $mode, $ctype = NULL) {
127 if ($mode & CRM_Profile_Form
::MODE_REGISTER
) {
128 $ufGroups = CRM_Core_BAO_UFGroup
::getModuleUFGroup('User Registration');
131 $ufGroups = CRM_Core_BAO_UFGroup
::getModuleUFGroup('Profile');
134 if (!is_array($ufGroups)) {
140 foreach ($ufGroups as $id => $title) {
142 $fieldType = CRM_Core_BAO_UFField
::getProfileType($id);
143 if (($fieldType != 'Contact') &&
144 ($fieldType != $ctype) &&
145 !CRM_Contact_BAO_ContactType
::isExtendsContactType($fieldType, $ctype)
149 if (CRM_Contact_BAO_ContactType
::isaSubType($fieldType)) {
150 $profileSubType = $fieldType;
154 $subset = self
::getFields($id, TRUE, $action,
155 NULL, NULL, FALSE, NULL, TRUE, $ctype
158 // we do not allow duplicates. the first field is the winner
159 foreach ($subset as $name => $field) {
160 if (empty($fields[$name])) {
161 $fields[$name] = $field;
170 * Get all the listing fields.
173 * What action are we doing.
174 * @param int $visibility
175 * Visibility of fields we are interested in.
176 * @param bool $considerSelector
177 * Whether to consider the in_selector parameter.
178 * @param array $ufGroupIds
179 * @param bool $searchable
181 * @param null $restrict
182 * @param bool $skipPermission
183 * @param int $permissionType
186 * the fields that are listings related
190 public static function getListingFields(
193 $considerSelector = FALSE,
197 $skipPermission = FALSE,
198 $permissionType = CRM_Core_Permission
::SEARCH
201 $subset = self
::getFields($ufGroupIds, FALSE, $action,
202 $visibility, $searchable,
208 if ($considerSelector) {
209 // drop the fields not meant for the selector
210 foreach ($subset as $name => $field) {
211 if (!$field['in_selector']) {
212 unset($subset[$name]);
219 $ufGroups = CRM_Core_PseudoConstant
::get('CRM_Core_DAO_UFField', 'uf_group_id');
222 foreach ($ufGroups as $id => $title) {
223 $subset = self
::getFields($id, FALSE, $action,
224 $visibility, $searchable,
230 if ($considerSelector) {
231 // drop the fields not meant for the selector
232 foreach ($subset as $name => $field) {
233 if (!$field['in_selector']) {
234 unset($subset[$name]);
238 $fields = array_merge($fields, $subset);
245 * Get all the fields that belong to the group with the name title,
246 * and format for use with buildProfile. This is the SQL analog of
250 * The id of the UF group or ids of ufgroup.
251 * @param bool|int $register are we interested in registration fields
253 * What action are we doing.
254 * @param int $visibility
255 * Visibility of fields we are interested in.
257 * @param bool $showAll
258 * @param string $restrict
259 * Should we restrict based on a specified profile type.
260 * @param bool $skipPermission
262 * @param int $permissionType
263 * @param string $orderBy
264 * @param null $orderProfiles
266 * @param bool $eventProfile
269 * The fields that belong to this ufgroup(s)
271 * @throws \CRM_Core_Exception
273 public static function getFields(
281 $skipPermission = FALSE,
283 $permissionType = CRM_Core_Permission
::CREATE
,
284 $orderBy = 'field_name',
285 $orderProfiles = NULL,
286 $eventProfile = FALSE
288 if (!is_array($id)) {
289 $id = CRM_Utils_Type
::escape($id, 'Positive');
296 $gids = implode(',', $profileIds);
299 $query = "SELECT g.* from civicrm_uf_group g
300 LEFT JOIN civicrm_uf_join j ON (j.uf_group_id = g.id)
301 WHERE g.id IN ( {$gids} )
302 AND ((j.uf_group_id IN ( {$gids} ) AND j.module = %1) OR g.is_reserved = 1 )
304 $params = [1 => [$restrict, 'String']];
307 $query = "SELECT g.* from civicrm_uf_group g WHERE g.id IN ( {$gids} ) ";
311 $query .= " AND g.is_active = 1";
316 'administer CiviCRM',
317 'manage event profiles',
320 if ($eventProfile && CRM_Core_Permission
::check($checkPermission)) {
321 $skipPermission = TRUE;
324 // add permissioning for profiles only if not registration
325 if (!$skipPermission) {
326 $permissionClause = CRM_Core_Permission
::ufGroupClause($permissionType, 'g.');
327 $query .= " AND $permissionClause ";
330 if ($orderProfiles and count($profileIds) > 1) {
331 $query .= " ORDER BY FIELD( g.id, {$gids} )";
333 $group = CRM_Core_DAO
::executeQuery($query, $params);
337 while ($group->fetch()) {
339 $query = self
::createUFFieldQuery($group->id
, $searchable, $showAll, $visibility, $orderBy);
340 $field = CRM_Core_DAO
::executeQuery($query);
342 $importableFields = self
::getProfileFieldMetadata($showAll);
343 list($customFields, $addressCustomFields) = self
::getCustomFields($ctype);
345 while ($field->fetch()) {
346 list($name, $formattedField) = self
::formatUFField($group, $field, $customFields, $addressCustomFields, $importableFields, $permissionType);
347 if ($formattedField !== NULL) {
348 $fields[$name] = $formattedField;
353 if (empty($fields) && !$validGroup) {
354 throw new CRM_Core_Exception(ts('The requested Profile (gid=%1) is disabled OR it is not configured to be used for \'Profile\' listings in its Settings OR there is no Profile with that ID OR you do not have permission to access this profile. Please contact the site administrator if you need assistance.',
355 [1 => implode(',', $profileIds)]
359 self
::reformatProfileFields($fields);
366 * Format a list of UFFields for use with buildProfile. This is the in-memory analog
369 * @param array $groupArr
370 * (mimic CRM_UF_DAO_UFGroup).
371 * @param array $fieldArrs
372 * List of fields (each mimics CRM_UF_DAO_UFField).
373 * @param bool $visibility
374 * Visibility of fields we are interested in.
375 * @param bool $searchable
376 * @param bool $showAll
378 * @param int $permissionType
381 * @see self::getFields
383 public static function formatUFFields(
390 $permissionType = CRM_Core_Permission
::CREATE
392 // $group = new CRM_Core_DAO_UFGroup();
393 // $group->copyValues($groupArr); // no... converts string('') to string('null')
394 $group = (object) $groupArr;
396 // Refactoring note: The $fieldArrs here may be slightly different than the $ufFields
397 // used by calculateGroupType, but I don't think the missing fields matter, and -- if
398 // they did -- the obvious fix would produce mutual recursion.
399 $ufGroupType = self
::_calculateGroupType($fieldArrs);
400 $profileType = CRM_Core_BAO_UFField
::calculateProfileType(implode(',', $ufGroupType));
401 $contactActivityProfile = CRM_Core_BAO_UFField
::checkContactActivityProfileTypeByGroupType(implode(',', $ufGroupType));
402 $importableFields = self
::getImportableFields($showAll, $profileType, $contactActivityProfile);
403 list($customFields, $addressCustomFields) = self
::getCustomFields($ctype);
405 $formattedFields = [];
406 foreach ($fieldArrs as $fieldArr) {
407 $field = (object) $fieldArr;
408 if (!self
::filterUFField($field, $searchable, $showAll, $visibility)) {
412 list($name, $formattedField) = self
::formatUFField($group, $field, $customFields, $addressCustomFields, $importableFields, $permissionType);
413 if ($formattedField !== NULL) {
414 $formattedFields[$name] = $formattedField;
417 return $formattedFields;
421 * Prepare a field for rendering with CRM_Core_BAO_UFGroup::buildProfile.
423 * @param CRM_Core_DAO_UFGroup|CRM_Core_DAO $group
424 * @param CRM_Core_DAO_UFField|CRM_Core_DAO $field
425 * @param array $customFields
426 * @param array $addressCustomFields
427 * @param array $importableFields
428 * @param int $permissionType
429 * Eg CRM_Core_Permission::CREATE.
433 protected static function formatUFField(
437 $addressCustomFields,
439 $permissionType = CRM_Core_Permission
::CREATE
441 $name = $field->field_name
;
442 $title = $field->label
;
444 $addressCustom = FALSE;
445 if (in_array($permissionType, [CRM_Core_Permission
::CREATE
, CRM_Core_Permission
::EDIT
]) &&
446 in_array($field->field_name
, array_keys($addressCustomFields))
448 $addressCustom = TRUE;
449 $name = "address_{$name}";
451 if ($field->field_name
== 'url') {
452 $name .= "-{$field->website_type_id}";
454 elseif (!empty($field->location_type_id
)) {
455 $name .= "-{$field->location_type_id}";
458 $locationFields = self
::getLocationFields();
459 if (in_array($field->field_name
, $locationFields) ||
$addressCustom) {
464 if (isset($field->phone_type_id
)) {
465 $name .= "-{$field->phone_type_id}";
467 $fieldMetaData = CRM_Utils_Array
::value($name, $importableFields, ($importableFields[$field->field_name
] ??
[]));
469 // No lie: this is bizarre; why do we need to mix so many UFGroup properties into UFFields?
470 // I guess to make field self sufficient with all the required data and avoid additional calls
473 'groupTitle' => $group->title
,
474 'groupName' => $group->name
,
475 'groupDisplayTitle' => (!empty($group->frontend_title
)) ?
$group->frontend_title
: $group->title
,
476 'groupHelpPre' => empty($group->help_pre
) ?
'' : $group->help_pre
,
477 'groupHelpPost' => empty($group->help_post
) ?
'' : $group->help_post
,
479 'where' => CRM_Utils_Array
::value('where', CRM_Utils_Array
::value($field->field_name
, $importableFields)),
480 'attributes' => CRM_Core_DAO
::makeAttribute(CRM_Utils_Array
::value($field->field_name
, $importableFields)),
481 'is_required' => $field->is_required
,
482 'is_view' => $field->is_view
,
483 'help_pre' => $field->help_pre
,
484 'help_post' => $field->help_post
,
485 'visibility' => $field->visibility
,
486 'in_selector' => $field->in_selector
,
487 'rule' => CRM_Utils_Array
::value('rule', CRM_Utils_Array
::value($field->field_name
, $importableFields)),
488 'location_type_id' => $field->location_type_id ??
NULL,
489 'website_type_id' => $field->website_type_id ??
NULL,
490 'phone_type_id' => $field->phone_type_id ??
NULL,
491 'group_id' => $group->id
,
492 'add_to_group_id' => $group->add_to_group_id ??
NULL,
493 'add_captcha' => $group->add_captcha ??
NULL,
494 'field_type' => $field->field_type
,
495 'field_id' => $field->id
,
496 'pseudoconstant' => CRM_Utils_Array
::value(
498 CRM_Utils_Array
::value($field->field_name
, $importableFields)
500 // obsolete this when we remove the name / dbName discrepancy with gender/suffix/prefix
501 'dbName' => CRM_Utils_Array
::value(
503 CRM_Utils_Array
::value($field->field_name
, $importableFields)
506 'data_type' => CRM_Utils_Type
::getDataTypeFromFieldMetadata($fieldMetaData),
507 'bao' => $fieldMetaData['bao'] ??
NULL,
510 $formattedField = CRM_Utils_Date
::addDateMetadataToField($fieldMetaData, $formattedField);
512 //adding custom field property
513 if (substr($field->field_name
, 0, 6) == 'custom' ||
514 substr($field->field_name
, 0, 14) === 'address_custom'
516 // if field is not present in customFields, that means the user
517 // DOES NOT HAVE permission to access that field
518 if (array_key_exists($field->field_name
, $customFields)) {
519 $formattedField['serialize'] = !empty($customFields[$field->field_name
]['serialize']);
520 $formattedField['is_search_range'] = $customFields[$field->field_name
]['is_search_range'];
522 $formattedField['options_per_line'] = $customFields[$field->field_name
]['options_per_line'];
523 $formattedField['html_type'] = $customFields[$field->field_name
]['html_type'];
525 if (CRM_Utils_Array
::value('html_type', $formattedField) == 'Select Date') {
526 $formattedField['date_format'] = $customFields[$field->field_name
]['date_format'];
527 $formattedField['time_format'] = $customFields[$field->field_name
]['time_format'];
528 $formattedField['is_datetime_field'] = TRUE;
529 $formattedField['smarty_view_format'] = CRM_Utils_Date
::getDateFieldViewFormat($formattedField['date_format']);
532 $formattedField['is_multi_summary'] = $field->is_multi_summary
;
533 return [$name, $formattedField];
536 $formattedField = NULL;
537 return [$name, $formattedField];
540 return [$name, $formattedField];
544 * Create a query to find all visible UFFields in a UFGroup.
546 * This is the SQL-variant of checkUFFieldDisplayable().
548 * @param int $groupId
549 * @param bool $searchable
550 * @param bool $showAll
551 * @param int $visibility
552 * @param string $orderBy
553 * Comma-delimited list of SQL columns.
557 protected static function createUFFieldQuery($groupId, $searchable, $showAll, $visibility, $orderBy) {
558 $where = " WHERE uf_group_id = {$groupId}";
561 $where .= " AND is_searchable = 1";
565 $where .= " AND is_active = 1";
570 if ($visibility & self
::PUBLIC_VISIBILITY
) {
571 $clause[] = 'visibility = "Public Pages"';
573 if ($visibility & self
::ADMIN_VISIBILITY
) {
574 $clause[] = 'visibility = "User and User Admin Only"';
576 if ($visibility & self
::LISTINGS_VISIBILITY
) {
577 $clause[] = 'visibility = "Public Pages and Listings"';
579 if (!empty($clause)) {
580 $where .= ' AND ( ' . implode(' OR ', $clause) . ' ) ';
584 $query = "SELECT * FROM civicrm_uf_field $where ORDER BY weight";
586 $query .= ", " . $orderBy;
593 * Create a query to find all visible UFFields in a UFGroup.
595 * This is the PHP in-memory variant of createUFFieldQuery().
597 * @param CRM_Core_DAO_UFField|CRM_Core_DAO $field
598 * @param bool $searchable
599 * @param bool $showAll
600 * @param int $visibility
603 * TRUE if field is displayable
605 protected static function filterUFField($field, $searchable, $showAll, $visibility) {
606 if ($searchable && $field->is_searchable
!= 1) {
610 if (!$showAll && $field->is_active
!= 1) {
615 $allowedVisibilities = [];
616 if ($visibility & self
::PUBLIC_VISIBILITY
) {
617 $allowedVisibilities[] = 'Public Pages';
619 if ($visibility & self
::ADMIN_VISIBILITY
) {
620 $allowedVisibilities[] = 'User and User Admin Only';
622 if ($visibility & self
::LISTINGS_VISIBILITY
) {
623 $allowedVisibilities[] = 'Public Pages and Listings';
625 // !empty($allowedVisibilities) seems silly to me, but it is equivalent to the pre-existing SQL
626 if (!empty($allowedVisibilities) && !in_array($field->visibility
, $allowedVisibilities)) {
635 * Get a list of filtered field metadata.
638 * @param $profileType
639 * @param $contactActivityProfile
640 * @param bool $filterMode
641 * Filter mode means you are using importable fields for filtering rather than just getting metadata.
642 * With filter mode = FALSE BOTH activity fields and component fields are returned.
643 * I can't see why you would ever want to use this function in filter mode as the component fields are
644 * still unfiltered. However, I feel scared enough to leave it as it is. I have marked this function as
645 * deprecated and am recommending the wrapper 'getProfileFieldMetadata' in order to try to
646 * send this confusion to history.
649 * @deprecated use getProfileFieldMetadata
652 protected static function getImportableFields($showAll, $profileType, $contactActivityProfile, $filterMode = TRUE) {
654 $importableFields = CRM_Contact_BAO_Contact
::importableFields('All', FALSE, FALSE, FALSE, TRUE, TRUE);
657 $importableFields = CRM_Contact_BAO_Contact
::importableFields('All', FALSE, TRUE, FALSE, TRUE, TRUE);
660 $activityFields = CRM_Activity_BAO_Activity
::getProfileFields();
661 $componentFields = CRM_Core_Component
::getQueryFields();
662 if ($filterMode == TRUE) {
663 if ($profileType == 'Activity' ||
$contactActivityProfile) {
664 $importableFields = array_merge($importableFields, $activityFields);
667 $importableFields = array_merge($importableFields, $componentFields);
671 $importableFields = array_merge($importableFields, $activityFields, $componentFields);
674 $importableFields['group']['title'] = ts('Group(s)');
675 $importableFields['group']['where'] = NULL;
676 $importableFields['tag']['title'] = ts('Tag(s)');
677 $importableFields['tag']['where'] = NULL;
678 return $importableFields;
682 * Get the metadata for all potential profile fields.
684 * @param bool $isIncludeInactive
685 * Should disabled fields be included.
688 * Field metadata for all fields that might potentially be in a profile.
690 protected static function getProfileFieldMetadata($isIncludeInactive) {
691 return self
::getImportableFields($isIncludeInactive, NULL, NULL, NULL, TRUE);
695 * Get the fields relating to locations.
699 public static function getLocationFields() {
700 static $locationFields = [
702 'supplemental_address_1',
703 'supplemental_address_2',
704 'supplemental_address_3',
707 'postal_code_suffix',
720 return $locationFields;
728 protected static function getCustomFields($ctype) {
729 $cacheKey = 'uf_group_custom_fields_' . $ctype;
730 if (!Civi
::cache('metadata')->has($cacheKey)) {
731 $customFields = CRM_Core_BAO_CustomField
::getFieldsForImport($ctype, FALSE, FALSE, FALSE, TRUE, TRUE);
733 // hack to add custom data for components
734 $components = ['Contribution', 'Participant', 'Membership', 'Activity', 'Case'];
735 foreach ($components as $value) {
736 $customFields = array_merge($customFields, CRM_Core_BAO_CustomField
::getFieldsForImport($value));
738 $addressCustomFields = CRM_Core_BAO_CustomField
::getFieldsForImport('Address');
739 $customFields = array_merge($customFields, $addressCustomFields);
740 Civi
::cache('metadata')->set($cacheKey, [$customFields, $addressCustomFields]);
742 return Civi
::cache('metadata')->get($cacheKey);
746 * Check the data validity.
749 * The user id that we are actually editing.
750 * @param string $name
751 * The machine-name of the group we are interested in.
752 * @param bool $register
754 * The action of the form.
756 * @pram boolean $register is this the registrtion form
758 * true if form is valid
760 public static function isValid($userID, $name, $register = FALSE, $action = NULL) {
762 $controller = new CRM_Core_Controller_Simple('CRM_Profile_Form_Dynamic',
763 ts('Dynamic Form Creator'),
766 $controller->set('id', $userID);
767 $controller->set('register', 1);
768 $controller->process();
769 return $controller->validate();
772 // make sure we have a valid group
773 $group = new CRM_Core_DAO_UFGroup();
775 $group->name
= $name;
777 if ($group->find(TRUE) && $userID) {
778 $controller = new CRM_Core_Controller_Simple('CRM_Profile_Form_Dynamic', ts('Dynamic Form Creator'), $action);
779 $controller->set('gid', $group->id
);
780 $controller->set('id', $userID);
781 $controller->set('register', 0);
782 $controller->process();
783 return $controller->validate();
790 * Get the html for the form that represents this particular group.
793 * The user id that we are actually editing.
794 * @param string $title
795 * The title of the group we are interested in.
797 * The action of the form.
798 * @param bool $register
799 * Is this the registration form.
801 * Should we reset the form?.
802 * @param int $profileID
803 * Do we have the profile ID?.
805 * @param bool $doNotProcess
809 * the html for the form on success, otherwise empty string
811 public static function getEditHTML(
818 $doNotProcess = FALSE,
823 $controller = new CRM_Core_Controller_Simple('CRM_Profile_Form_Dynamic',
824 ts('Dynamic Form Creator'),
827 if ($reset ||
$doNotProcess) {
828 // hack to make sure we do not process this form
829 $oldQFDefault = CRM_Utils_Array
::value('_qf_default',
832 unset($_POST['_qf_default']);
833 unset($_REQUEST['_qf_default']);
835 $controller->reset();
839 $controller->set('id', $userID);
840 $controller->set('register', 1);
841 $controller->set('skipPermission', 1);
842 $controller->set('ctype', $ctype);
843 $controller->process();
844 if ($doNotProcess ||
!empty($_POST)) {
845 $controller->validate();
847 $controller->setEmbedded(TRUE);
849 //CRM-5839 - though we want to process form, get the control back.
850 $controller->setSkipRedirection(!$doNotProcess);
854 // we are done processing so restore the POST/REQUEST vars
855 if (($reset ||
$doNotProcess) && $oldQFDefault) {
856 $_POST['_qf_default'] = $_REQUEST['_qf_default'] = $oldQFDefault;
859 $template = CRM_Core_Smarty
::singleton();
861 // Hide CRM error messages if they are displayed using drupal form_set_error.
862 if (!empty($_POST)) {
863 $template->assign('suppressForm', TRUE);
866 return trim($template->fetch('CRM/Profile/Form/Dynamic.tpl'));
870 // make sure we have a valid group
871 $group = new CRM_Core_DAO_UFGroup();
873 $group->title
= $title;
875 if ($group->find(TRUE)) {
876 $profileID = $group->id
;
881 // make sure profileID and ctype match if ctype exists
883 $profileType = CRM_Core_BAO_UFField
::getProfileType($profileID);
884 if (CRM_Contact_BAO_ContactType
::isaSubType($profileType)) {
885 $profileType = CRM_Contact_BAO_ContactType
::getBasicType($profileType);
888 if (($profileType != 'Contact') && ($profileType != $ctype)) {
893 $controller = new CRM_Core_Controller_Simple('CRM_Profile_Form_Dynamic',
894 ts('Dynamic Form Creator'),
898 $controller->reset();
900 $controller->set('gid', $profileID);
901 $controller->set('id', $userID);
902 $controller->set('register', 0);
903 $controller->set('skipPermission', 1);
905 $controller->set('ctype', $ctype);
907 $controller->process();
908 $controller->setEmbedded(TRUE);
910 //CRM-5846 - give the control back to drupal.
911 $controller->setSkipRedirection(!$doNotProcess);
914 $template = CRM_Core_Smarty
::singleton();
916 // Hide CRM error messages if they are displayed using drupal form_set_error.
917 if (!empty($_POST) && CRM_Core_Config
::singleton()->userFramework
== 'Drupal') {
918 if (arg(0) == 'user' ||
(arg(0) == 'admin' && arg(1) == 'people')) {
919 $template->assign('suppressForm', TRUE);
923 $templateFile = "CRM/Profile/Form/{$profileID}/Dynamic.tpl";
924 if (!$template->template_exists($templateFile)) {
925 $templateFile = 'CRM/Profile/Form/Dynamic.tpl';
927 return trim($template->fetch($templateFile));
930 $userEmail = CRM_Contact_BAO_Contact_Location
::getEmailDetails($userID);
932 // if post not empty then only proceed
933 if (!empty($_POST)) {
935 $config = CRM_Core_Config
::singleton();
936 $email = $_POST['mail'] ??
NULL;
938 if (CRM_Utils_Rule
::email($email) && ($email != $userEmail[1])) {
939 CRM_Core_BAO_UFMatch
::updateContactEmail($userID, $email);
948 * Given a contact id and a field set, return the values from the db.
951 * @param array $fields
952 * The profile fields of interest.
953 * @param array $values
954 * The values for the above fields.
955 * @param bool $searchable
957 * @param array $componentWhere
958 * Component condition.
959 * @param bool $absolute
960 * Return urls in absolute form (useful when sending an email).
961 * @param null $additionalWhereClause
965 public static function getValues(
966 $cid, &$fields, &$values,
967 $searchable = TRUE, $componentWhere = NULL,
968 $absolute = FALSE, $additionalWhereClause = NULL
970 if (empty($cid) && empty($componentWhere)) {
974 // get the contact details (hier)
975 $returnProperties = CRM_Contact_BAO_Contact
::makeHierReturnProperties($fields);
976 $params = $cid ?
[['contact_id', '=', $cid, 0, 0]] : [];
978 // add conditions specified by components. eg partcipant_id etc
979 if (!empty($componentWhere)) {
980 $params = array_merge($params, $componentWhere);
983 $query = new CRM_Contact_BAO_Query($params, $returnProperties, $fields);
985 $details = $query->searchQuery(0, 0, NULL, FALSE, FALSE,
986 FALSE, FALSE, FALSE, $additionalWhereClause);
987 while ($details->fetch()) {
992 $query->convertToPseudoNames($details);
994 $locationTypes = CRM_Core_BAO_Address
::buildOptions('location_type_id', 'validate');
995 $imProviders = CRM_Core_DAO_IM
::buildOptions('provider_id');
996 $websiteTypes = CRM_Core_DAO_Website
::buildOptions('website_type_id');
998 $multipleFields = ['url'];
1000 //start of code to set the default values
1001 foreach ($fields as $name => $field) {
1003 if ($name == 'id') {
1004 $name = 'contact_id';
1007 // skip fields that should not be displayed separately
1008 if (!empty($field['skipDisplay'])) {
1012 // Create a unique, non-empty index for each field.
1013 $index = $field['title'];
1014 if ($index === '') {
1017 while (array_key_exists($index, $values)) {
1021 $params[$index] = $values[$index] = '';
1022 $customFieldName = NULL;
1024 if (isset($details->$name) ||
$name == 'group' ||
$name == 'tag') {
1025 // to handle gender / suffix / prefix
1026 if (in_array(substr($name, 0, -3), ['gender', 'prefix', 'suffix'])) {
1027 $params[$index] = $details->$name;
1028 $values[$index] = $details->$name;
1030 elseif (in_array($name, CRM_Contact_BAO_Contact
::$_greetingTypes)) {
1031 $dname = $name . '_display';
1032 $values[$index] = $details->$dname;
1033 $name = $name . '_id';
1034 $params[$index] = $details->$name;
1036 elseif (in_array($name, [
1041 $values[$index] = $details->$name;
1042 $idx = $name . '_id';
1043 $params[$index] = $details->$idx;
1045 elseif ($name === 'preferred_language') {
1046 $params[$index] = $details->$name;
1047 $values[$index] = CRM_Core_PseudoConstant
::getLabel('CRM_Contact_DAO_Contact', 'preferred_language', $details->$name);
1049 elseif ($name == 'group') {
1050 $groups = CRM_Contact_BAO_GroupContact
::getContactGroup($cid, 'Added', NULL, FALSE, TRUE);
1053 foreach ($groups as $g) {
1054 // CRM-8362: User and User Admin visibility groups should be included in display if user has
1055 // VIEW permission on that group
1056 $groupPerm = CRM_Contact_BAO_Group
::checkPermission($g['group_id'], TRUE);
1058 if ($g['visibility'] != 'User and User Admin Only' ||
1059 CRM_Utils_Array
::key(CRM_Core_Permission
::VIEW
, $groupPerm)
1061 $title[] = $g['title'];
1062 if ($g['visibility'] == 'Public Pages') {
1063 $ids[] = $g['group_id'];
1067 $values[$index] = implode(', ', $title);
1068 $params[$index] = implode(',', $ids);
1070 elseif ($name == 'tag') {
1071 $entityTags = CRM_Core_BAO_EntityTag
::getTag($cid);
1072 $allTags = CRM_Core_PseudoConstant
::get('CRM_Core_DAO_EntityTag', 'tag_id', ['onlyActive' => FALSE]);
1074 foreach ($entityTags as $tagId) {
1075 $title[] = $allTags[$tagId];
1077 $values[$index] = implode(', ', $title);
1078 $params[$index] = implode(',', $entityTags);
1080 elseif ($name == 'activity_status_id') {
1081 $activityStatus = CRM_Core_PseudoConstant
::activityStatus();
1082 $values[$index] = $activityStatus[$details->$name];
1083 $params[$index] = $details->$name;
1085 elseif ($name == 'activity_date_time') {
1086 $values[$index] = CRM_Utils_Date
::customFormat($details->$name);
1087 $params[$index] = $details->$name;
1089 elseif ($name == 'contact_sub_type') {
1090 $contactSubTypeNames = explode(CRM_Core_DAO
::VALUE_SEPARATOR
, $details->$name);
1091 if (!empty($contactSubTypeNames)) {
1092 $contactSubTypeLabels = [];
1093 // get all contact subtypes
1094 $allContactSubTypes = CRM_Contact_BAO_ContactType
::subTypeInfo();
1095 // build contact subtype labels array
1096 foreach ($contactSubTypeNames as $cstName) {
1098 $contactSubTypeLabels[] = $allContactSubTypes[$cstName]['label'];
1101 $values[$index] = implode(',', $contactSubTypeLabels);
1104 $params[$index] = $details->$name;
1107 if (substr($name, 0, 7) === 'do_not_' ||
substr($name, 0, 3) === 'is_') {
1108 if ($details->$name) {
1109 $values[$index] = '[ x ]';
1113 if ($cfID = CRM_Core_BAO_CustomField
::getKeyID($name)) {
1114 $htmlType = $field['html_type'];
1116 // field_type is only set when we are retrieving profile values
1117 // when sending email, we call the same function to get custom field
1118 // values etc, i.e. emulating a profile
1119 $fieldType = $field['field_type'] ??
NULL;
1121 if ($htmlType == 'File') {
1124 $fieldType == 'Activity' && !empty($componentWhere[0][2])
1126 $entityId = $componentWhere[0][2];
1129 $fileURL = CRM_Core_BAO_CustomField
::getFileURL($entityId,
1133 $additionalWhereClause
1135 $params[$index] = $values[$index] = $fileURL['file_url'];
1139 if (isset($dao) && property_exists($dao, 'data_type') &&
1140 ($dao->data_type
== 'Int' ||
1141 $dao->data_type
== 'Boolean'
1144 $customVal = (int ) ($details->{$name});
1146 elseif (isset($dao) && property_exists($dao, 'data_type')
1147 && $dao->data_type
== 'Float'
1149 $customVal = (float ) ($details->{$name});
1151 elseif (!CRM_Utils_System
::isNull(explode(CRM_Core_DAO
::VALUE_SEPARATOR
,
1155 $customVal = $details->{$name};
1159 if (CRM_Utils_System
::isNull($customVal)) {
1163 $params[$index] = $customVal;
1164 $values[$index] = CRM_Core_BAO_CustomField
::displayValue($customVal, $cfID);
1165 if ($field['data_type'] == 'ContactReference') {
1166 $params[$index] = $values[$index];
1168 if (CRM_Core_DAO
::getFieldValue('CRM_Core_DAO_CustomField',
1169 $cfID, 'is_search_range'
1172 $customFieldName = "{$name}_from";
1176 elseif ($name == 'image_URL') {
1177 list($width, $height) = getimagesize(CRM_Utils_String
::unstupifyUrl($details->$name));
1178 list($thumbWidth, $thumbHeight) = CRM_Contact_BAO_Contact
::getThumbSize($width, $height);
1180 $image_URL = '<img src="' . $details->$name . '" height= ' . $thumbHeight . ' width= ' . $thumbWidth . ' />';
1181 $values[$index] = "<a href='#' onclick='contactImagePopUp(\"{$details->$name}\", {$width}, {$height});'>{$image_URL}</a>";
1183 elseif (in_array($name, [
1187 // @todo this set should be determined from metadata, not hard-coded.
1188 $values[$index] = CRM_Utils_Date
::customFormat($details->$name);
1189 $params[$index] = CRM_Utils_Date
::isoToMysql($details->$name);
1193 if ($index == 'Campaign') {
1194 $dao = 'CRM_Campaign_DAO_Campaign';
1196 elseif ($index == 'Contribution Page') {
1197 $dao = 'CRM_Contribute_DAO_ContributionPage';
1200 $value = CRM_Core_DAO
::getFieldValue($dao, $details->$name, 'title');
1203 $value = $details->$name;
1205 $values[$index] = $value;
1210 elseif (strpos($name, '-') !== FALSE) {
1211 list($fieldName, $id, $type) = CRM_Utils_System
::explode('-', $name, 3);
1213 if (!in_array($fieldName, $multipleFields)) {
1214 if ($id == 'Primary') {
1216 // not sure why we'd every use Primary location type id
1217 // we need to fix the source if we are using it
1218 // $locationTypeName = CRM_Contact_BAO_Contact::getPrimaryLocationType( $cid );
1219 $locationTypeName = 1;
1222 $locationTypeName = $locationTypes[$id] ??
NULL;
1225 if (!$locationTypeName) {
1229 $detailName = "{$locationTypeName}-{$fieldName}";
1230 $detailName = str_replace(' ', '_', $detailName);
1232 if (in_array($fieldName, [
1239 $detailName .= "-{$type}";
1243 if (in_array($fieldName, [
1248 $values[$index] = $details->$detailName;
1249 $idx = $detailName . '_id';
1250 $params[$index] = $details->$idx;
1252 elseif ($fieldName == 'im') {
1253 $providerId = $detailName . '-provider_id';
1254 if (isset($imProviders[$details->$providerId])) {
1255 $values[$index] = $details->$detailName . " (" . $imProviders[$details->$providerId] . ")";
1258 $values[$index] = $details->$detailName;
1260 $params[$index] = $details->$detailName;
1262 elseif ($fieldName == 'phone') {
1263 $phoneExtField = str_replace('phone', 'phone_ext', $detailName);
1264 if (isset($details->$phoneExtField)) {
1265 $values[$index] = $details->$detailName . " (" . $details->$phoneExtField . ")";
1268 $values[$index] = $details->$detailName;
1270 $params[$index] = $details->$detailName;
1273 $values[$index] = $params[$index] = $details->$detailName;
1277 $detailName = "website-{$id}-{$fieldName}";
1278 $url = CRM_Utils_System
::fixURL($details->$detailName);
1279 if ($details->$detailName) {
1280 $websiteTypeId = "website-{$id}-website_type_id";
1281 $websiteType = $websiteTypes[$details->$websiteTypeId];
1282 $values[$index] = "<a href=\"$url\">{$details->$detailName} ( {$websiteType} )</a>";
1285 $values[$index] = '';
1290 if ((CRM_Utils_Array
::value('visibility', $field) == 'Public Pages and Listings') &&
1291 CRM_Core_Permission
::check('profile listings and forms')
1294 if (CRM_Utils_System
::isNull($params[$index])) {
1295 $params[$index] = $values[$index];
1297 if (!isset($params[$index])) {
1300 if (!$customFieldName) {
1301 $fieldName = $field['name'];
1304 $fieldName = $customFieldName;
1308 if (CRM_Core_BAO_CustomField
::getKeyID($field['name'])) {
1309 $htmlType = $field['html_type'];
1310 if ($htmlType == 'Link') {
1311 $url = $params[$index];
1313 elseif (!empty($field['serialize'])) {
1314 $valSeparator = CRM_Core_DAO
::VALUE_SEPARATOR
;
1315 $selectedOptions = explode($valSeparator, $params[$index]);
1317 foreach ($selectedOptions as $key => $multiOption) {
1319 $url[] = CRM_Utils_System
::url('civicrm/profile',
1320 'reset=1&force=1&gid=' . $field['group_id'] . '&' .
1321 urlencode($fieldName) .
1323 urlencode($multiOption)
1329 $url = CRM_Utils_System
::url('civicrm/profile',
1330 'reset=1&force=1&gid=' . $field['group_id'] . '&' .
1331 urlencode($fieldName) .
1333 urlencode($params[$index])
1338 $url = CRM_Utils_System
::url('civicrm/profile',
1339 'reset=1&force=1&gid=' . $field['group_id'] . '&' .
1340 urlencode($fieldName) .
1342 urlencode($params[$index])
1347 !empty($values[$index]) &&
1351 if (is_array($url) && !empty($url)) {
1353 $eachMultiValue = explode(', ', $values[$index]);
1354 foreach ($eachMultiValue as $key => $valueLabel) {
1355 $links[] = '<a href="' . $url[$key] . '">' . $valueLabel . '</a>';
1357 $values[$index] = implode(', ', $links);
1360 $values[$index] = '<a href="' . $url . '">' . $values[$index] . '</a>';
1368 * Check if profile Group used by any module.
1376 public static function usedByModule($id) {
1377 //check whether this group is used by any module(check uf join records)
1379 FROM civicrm_uf_join
1380 WHERE civicrm_uf_join.uf_group_id=$id";
1382 $dao = new CRM_Core_DAO();
1384 if ($dao->fetch()) {
1393 * Delete the profile Group.
1401 public static function del($id) {
1402 //check whether this group contains any profile fields
1403 $profileField = new CRM_Core_DAO_UFField();
1404 $profileField->uf_group_id
= $id;
1405 $profileField->find();
1406 while ($profileField->fetch()) {
1407 CRM_Core_BAO_UFField
::del($profileField->id
);
1410 //delete records from uf join table
1411 $ufJoin = new CRM_Core_DAO_UFJoin();
1412 $ufJoin->uf_group_id
= $id;
1415 //delete profile group
1416 $group = new CRM_Core_DAO_UFGroup();
1425 * @param array $params
1426 * Reference array contains the values submitted by the form.
1428 * Reference array contains the id.
1433 public static function add(&$params, $ids = []) {
1443 foreach ($fields as $field) {
1444 $params[$field] = CRM_Utils_Array
::value($field, $params, FALSE);
1447 $params['limit_listings_group_id'] = $params['group'] ??
NULL;
1448 $params['add_to_group_id'] = $params['add_contact_to_group'] ??
NULL;
1451 if (!empty($params['group_type']) && is_array($params['group_type'])) {
1452 $params['group_type'] = implode(',', $params['group_type']);
1454 $ufGroup = new CRM_Core_DAO_UFGroup();
1455 $ufGroup->copyValues($params);
1457 $ufGroupID = CRM_Utils_Array
::value('ufgroup', $ids, CRM_Utils_Array
::value('id', $params));
1458 if (!$ufGroupID && empty($params['name'])) {
1459 $ufGroup->name
= CRM_Utils_String
::munge($ufGroup->title
, '_', 56);
1461 $ufGroup->id
= $ufGroupID;
1465 if (!$ufGroupID && empty($params['name'])) {
1466 $ufGroup->name
= $ufGroup->name
. "_{$ufGroup->id}";
1474 * Make uf join entries for an uf group.
1476 * @param int $weight
1477 * @param array $groupTypes
1478 * An assoc array of name/value pairs.
1479 * @param int $ufGroupId
1482 public static function createUFJoin($weight, $groupTypes, $ufGroupId) {
1484 // get ufjoin records for uf group
1485 $ufGroupRecord = CRM_Core_BAO_UFGroup
::getUFJoinRecord($ufGroupId);
1487 // get the list of all ufgroup types
1488 $allUFGroupType = CRM_Core_SelectValues
::ufGroupTypes();
1490 // this fix is done to prevent warning generated by array_key_exits incase of empty array is given as input
1491 if (!is_array($groupTypes)) {
1495 // this fix is done to prevent warning generated by array_key_exits incase of empty array is given as input
1496 if (!is_array($ufGroupRecord)) {
1497 $ufGroupRecord = [];
1500 // check which values has to be inserted/deleted for contact
1501 $menuRebuild = FALSE;
1502 foreach ($allUFGroupType as $key => $value) {
1504 $joinParams['uf_group_id'] = $ufGroupId;
1505 $joinParams['module'] = $key;
1506 if ($key === 'User Account') {
1507 $menuRebuild = TRUE;
1509 if (array_key_exists($key, $groupTypes) && !in_array($key, $ufGroupRecord)) {
1510 // insert a new record
1511 CRM_Core_BAO_UFGroup
::addUFJoin($joinParams);
1513 elseif (!array_key_exists($key, $groupTypes) && in_array($key, $ufGroupRecord)) {
1514 // delete a record for existing ufgroup
1515 CRM_Core_BAO_UFGroup
::delUFJoin($joinParams);
1521 UPDATE civicrm_uf_join
1523 WHERE uf_group_id = %2
1524 AND ( entity_id IS NULL OR entity_id <= 0 )
1527 1 => [$weight, 'Integer'],
1528 2 => [$ufGroupId, 'Integer'],
1530 CRM_Core_DAO
::executeQuery($query, $p);
1532 // Do a menu rebuild, so it gets all the new menu entries for user account
1534 $config = CRM_Core_Config
::singleton();
1535 $config->userSystem
->updateCategories();
1540 * Get the UF Join records for an ufgroup id.
1542 * @param int $ufGroupId
1544 * @param int $displayName
1545 * If set return display name in array.
1546 * @param int $status
1547 * If set return module other than default modules (User Account/User registration/Profile).
1552 public static function getUFJoinRecord($ufGroupId = NULL, $displayName = NULL, $status = NULL) {
1555 $UFGroupType = CRM_Core_SelectValues
::ufGroupTypes();
1559 $dao = new CRM_Core_DAO_UFJoin();
1562 $dao->uf_group_id
= $ufGroupId;
1568 while ($dao->fetch()) {
1569 if (!$displayName) {
1570 $ufJoin[$dao->id
] = $dao->module
;
1573 if (isset($UFGroupType[$dao->module
])) {
1574 // skip the default modules
1576 $ufJoin[$dao->id
] = $UFGroupType[$dao->module
];
1578 // added for CRM-1475
1580 elseif (!CRM_Utils_Array
::key($dao->module
, $ufJoin)) {
1581 $ufJoin[$dao->id
] = $dao->module
;
1589 * Function takes an associative array and creates a ufjoin record for ufgroup.
1591 * @param array $params
1592 * (reference) an assoc array of name/value pairs.
1594 * @return CRM_Core_BAO_UFJoin
1596 public static function addUFJoin(&$params) {
1597 $ufJoin = new CRM_Core_DAO_UFJoin();
1598 $ufJoin->copyValues($params);
1604 * Delete the uf join record for an uf group.
1606 * @param array $params
1607 * (reference) an assoc array of name/value pairs.
1609 public static function delUFJoin(&$params) {
1610 $ufJoin = new CRM_Core_DAO_UFJoin();
1611 $ufJoin->copyValues($params);
1616 * Get the weight for ufjoin record.
1618 * @param int $ufGroupId
1619 * If $ufGroupId get update weight or add weight.
1622 * weight of the UFGroup
1624 public static function getWeight($ufGroupId = NULL) {
1625 //calculate the weight
1628 $queryString = "SELECT ( MAX(civicrm_uf_join.weight)+1) as new_weight
1629 FROM civicrm_uf_join
1630 WHERE module = 'User Registration' OR module = 'User Account' OR module = 'Profile'";
1633 $queryString = "SELECT MAX(civicrm_uf_join.weight) as new_weight
1634 FROM civicrm_uf_join
1635 WHERE civicrm_uf_join.uf_group_id = %1
1636 AND ( entity_id IS NULL OR entity_id <= 0 )";
1637 $p[1] = [$ufGroupId, 'Integer'];
1640 $dao = CRM_Core_DAO
::executeQuery($queryString, $p);
1642 return ($dao->new_weight
) ?
$dao->new_weight
: 1;
1646 * Get the uf group for a module.
1648 * @param string $moduleName
1651 * No to increment the weight.
1652 * @param bool $skipPermission
1654 * Which operation (view, edit, create, etc) to check permission for.
1655 * @param array|NULL $returnFields list of UFGroup fields to return; NULL for default
1658 * array of ufgroups for a module
1660 public static function getModuleUFGroup($moduleName = NULL, $count = 0, $skipPermission = TRUE, $op = CRM_Core_Permission
::VIEW
, $returnFields = NULL) {
1661 $selectFields = ['id', 'title', 'created_id', 'is_active', 'is_reserved', 'group_type', 'description'];
1663 if (CRM_Core_BAO_SchemaHandler
::checkIfFieldExists('civicrm_uf_group', 'frontend_title')) {
1664 $selectFields[] = 'frontend_title';
1667 if (!empty($returnFields)) {
1668 $selectFields = array_merge($returnFields, array_diff($selectFields, $returnFields));
1671 $queryString = 'SELECT civicrm_uf_group.' . implode(', civicrm_uf_group.', $selectFields) . '
1672 FROM civicrm_uf_group
1673 LEFT JOIN civicrm_uf_join ON (civicrm_uf_group.id = uf_group_id)';
1676 $queryString .= ' AND civicrm_uf_group.is_active = 1
1677 WHERE civicrm_uf_join.module = %2';
1678 $p[2] = [$moduleName, 'String'];
1681 // add permissioning for profiles only if not registration
1682 if (!$skipPermission) {
1683 $permissionClause = CRM_Core_Permission
::ufGroupClause($op, 'civicrm_uf_group.');
1684 if (strpos($queryString, 'WHERE') !== FALSE) {
1685 $queryString .= " AND $permissionClause ";
1688 $queryString .= " $permissionClause ";
1692 $queryString .= ' ORDER BY civicrm_uf_join.weight, civicrm_uf_group.title';
1693 $dao = CRM_Core_DAO
::executeQuery($queryString, $p);
1696 while ($dao->fetch()) {
1697 //skip mix profiles in user Registration / User Account
1698 if (($moduleName === 'User Registration' ||
$moduleName === 'User Account') &&
1699 CRM_Core_BAO_UFField
::checkProfileType($dao->id
)
1703 foreach ($selectFields as $key => $field) {
1704 if ($field === 'id') {
1707 $ufGroups[$dao->id
][$field] = $dao->$field;
1711 // Allow other modules to alter/override the UFGroups.
1712 CRM_Utils_Hook
::buildUFGroupsForModule($moduleName, $ufGroups);
1718 * Filter ufgroups based on logged in user contact type.
1720 * @param int $ufGroupId
1721 * Uf group id (profile id).
1722 * @param int $contactID
1727 public static function filterUFGroups($ufGroupId, $contactID = NULL) {
1729 $session = CRM_Core_Session
::singleton();
1730 $contactID = $session->get('userID');
1734 //get the contact type
1735 $contactType = CRM_Contact_BAO_Contact
::getContactType($contactID);
1737 //match if exixting contact type is same as profile contact type
1738 $profileType = CRM_Core_BAO_UFField
::getProfileType($ufGroupId);
1740 if (CRM_Contact_BAO_ContactType
::isaSubType($profileType)) {
1741 $profileType = CRM_Contact_BAO_ContactType
::getBasicType($profileType);
1743 //in some cases getBasicType() returns a cached array instead of string. Example: array ('sponsor' => 'organization')
1744 if (is_array($profileType)) {
1745 $profileType = array_shift($profileType);
1749 //allow special mix profiles for Contribution and Participant
1750 $specialProfiles = ['Contribution', 'Participant', 'Membership'];
1752 if (in_array($profileType, $specialProfiles)) {
1756 if (($contactType == $profileType) ||
$profileType == 'Contact') {
1765 * Add profile field to a form.
1767 * @param CRM_Core_Form $form
1768 * @param array $field
1772 * @param int $contactId
1773 * @param bool $online
1774 * @param string $usedFor
1775 * For building up prefixed fieldname for special cases (e.g. onBehalf, Honor).
1776 * @param int $rowNumber
1777 * @param string $prefix
1781 public static function buildProfile(
1791 $defaultValues = [];
1792 $fieldName = $field['name'];
1793 $title = $field['title'];
1794 $attributes = $field['attributes'];
1795 $rule = $field['rule'];
1796 $view = $field['is_view'];
1797 $required = ($mode == CRM_Profile_Form
::MODE_SEARCH
) ?
FALSE : $field['is_required'];
1798 $search = $mode == CRM_Profile_Form
::MODE_SEARCH
;
1799 $isShared = CRM_Utils_Array
::value('is_shared', $field, 0);
1801 // do not display view fields in drupal registration form
1803 if ($view && $mode == CRM_Profile_Form
::MODE_REGISTER
) {
1807 if ($usedFor == 'onbehalf') {
1808 $name = "onbehalf[$fieldName]";
1810 elseif ($usedFor == 'honor') {
1811 $name = "honor[$fieldName]";
1813 elseif ($contactId && !$online) {
1814 $name = "field[$contactId][$fieldName]";
1816 elseif ($rowNumber) {
1817 $name = "field[$rowNumber][$fieldName]";
1819 elseif (!empty($prefix)) {
1820 $name = $prefix . "[$fieldName]";
1826 $selectAttributes = ['class' => 'crm-select2', 'placeholder' => TRUE];
1828 if ($fieldName == 'image_URL' && $mode == CRM_Profile_Form
::MODE_EDIT
) {
1829 $deleteExtra = json_encode(ts('Are you sure you want to delete contact image.'));
1831 CRM_Core_Action
::DELETE
=> [
1832 'name' => ts('Delete Contact Image'),
1833 'url' => 'civicrm/contact/image',
1834 'qs' => 'reset=1&id=%%id%%&gid=%%gid%%&action=delete',
1835 'extra' => 'onclick = "' . htmlspecialchars("if (confirm($deleteExtra)) this.href+='&confirmed=1'; else return false;") . '"',
1838 $deleteURL = CRM_Core_Action
::formLink($deleteURL,
1839 CRM_Core_Action
::DELETE
,
1841 'id' => $form->get('id'),
1842 'gid' => $form->get('gid'),
1846 'contact.profileimage.delete',
1850 $form->assign('deleteURL', $deleteURL);
1852 $addressOptions = CRM_Core_BAO_Setting
::valueOptions(CRM_Core_BAO_Setting
::SYSTEM_PREFERENCES_NAME
,
1853 'address_options', TRUE, NULL, TRUE
1856 if (substr($fieldName, 0, 14) === 'state_province') {
1857 $form->addChainSelect($name, ['label' => $title, 'required' => $required]);
1858 $config = CRM_Core_Config
::singleton();
1859 if (!in_array($mode, [CRM_Profile_Form
::MODE_EDIT
, CRM_Profile_Form
::MODE_SEARCH
]) &&
1860 $config->defaultContactStateProvince
1862 $defaultValues[$name] = $config->defaultContactStateProvince
;
1863 $form->setDefaults($defaultValues);
1866 elseif (substr($fieldName, 0, 7) === 'country') {
1867 $form->add('select', $name, $title, CRM_Core_PseudoConstant
::country(), $required, $selectAttributes);
1868 $config = CRM_Core_Config
::singleton();
1869 if (!in_array($mode, [CRM_Profile_Form
::MODE_EDIT
, CRM_Profile_Form
::MODE_SEARCH
]) &&
1870 $config->defaultContactCountry
1872 $defaultValues[$name] = $config->defaultContactCountry
;
1873 $form->setDefaults($defaultValues);
1876 elseif (substr($fieldName, 0, 6) === 'county') {
1877 if ($addressOptions['county']) {
1878 $form->addChainSelect($name, ['label' => $title, 'required' => $required]);
1881 elseif (substr($fieldName, 0, 9) === 'image_URL') {
1882 $form->add('file', $name, $title, $attributes, $required);
1883 $form->addUploadElement($name);
1885 elseif (substr($fieldName, 0, 2) === 'im') {
1886 $form->add('text', $name, $title, $attributes, $required);
1889 if (substr($name, -1) === ']') {
1890 $providerName = substr($name, 0, -1) . '-provider_id]';
1892 $form->add('select', $providerName, NULL,
1893 CRM_Core_PseudoConstant
::get('CRM_Core_DAO_IM', 'provider_id'), $required
1897 $form->add('select', $name . '-provider_id', $title,
1898 CRM_Core_PseudoConstant
::get('CRM_Core_DAO_IM', 'provider_id'), $required
1902 if ($view && $mode != CRM_Profile_Form
::MODE_SEARCH
) {
1903 $form->freeze($name . '-provider_id');
1907 elseif (CRM_Utils_Array
::value('name', $field) == 'membership_type') {
1908 list($orgInfo, $types) = CRM_Member_BAO_MembershipType
::getMembershipTypeInfo();
1909 $sel = &$form->addElement('hierselect', $name, $title);
1910 $select = ['' => ts('- select membership type -')];
1911 if (count($orgInfo) == 1 && $field['is_required']) {
1912 // we only have one org - so we should default to it. Not sure about defaulting to first type
1913 // as it could be missed - so adding a select
1914 // however, possibly that is more similar to the membership form
1915 if (count($types[1]) > 1) {
1916 $types[1] = $select +
$types[1];
1920 $orgInfo = $select +
$orgInfo;
1922 $sel->setOptions([$orgInfo, $types]);
1924 elseif (CRM_Utils_Array
::value('name', $field) == 'membership_status') {
1925 $form->add('select', $name, $title,
1926 CRM_Member_PseudoConstant
::membershipStatus(NULL, NULL, 'label'), $required
1929 elseif (in_array($fieldName, ['gender_id', 'communication_style_id'])) {
1931 $pseudoValues = CRM_Core_PseudoConstant
::get('CRM_Contact_DAO_Contact', $fieldName);
1932 $form->addRadio($name, ts('%1', [1 => $title]), $pseudoValues, ['allowClear' => !$required], NULL, $required);
1934 elseif ($fieldName === 'prefix_id' ||
$fieldName === 'suffix_id') {
1935 $form->addSelect($name, [
1937 'entity' => 'contact',
1938 'field' => $fieldName,
1940 'placeholder' => '',
1943 elseif ($fieldName === 'contact_sub_type') {
1944 $gId = $form->get('gid') ?
$form->get('gid') : CRM_Utils_Array
::value('group_id', $field);
1945 if ($usedFor == 'onbehalf') {
1946 $profileType = 'Organization';
1948 elseif ($usedFor == 'honor') {
1949 $profileType = CRM_Core_BAO_UFField
::getProfileType($form->_params
['honoree_profile_id']);
1952 $profileType = $gId ? CRM_Core_BAO_UFField
::getProfileType($gId) : NULL;
1953 if ($profileType == 'Contact') {
1954 $profileType = 'Individual';
1958 $setSubtype = FALSE;
1959 if (CRM_Contact_BAO_ContactType
::isaSubType($profileType)) {
1960 $setSubtype = $profileType;
1961 $profileType = CRM_Contact_BAO_ContactType
::getBasicType($profileType);
1964 $subtypes = $profileType ? CRM_Contact_BAO_ContactType
::subTypePairs($profileType) : [];
1968 $subtypeList[$setSubtype] = $subtypes[$setSubtype];
1971 $subtypeList = $subtypes;
1974 $form->add('select', $name, $title, $subtypeList, $required, ['class' => 'crm-select2', 'multiple' => TRUE]);
1976 elseif (in_array($fieldName, CRM_Contact_BAO_Contact
::$_greetingTypes)) {
1977 // Get contact type for greeting selector
1978 $gId = $form->get('gid') ?
: CRM_Utils_Array
::value('group_id', $field);
1979 $profileType = CRM_Core_BAO_UFField
::getProfileType($gId, TRUE, FALSE, TRUE);
1981 if (!$profileType ||
in_array($profileType, ['Contact', 'Contribution', 'Participant', 'Membership'])) {
1982 $profileType = ($profileType == 'Contact' && $form->get('id')) ? CRM_Contact_BAO_Contact
::getContactType($form->get('id')) : 'Individual';
1984 if (CRM_Contact_BAO_ContactType
::isaSubType($profileType)) {
1985 $profileType = CRM_Contact_BAO_ContactType
::getBasicType($profileType);
1988 'contact_type' => $profileType,
1989 'greeting_type' => $fieldName,
1991 $form->add('select', $name, $title, CRM_Core_PseudoConstant
::greeting($greeting), $required, ['placeholder' => TRUE]);
1992 // add custom greeting element
1993 $form->add('text', $fieldName . '_custom', ts('Custom %1', [1 => ucwords(str_replace('_', ' ', $fieldName))]),
1997 elseif ($fieldName === 'preferred_communication_method') {
1998 $communicationFields = CRM_Core_PseudoConstant
::get('CRM_Contact_DAO_Contact', 'preferred_communication_method');
1999 foreach ($communicationFields as $key => $var) {
2003 $communicationOptions[] = $form->createElement('checkbox', $key, NULL, $var);
2005 $form->addGroup($communicationOptions, $name, $title, '<br/>');
2007 elseif ($fieldName === 'preferred_mail_format') {
2008 $form->add('select', $name, $title, CRM_Core_SelectValues
::pmf());
2010 elseif ($fieldName === 'preferred_language') {
2011 $form->add('select', $name, $title, CRM_Contact_BAO_Contact
::buildOptions('preferred_language'), $required, ['placeholder' => TRUE]);
2013 elseif ($fieldName == 'external_identifier') {
2014 $form->add('text', $name, $title, $attributes, $required);
2015 $contID = $contactId;
2017 $contID = $form->get('id');
2019 $form->addRule($name,
2020 ts('External ID already exists in Database.'),
2022 ['CRM_Contact_DAO_Contact', $contID, 'external_identifier']
2025 elseif ($fieldName === 'group') {
2026 CRM_Contact_Form_Edit_TagsAndGroups
::buildQuickForm($form, $contactId,
2027 CRM_Contact_Form_Edit_TagsAndGroups
::GROUP
,
2029 $title, NULL, $name, 'checkbox', TRUE
2032 elseif ($fieldName === 'tag') {
2033 CRM_Contact_Form_Edit_TagsAndGroups
::buildQuickForm($form, $contactId,
2034 CRM_Contact_Form_Edit_TagsAndGroups
::TAG
,
2039 elseif (substr($fieldName, 0, 4) === 'url-') {
2040 $form->add('text', $name, $title, CRM_Core_DAO
::getAttribute('CRM_Core_DAO_Website', 'url'), $required);
2041 $form->addRule($name, ts('Enter a valid web address beginning with \'http://\' or \'https://\'.'), 'url');
2043 // Note should be rendered as textarea
2044 elseif (substr($fieldName, -4) == 'note') {
2045 $form->add('textarea', $name, $title, $attributes, $required);
2047 elseif (substr($fieldName, 0, 6) === 'custom') {
2048 $customFieldID = CRM_Core_BAO_CustomField
::getKeyID($fieldName);
2049 if ($customFieldID) {
2050 CRM_Core_BAO_CustomField
::addQuickFormElement($form, $name, $customFieldID, $required, $search, $title);
2053 elseif (substr($fieldName, 0, 14) === 'address_custom') {
2054 list($fName, $locTypeId) = CRM_Utils_System
::explode('-', $fieldName, 2);
2055 $customFieldID = CRM_Core_BAO_CustomField
::getKeyID(substr($fName, 8));
2056 if ($customFieldID) {
2057 CRM_Core_BAO_CustomField
::addQuickFormElement($form, $name, $customFieldID, $required, $search, $title);
2060 elseif ($fieldName == 'send_receipt') {
2061 $form->addElement('checkbox', $name, $title);
2063 elseif ($fieldName == 'soft_credit') {
2064 $form->addEntityRef("soft_credit_contact_id[$rowNumber]", ts('Soft Credit To'), ['create' => TRUE]);
2065 $form->addMoney("soft_credit_amount[{$rowNumber}]", ts('Amount'), FALSE, NULL, FALSE);
2067 elseif ($fieldName === 'product_name') {
2068 list($products, $options) = CRM_Contribute_BAO_Premium
::getPremiumProductInfo();
2069 $sel = &$form->addElement('hierselect', $name, $title);
2070 $products = ['0' => ts('- select %1 -', [1 => $title])] +
$products;
2071 $sel->setOptions([$products, $options]);
2073 elseif ($fieldName === 'payment_instrument') {
2074 $form->add('select', $name, $title,
2075 CRM_Contribute_PseudoConstant
::paymentInstrument(), $required, ['placeholder' => TRUE]);
2077 elseif ($fieldName === 'financial_type') {
2078 $form->add('select', $name, $title,
2079 CRM_Contribute_PseudoConstant
::financialType(), $required, ['placeholder' => TRUE]
2082 elseif ($fieldName === 'contribution_status_id') {
2083 $contributionStatuses = CRM_Contribute_BAO_Contribution_Utils
::getContributionStatuses();
2085 $form->add('select', $name, $title,
2086 $contributionStatuses, $required, ['placeholder' => TRUE]
2089 elseif ($fieldName === 'soft_credit_type') {
2090 $name = "soft_credit_type[$rowNumber]";
2091 $form->add('select', $name, $title,
2092 CRM_Core_OptionGroup
::values("soft_credit_type"), ['placeholder' => TRUE]
2094 //CRM-15350: choose SCT field default value as 'Gift' for membership use
2095 //else (for contribution), use configured SCT default value
2096 $SCTDefaultValue = CRM_Core_OptionGroup
::getDefaultValue("soft_credit_type");
2097 if ($field['field_type'] == 'Membership') {
2098 $SCTDefaultValue = CRM_Core_PseudoConstant
::getKey('CRM_Contribute_BAO_ContributionSoft', 'soft_credit_type_id', 'gift');
2100 $form->addElement('hidden', 'sct_default_id', $SCTDefaultValue, ['id' => 'sct_default_id']);
2102 elseif ($fieldName == 'contribution_soft_credit_pcp_id') {
2103 CRM_Contribute_Form_SoftCredit
::addPCPFields($form, "[$rowNumber]");
2105 elseif ($fieldName == 'currency') {
2106 $form->addCurrency($name, $title, $required, NULL, FALSE, FALSE);
2108 elseif ($fieldName == 'contribution_page_id') {
2109 $form->add('select', $name, $title,
2110 CRM_Contribute_PseudoConstant
::contributionPage(), $required, [
2112 'placeholder' => TRUE,
2116 elseif ($fieldName == 'activity_status_id') {
2117 $form->add('select', $name, $title,
2118 CRM_Core_PseudoConstant
::activityStatus(), $required, ['placeholder' => TRUE]
2121 elseif ($fieldName == 'activity_engagement_level') {
2122 $form->add('select', $name, $title,
2123 CRM_Campaign_PseudoConstant
::engagementLevel(), $required, ['placeholder' => TRUE]
2126 elseif ($fieldName == 'participant_status') {
2128 if ($online == TRUE) {
2129 $cond = 'visibility_id = 1';
2131 $form->add('select', $name, $title,
2132 CRM_Event_PseudoConstant
::participantStatus(NULL, $cond, 'label'), $required, ['placeholder' => TRUE]
2135 elseif ($fieldName == 'participant_role') {
2136 if (!empty($field['is_multiple'])) {
2137 $form->addCheckBox($name, $title, CRM_Event_PseudoConstant
::participantRole(), NULL, NULL, NULL, NULL, ' ', TRUE);
2140 $form->add('select', $name, $title,
2141 CRM_Event_PseudoConstant
::participantRole(), $required, ['placeholder' => TRUE]
2145 elseif ($fieldName == 'world_region') {
2146 $form->add('select', $name, $title, CRM_Core_PseudoConstant
::worldRegion(), $required, $selectAttributes);
2148 elseif ($fieldName == 'signature_html') {
2149 $form->add('wysiwyg', $name, $title, CRM_Core_DAO
::getAttribute('CRM_Core_DAO_Email', $fieldName));
2151 elseif ($fieldName == 'signature_text') {
2152 $form->add('textarea', $name, $title, CRM_Core_DAO
::getAttribute('CRM_Core_DAO_Email', $fieldName));
2154 elseif (substr($fieldName, -11) == 'campaign_id') {
2155 if (CRM_Campaign_BAO_Campaign
::isCampaignEnable()) {
2156 $campaigns = CRM_Campaign_BAO_Campaign
::getCampaigns(CRM_Utils_Array
::value($contactId,
2157 $form->_componentCampaigns
2159 $form->add('select', $name, $title,
2160 $campaigns, $required,
2162 'class' => 'crm-select2 big',
2163 'placeholder' => TRUE,
2168 elseif ($fieldName == 'activity_details') {
2169 $form->add('wysiwyg', $fieldName, $title, ['rows' => 4, 'cols' => 60], $required);
2171 elseif ($fieldName == 'activity_duration') {
2172 $form->add('text', $name, $title, $attributes, $required);
2173 $form->addRule($name, ts('Please enter the duration as number of minutes (integers only).'), 'positiveInteger');
2175 elseif ($fieldName == 'case_status') {
2176 $form->add('select', $name, $title,
2177 CRM_Case_BAO_Case
::buildOptions('case_status_id', 'create'),
2178 $required, ['placeholder' => TRUE]
2182 if (substr($fieldName, 0, 3) === 'is_' or substr($fieldName, 0, 7) === 'do_not_') {
2183 $form->add('advcheckbox', $name, $title, $attributes, $required);
2185 elseif (CRM_Utils_Array
::value('html_type', $field) === 'Select Date') {
2186 $extra = isset($field['datepicker']) ?
$field['datepicker']['extra'] : CRM_Utils_Date
::getDatePickerExtra($field);
2187 $attributes = isset($field['datepicker']) ?
$field['datepicker']['attributes'] : CRM_Utils_Date
::getDatePickerAttributes($field);
2188 $form->add('datepicker', $name, $title, $attributes, $required, $extra);
2191 $form->add('text', $name, $title, $attributes, $required);
2195 static $hiddenSubtype = FALSE;
2196 if (!$hiddenSubtype && CRM_Contact_BAO_ContactType
::isaSubType($field['field_type'])) {
2197 // In registration mode params are submitted via POST and we don't have any clue
2198 // about profile-id or the profile-type (which could be a subtype)
2199 // To generalize the behavior and simplify the process,
2200 // lets always add the hidden
2201 //subtype value if there is any, and we won't have to
2202 // compute it while processing.
2204 $form->addElement('hidden', $usedFor . '[contact_sub_type]', $field['field_type']);
2207 $form->addElement('hidden', 'contact_sub_type_hidden', $field['field_type']);
2209 $hiddenSubtype = TRUE;
2212 if (($view && $mode != CRM_Profile_Form
::MODE_SEARCH
) ||
$isShared) {
2213 $form->freeze($name);
2217 if (in_array($fieldName, [
2218 'non_deductible_amount',
2223 $form->addRule($name, ts('Please enter a valid amount.'), 'money');
2226 if (!($rule == 'email' && $mode == CRM_Profile_Form
::MODE_SEARCH
)) {
2227 $form->addRule($name, ts('Please enter a valid %1', [1 => $title]), $rule);
2233 * Set profile defaults.
2235 * @param int $contactId
2237 * @param array $fields
2238 * Associative array of fields.
2239 * @param array $defaults
2241 * @param bool $singleProfile
2242 * True for single profile else false(Update multiple items).
2243 * @param int $componentId
2244 * Id for specific components like contribute, event etc.
2245 * @param null $component
2247 public static function setProfileDefaults(
2248 $contactId, &$fields, &$defaults,
2249 $singleProfile = TRUE, $componentId = NULL, $component = NULL
2251 if (!$componentId) {
2252 //get the contact details
2253 $contactDetails = CRM_Contact_BAO_Contact
::getHierContactDetails($contactId, $fields);
2254 $details = $contactDetails[$contactId] ??
NULL;
2255 $multipleFields = ['website' => 'url'];
2257 //start of code to set the default values
2258 foreach ($fields as $name => $field) {
2259 // skip pseudo fields
2260 if (substr($name, 0, 9) == 'phone_ext') {
2264 //set the field name depending upon the profile mode(single/multiple)
2265 if ($singleProfile) {
2269 $fldName = "field[$contactId][$name]";
2272 if ($name == 'group') {
2273 CRM_Contact_Form_Edit_TagsAndGroups
::setDefaults($contactId, $defaults, CRM_Contact_Form_Edit_TagsAndGroups
::GROUP
, $fldName);
2275 if ($name == 'tag') {
2276 CRM_Contact_Form_Edit_TagsAndGroups
::setDefaults($contactId, $defaults, CRM_Contact_Form_Edit_TagsAndGroups
::TAG
, $fldName);
2279 if (!empty($details[$name]) ||
isset($details[$name])) {
2280 //to handle custom data (checkbox) to be written
2281 // to handle birth/deceased date, greeting_type and few other fields
2282 if (in_array($name, CRM_Contact_BAO_Contact
::$_greetingTypes)) {
2283 $defaults[$fldName] = $details[$name . '_id'];
2284 $defaults[$name . '_custom'] = $details[$name . '_custom'];
2286 elseif ($name == 'preferred_communication_method') {
2287 $v = $details[$name];
2288 if (!is_array($details[$name])) {
2289 $v = explode(CRM_Core_DAO
::VALUE_SEPARATOR
, $v);
2291 foreach ($v as $item) {
2293 $defaults[$fldName . "[$item]"] = 1;
2297 elseif ($name == 'contact_sub_type') {
2298 $defaults[$fldName] = explode(CRM_Core_DAO
::VALUE_SEPARATOR
, trim($details[$name], CRM_Core_DAO
::VALUE_SEPARATOR
));
2300 elseif ($name == 'world_region') {
2301 $defaults[$fldName] = $details['worldregion_id'];
2303 elseif (CRM_Core_BAO_CustomField
::getKeyID($name)) {
2304 $defaults[$fldName] = self
::formatCustomValue($field, $details[$name]);
2305 if (!$singleProfile && $field['html_type'] === 'CheckBox') {
2306 // For batch update profile there needs to be a key lik
2307 // $defaults['field[166]['custom_8'][2]'] => 1 where
2308 // 166 is the conntact id, 8 is the field id and 2 is the checkbox option.
2309 foreach ($defaults[$fldName] as $itemKey => $itemValue) {
2310 $defaults[$fldName . '[' . $itemKey . ']'] = $itemValue;
2315 $defaults[$fldName] = $details[$name];
2319 $blocks = ['email', 'phone', 'im', 'openid'];
2320 list($fieldName, $locTypeId, $phoneTypeId) = CRM_Utils_System
::explode('-', $name, 3);
2321 if (!in_array($fieldName, $multipleFields)) {
2322 if (is_array($details)) {
2323 foreach ($details as $key => $value) {
2324 // when we fixed CRM-5319 - get primary loc
2325 // type as per loc field and removed below code.
2326 $primaryLocationType = FALSE;
2327 if ($locTypeId == 'Primary') {
2328 if (is_array($value) && array_key_exists($fieldName, $value)) {
2329 $primaryLocationType = TRUE;
2330 if (in_array($fieldName, $blocks)) {
2331 $locTypeId = CRM_Contact_BAO_Contact
::getPrimaryLocationType($contactId, FALSE, $fieldName);
2334 $locTypeId = CRM_Contact_BAO_Contact
::getPrimaryLocationType($contactId, FALSE, 'address');
2339 // fixed for CRM-665
2340 if (is_numeric($locTypeId)) {
2341 if ($primaryLocationType ||
$locTypeId == CRM_Utils_Array
::value('location_type_id', $value)) {
2342 if (!empty($value[$fieldName])) {
2343 //to handle stateprovince and country
2344 if ($fieldName == 'state_province') {
2345 $defaults[$fldName] = $value['state_province_id'];
2347 elseif ($fieldName == 'county') {
2348 $defaults[$fldName] = $value['county_id'];
2350 elseif ($fieldName == 'country') {
2351 if (!isset($value['country_id']) ||
!$value['country_id']) {
2352 $config = CRM_Core_Config
::singleton();
2353 if ($config->defaultContactCountry
) {
2354 $defaults[$fldName] = $config->defaultContactCountry
;
2358 $defaults[$fldName] = $value['country_id'];
2361 elseif ($fieldName == 'phone') {
2363 if (isset($value['phone'][$phoneTypeId])) {
2364 $defaults[$fldName] = $value['phone'][$phoneTypeId];
2366 if (isset($value['phone_ext'][$phoneTypeId])) {
2367 $defaults[str_replace('phone', 'phone_ext', $fldName)] = $value['phone_ext'][$phoneTypeId];
2371 $phoneDefault = $value['phone'] ??
NULL;
2373 if (!is_array($phoneDefault)) {
2374 $defaults[$fldName] = $phoneDefault;
2378 elseif ($fieldName == 'email') {
2379 //adding the first email (currently we don't support multiple emails of same location type)
2380 $defaults[$fldName] = $value['email'];
2382 elseif ($fieldName == 'im') {
2383 //adding the first im (currently we don't support multiple ims of same location type)
2384 $defaults[$fldName] = $value['im'];
2385 $defaults[$fldName . '-provider_id'] = $value['im_provider_id'];
2388 $defaults[$fldName] = $value[$fieldName];
2391 elseif (strpos($fieldName, 'address_custom') === 0 && !empty($value[substr($fieldName, 8)])) {
2392 $defaults[$fldName] = self
::formatCustomValue($field, $value[substr($fieldName, 8)]);
2396 elseif (strpos($fieldName, 'address_custom') === 0 && !empty($value[substr($fieldName, 8)])) {
2397 $defaults[$fldName] = self
::formatCustomValue($field, $value[substr($fieldName, 8)]);
2403 if (is_array($details)) {
2404 if ($fieldName === 'url'
2405 && !empty($details['website'])
2406 && !empty($details['website'][$locTypeId])
2408 $defaults[$fldName] = $details['website'][$locTypeId]['url'] ??
NULL;
2416 // Handling Contribution Part of the batch profile
2417 if (CRM_Core_Permission
::access('CiviContribute') && $component == 'Contribute') {
2418 self
::setComponentDefaults($fields, $componentId, $component, $defaults);
2421 // Handling Event Participation Part of the batch profile
2422 if (CRM_Core_Permission
::access('CiviEvent') && $component == 'Event') {
2423 self
::setComponentDefaults($fields, $componentId, $component, $defaults);
2426 // Handling membership Part of the batch profile
2427 if (CRM_Core_Permission
::access('CiviMember') && $component == 'Membership') {
2428 self
::setComponentDefaults($fields, $componentId, $component, $defaults);
2431 // Handling Activity Part of the batch profile
2432 if ($component == 'Activity') {
2433 self
::setComponentDefaults($fields, $componentId, $component, $defaults);
2436 // Handling Case Part of the batch profile
2437 if (CRM_Core_Permission
::access('CiviCase') && $component == 'Case') {
2438 self
::setComponentDefaults($fields, $componentId, $component, $defaults);
2443 * Get profiles by type eg: pure Individual etc
2445 * @param array $types
2446 * Associative array of types eg: types('Individual').
2447 * @param bool $onlyPure
2448 * True if only pure profiles are required.
2451 * associative array of profiles
2453 public static function getProfiles($types, $onlyPure = FALSE) {
2455 $ufGroups = CRM_Core_PseudoConstant
::get('CRM_Core_DAO_UFField', 'uf_group_id');
2457 CRM_Utils_Hook
::aclGroup(CRM_Core_Permission
::ADMIN
, NULL, 'civicrm_uf_group', $ufGroups, $ufGroups);
2459 // Exclude Batch Data Entry profiles - CRM-10901
2460 $batchProfiles = CRM_Core_BAO_UFGroup
::getBatchProfiles();
2462 foreach ($ufGroups as $id => $title) {
2463 $ptype = CRM_Core_BAO_UFField
::getProfileType($id, FALSE, $onlyPure);
2464 if (in_array($ptype, $types) && !array_key_exists($id, $batchProfiles)) {
2465 $profiles[$id] = $title;
2472 * Check whether a profile is valid combination of
2473 * required and/or optional profile types
2475 * @param array $required
2476 * Array of types those are required.
2477 * @param array $optional
2478 * Array of types those are optional.
2481 * associative array of profiles
2483 public static function getValidProfiles($required, $optional = NULL) {
2484 if (!is_array($required) ||
empty($required)) {
2489 $ufGroups = CRM_Core_PseudoConstant
::get('CRM_Core_DAO_UFField', 'uf_group_id');
2491 CRM_Utils_Hook
::aclGroup(CRM_Core_Permission
::ADMIN
, NULL, 'civicrm_uf_group', $ufGroups, $ufGroups);
2493 foreach ($ufGroups as $id => $title) {
2494 $type = CRM_Core_BAO_UFField
::checkValidProfileType($id, $required, $optional);
2496 $profiles[$id] = $title;
2504 * Check whether a profile is valid combination of
2505 * required profile fields
2507 * @param array $ufId
2508 * Integer id of the profile.
2509 * @param array $required
2510 * Array of fields those are required in the profile.
2513 * associative array of profiles
2515 public static function checkValidProfile($ufId, $required = NULL) {
2516 $validProfile = FALSE;
2518 return $validProfile;
2521 if (!CRM_Core_DAO
::getFieldValue('CRM_Core_DAO_UFGroup', $ufId, 'is_active')) {
2522 return $validProfile;
2525 $profileFields = self
::getFields($ufId, FALSE, CRM_Core_Action
::VIEW
, NULL,
2526 NULL, FALSE, NULL, FALSE, NULL,
2527 CRM_Core_Permission
::CREATE
, NULL
2531 if (!empty($profileFields)) {
2532 $fields = array_keys($profileFields);
2533 foreach ($fields as $val) {
2534 foreach ($required as $key => $field) {
2535 if (strpos($val, $field) === 0) {
2536 unset($required[$key]);
2541 $validProfile = (empty($required));
2544 return $validProfile;
2548 * Get default value for Register.
2550 * @param array $fields
2551 * @param array $defaults
2555 public static function setRegisterDefaults(&$fields, &$defaults) {
2556 $config = CRM_Core_Config
::singleton();
2557 foreach ($fields as $name => $field) {
2558 if (substr($name, 0, 8) == 'country-') {
2559 if (!empty($config->defaultContactCountry
)) {
2560 $defaults[$name] = $config->defaultContactCountry
;
2563 elseif (substr($name, 0, 15) == 'state_province-') {
2564 if (!empty($config->defaultContactStateProvince
)) {
2565 $defaults[$name] = $config->defaultContactStateProvince
;
2573 * make a copy of a profile, including
2574 * all the fields in the profile
2577 * The profile id to copy.
2579 * @return \CRM_Core_DAO
2581 public static function copy($id) {
2582 $maxId = CRM_Core_DAO
::singleValueQuery("SELECT max(id) FROM civicrm_uf_group");
2584 $title = ts('[Copy id %1]', [1 => $maxId +
1]);
2587 'title' => ' ' . $title,
2588 'name' => '__Copy_id_' . ($maxId +
1) . '_',
2592 $copy = CRM_Core_DAO
::copyGeneric('CRM_Core_DAO_UFGroup',
2598 if ($pos = strrpos($copy->name
, "_{$id}")) {
2599 $copy->name
= substr_replace($copy->name
, '', $pos);
2601 $copy->name
= CRM_Utils_String
::munge($copy->name
, '_', 56) . "_{$copy->id}";
2604 $copyUFJoin = CRM_Core_DAO
::copyGeneric('CRM_Core_DAO_UFJoin',
2605 ['uf_group_id' => $id],
2606 ['uf_group_id' => $copy->id
],
2611 $copyUFField = CRM_Core_DAO
::copyGeneric('CRM_Core_BAO_UFField',
2612 ['uf_group_id' => $id],
2613 ['uf_group_id' => $copy->id
]
2616 $maxWeight = CRM_Utils_Weight
::getMax('CRM_Core_DAO_UFJoin', NULL, 'weight');
2620 UPDATE civicrm_uf_join
2622 WHERE uf_group_id = %2
2623 AND ( entity_id IS NULL OR entity_id <= 0 )
2626 1 => [$maxWeight +
1, 'Integer'],
2627 2 => [$copy->id
, 'Integer'],
2629 CRM_Core_DAO
::executeQuery($query, $p);
2630 if ($copy->is_reserved
) {
2631 $query = "UPDATE civicrm_uf_group SET is_reserved = 0 WHERE id = %1";
2632 $params = [1 => [$copy->id
, 'Integer']];
2633 CRM_Core_DAO
::executeQuery($query, $params);
2635 CRM_Utils_Hook
::copy('UFGroup', $copy);
2641 * Process that send notification e-mails
2643 * @param int $contactID
2645 * @param array $values
2646 * Associative array of name/value pair.
2648 public static function commonSendMail($contactID, &$values) {
2649 if (!$contactID ||
!$values) {
2653 $template = CRM_Core_Smarty
::singleton();
2655 $displayName = CRM_Core_DAO
::getFieldValue('CRM_Contact_DAO_Contact',
2660 self
::profileDisplay($values['id'], $values['values'], $template);
2661 $emailList = explode(',', $values['email']);
2663 $contactLink = CRM_Utils_System
::url('civicrm/contact/view',
2664 "reset=1&cid=$contactID",
2665 TRUE, NULL, FALSE, FALSE, TRUE
2668 //get the default domain email address.
2669 list($domainEmailName, $domainEmailAddress) = CRM_Core_BAO_Domain
::getNameAndEmail();
2671 if (!$domainEmailAddress ||
$domainEmailAddress == 'info@EXAMPLE.ORG') {
2672 $fixUrl = CRM_Utils_System
::url('civicrm/admin/domain', 'action=update&reset=1');
2673 CRM_Core_Error
::statusBounce(ts('The site administrator needs to enter a valid \'FROM Email Address\' in <a href="%1">Administer CiviCRM » Communications » FROM Email Addresses</a>. The email address used may need to be a valid mail account with your email service provider.', [1 => $fixUrl]));
2676 foreach ($emailList as $emailTo) {
2677 // FIXME: take the below out of the foreach loop
2678 CRM_Core_BAO_MessageTemplate
::sendTemplate(
2680 'groupName' => 'msg_tpl_workflow_uf',
2681 'valueName' => 'uf_notify',
2682 'contactId' => $contactID,
2684 'displayName' => $displayName,
2685 'currentDate' => date('r'),
2686 'contactLink' => $contactLink,
2688 'from' => "$domainEmailName <$domainEmailAddress>",
2689 'toEmail' => $emailTo,
2696 * Given a contact id and a group id, returns the field values from the db
2697 * for this group and notify email only if group's notify field is
2698 * set and field values are not empty
2704 * @param array $params
2705 * @param bool $skipCheck
2709 public function checkFieldsEmptyValues($gid, $cid, $params, $skipCheck = FALSE) {
2711 if (CRM_Core_BAO_UFGroup
::filterUFGroups($gid, $cid) ||
$skipCheck) {
2713 $fields = CRM_Core_BAO_UFGroup
::getFields($gid, FALSE, CRM_Core_Action
::VIEW
);
2714 CRM_Core_BAO_UFGroup
::getValues($cid, $fields, $values, FALSE, $params, TRUE);
2716 $email = CRM_Core_DAO
::getFieldValue('CRM_Core_DAO_UFGroup', $gid, 'notify');
2718 if (!empty($values) &&
2723 'values' => $values,
2734 * Assign uf fields to template.
2738 * @param array $values
2739 * @param CRM_Core_Smarty $template
2741 public static function profileDisplay($gid, $values, $template) {
2742 $groupTitle = CRM_Core_DAO
::getFieldValue('CRM_Core_DAO_UFGroup', $gid, 'title');
2743 $template->assign('grouptitle', $groupTitle);
2744 if (count($values)) {
2745 $template->assign('values', $values);
2750 * Format fields for dupe Contact Matching.
2752 * @param array $params
2754 * @param int $contactId
2757 * associated formatted array
2759 public static function formatFields($params, $contactId = NULL) {
2761 // get the primary location type id and email
2762 list($name, $primaryEmail, $primaryLocationType) = CRM_Contact_BAO_Contact_Location
::getEmailDetails($contactId);
2765 $defaultLocationType = CRM_Core_BAO_LocationType
::getDefault();
2766 $primaryLocationType = $defaultLocationType->id
;
2772 $primaryLocation = 0;
2773 foreach ($params as $key => $value) {
2774 list($fieldName, $locTypeId, $phoneTypeId) = explode('-', $key);
2776 if ($locTypeId == 'Primary') {
2777 $locTypeId = $primaryLocationType;
2780 if (is_numeric($locTypeId)) {
2781 if (!in_array($locTypeId, $locationType)) {
2782 $locationType[$count] = $locTypeId;
2785 $loc = CRM_Utils_Array
::key($locTypeId, $locationType);
2787 $data['location'][$loc]['location_type_id'] = $locTypeId;
2789 // if we are getting in a new primary email, dont overwrite the new one
2790 if ($locTypeId == $primaryLocationType) {
2791 if (!empty($params['email-' . $primaryLocationType])) {
2792 $data['location'][$loc]['email'][$loc]['email'] = $fields['email-' . $primaryLocationType];
2794 elseif (isset($primaryEmail)) {
2795 $data['location'][$loc]['email'][$loc]['email'] = $primaryEmail;
2801 $data['location'][$loc]['is_primary'] = 1;
2803 if ($fieldName == 'phone') {
2805 $data['location'][$loc]['phone'][$loc]['phone_type_id'] = $phoneTypeId;
2808 $data['location'][$loc]['phone'][$loc]['phone_type_id'] = '';
2810 $data['location'][$loc]['phone'][$loc]['phone'] = $value;
2812 elseif ($fieldName == 'email') {
2813 $data['location'][$loc]['email'][$loc]['email'] = $value;
2815 elseif ($fieldName == 'im') {
2816 $data['location'][$loc]['im'][$loc]['name'] = $value;
2819 if ($fieldName === 'state_province') {
2820 $data['location'][$loc]['address']['state_province_id'] = $value;
2822 elseif ($fieldName === 'country') {
2823 $data['location'][$loc]['address']['country_id'] = $value;
2826 $data['location'][$loc]['address'][$fieldName] = $value;
2831 // TODO: prefix, suffix and gender translation may no longer be necessary - check inputs
2832 if ($key === 'individual_suffix') {
2833 $data['suffix_id'] = $value;
2835 elseif ($key === 'individual_prefix') {
2836 $data['prefix_id'] = $value;
2838 elseif ($key === 'gender') {
2839 $data['gender_id'] = $value;
2841 elseif (substr($key, 0, 6) === 'custom') {
2842 if ($customFieldID = CRM_Core_BAO_CustomField
::getKeyID($key)) {
2844 if ($customFields[$customFieldID]['html_type'] == 'CheckBox') {
2845 $value = implode(CRM_Core_DAO
::VALUE_SEPARATOR
, array_keys($value));
2847 // fix the date field
2848 if ($customFields[$customFieldID]['data_type'] == 'Date') {
2849 $date = CRM_Utils_Date
::format($value);
2856 $data['custom'][$customFieldID] = [
2859 'extends' => $customFields[$customFieldID]['extends'],
2860 'type' => $customFields[$customFieldID]['data_type'],
2861 'custom_field_id' => $customFieldID,
2865 elseif ($key == 'edit') {
2869 $data[$key] = $value;
2874 if (!$primaryLocation) {
2876 $data['location'][$loc]['email'][$loc]['email'] = $primaryEmail;
2883 * Calculate the profile type 'group_type' as per profile fields.
2887 * @param bool $includeTypeValues
2888 * @param int $ignoreFieldId
2889 * Ignore particular profile field.
2892 * list of calculated group type
2894 public static function calculateGroupType($gId, $includeTypeValues = FALSE, $ignoreFieldId = NULL) {
2895 //get the profile fields.
2896 $ufFields = self
::getFields($gId, FALSE, NULL, NULL, NULL, TRUE, NULL, TRUE);
2897 return self
::_calculateGroupType($ufFields, $includeTypeValues, $ignoreFieldId);
2901 * Calculate the profile type 'group_type' as per profile fields.
2904 * @param bool $includeTypeValues
2905 * @param int $ignoreFieldId
2906 * Ignore perticular profile field.
2909 * list of calculated group type
2911 public static function _calculateGroupType($ufFields, $includeTypeValues = FALSE, $ignoreFieldId = NULL) {
2912 $groupType = $groupTypeValues = $customFieldIds = [];
2913 if (!empty($ufFields)) {
2914 foreach ($ufFields as $fieldName => $fieldValue) {
2915 //ignore field from group type when provided.
2916 //in case of update profile field.
2917 if ($ignoreFieldId && ($ignoreFieldId == $fieldValue['field_id'])) {
2920 if (!in_array($fieldValue['field_type'], $groupType)) {
2921 $groupType[$fieldValue['field_type']] = $fieldValue['field_type'];
2924 if ($includeTypeValues && ($fldId = CRM_Core_BAO_CustomField
::getKeyID($fieldName))) {
2925 $customFieldIds[$fldId] = $fldId;
2930 if (!empty($customFieldIds)) {
2931 $query = 'SELECT DISTINCT(cg.id), cg.extends, cg.extends_entity_column_id, cg.extends_entity_column_value FROM civicrm_custom_group cg LEFT JOIN civicrm_custom_field cf ON cf.custom_group_id = cg.id WHERE cg.extends_entity_column_value IS NOT NULL AND cf.id IN (' . implode(',', $customFieldIds) . ')';
2933 $customGroups = CRM_Core_DAO
::executeQuery($query);
2934 while ($customGroups->fetch()) {
2935 if (!$customGroups->extends_entity_column_value
) {
2939 $groupTypeName = "{$customGroups->extends}Type";
2940 if ($customGroups->extends == 'Participant' && $customGroups->extends_entity_column_id
) {
2941 $groupTypeName = CRM_Core_PseudoConstant
::getName('CRM_Core_DAO_CustomGroup', 'extends_entity_column_id', $customGroups->extends_entity_column_id
);
2944 foreach (explode(CRM_Core_DAO
::VALUE_SEPARATOR
, $customGroups->extends_entity_column_value
) as $val) {
2946 $groupTypeValues[$groupTypeName][$val] = $val;
2951 if (!empty($groupTypeValues)) {
2952 $groupType = array_merge($groupType, $groupTypeValues);
2960 * Update the profile type 'group_type' as per profile fields including group types and group subtype values.
2961 * Build and store string like: group_type1,group_type2[VALUE_SEPARATOR]group_type1Type:1:2:3,group_type2Type:1:2
2964 * BirthDate + Email Individual,Contact
2965 * BirthDate + Subject Individual,Activity
2966 * BirthDate + Subject + SurveyOnlyField Individual,Activity\0ActivityType:28
2967 * BirthDate + Subject + SurveyOnlyField + PhoneOnlyField (Not allowed)
2968 * BirthDate + SurveyOnlyField Individual,Activity\0ActivityType:28
2969 * BirthDate + Subject + SurveyOrPhoneField Individual,Activity\0ActivityType:2:28
2970 * BirthDate + SurveyOrPhoneField Individual,Activity\0ActivityType:2:28
2971 * BirthDate + SurveyOrPhoneField + SurveyOnlyField Individual,Activity\0ActivityType:2:28
2972 * BirthDate + StudentField + Subject + SurveyOnlyField Individual,Activity,Student\0ActivityType:28
2975 * @param array $groupTypes
2976 * With key having group type names.
2980 public static function updateGroupTypes($gId, $groupTypes = []) {
2981 if (!is_array($groupTypes) ||
!$gId) {
2985 // If empty group types set group_type as 'null'
2986 if (empty($groupTypes)) {
2987 return CRM_Core_DAO
::setFieldValue('CRM_Core_DAO_UFGroup', $gId, 'group_type', 'null');
2990 $componentGroupTypes = ['Contribution', 'Participant', 'Membership', 'Activity', 'Case'];
2991 $validGroupTypes = array_merge([
2996 ], $componentGroupTypes, CRM_Contact_BAO_ContactType
::subTypes());
2998 $gTypes = $gTypeValues = [];
3000 $participantExtends = ['ParticipantRole', 'ParticipantEventName', 'ParticipantEventType'];
3001 // Get valid group type and group subtypes
3002 foreach ($groupTypes as $groupType => $value) {
3003 if (in_array($groupType, $validGroupTypes) && !in_array($groupType, $gTypes)) {
3004 $gTypes[] = $groupType;
3009 if (in_array($groupType, $participantExtends)) {
3010 $subTypesOf = $groupType;
3012 elseif (strpos($groupType, 'Type') > 0) {
3013 $subTypesOf = substr($groupType, 0, strpos($groupType, 'Type'));
3019 if (!empty($value) &&
3020 (in_array($subTypesOf, $componentGroupTypes) ||
3021 in_array($subTypesOf, $participantExtends)
3024 $gTypeValues[$subTypesOf] = $groupType . ":" . implode(':', $value);
3028 if (empty($gTypes)) {
3032 // Build String to store group types and group subtypes
3033 $groupTypeString = implode(',', $gTypes);
3034 if (!empty($gTypeValues)) {
3035 $groupTypeString .= CRM_Core_DAO
::VALUE_SEPARATOR
. implode(',', $gTypeValues);
3038 return CRM_Core_DAO
::setFieldValue('CRM_Core_DAO_UFGroup', $gId, 'group_type', $groupTypeString);
3042 * Create a "group_type" string.
3044 * @param array $coreTypes
3045 * E.g. array('Individual','Contact','Student').
3046 * @param array $subTypes
3047 * E.g. array('ActivityType' => array(7, 11)).
3048 * @param string $delim
3051 * @throws CRM_Core_Exception
3053 public static function encodeGroupType($coreTypes, $subTypes, $delim = CRM_Core_DAO
::VALUE_SEPARATOR
) {
3054 $groupTypeExpr = '';
3056 $groupTypeExpr .= implode(',', $coreTypes);
3059 //CRM-15427 Allow Multiple subtype filtering
3060 //if (count($subTypes) > 1) {
3061 //throw new CRM_Core_Exception("Multiple subtype filtering is not currently supported by widget.");
3063 foreach ($subTypes as $subType => $subTypeIds) {
3064 $groupTypeExpr .= $delim . $subType . ':' . implode(':', $subTypeIds);
3067 return $groupTypeExpr;
3071 * setDefault componet specific profile fields.
3073 * @param array $fields
3075 * @param int $componentId
3077 * @param string $component
3079 * @param array $defaults
3080 * An array of default values.
3082 * @param bool $isStandalone
3084 public static function setComponentDefaults(&$fields, $componentId, $component, &$defaults, $isStandalone = FALSE) {
3085 if (!$componentId ||
3086 !in_array($component, ['Contribute', 'Membership', 'Event', 'Activity', 'Case'])
3091 $componentBAO = $componentSubType = NULL;
3092 switch ($component) {
3094 $componentBAO = 'CRM_Member_BAO_Membership';
3095 $componentBAOName = 'Membership';
3096 $componentSubType = ['membership_type_id'];
3100 $componentBAO = 'CRM_Contribute_BAO_Contribution';
3101 $componentBAOName = 'Contribution';
3102 $componentSubType = ['financial_type_id'];
3106 $componentBAO = 'CRM_Event_BAO_Participant';
3107 $componentBAOName = 'Participant';
3108 $componentSubType = ['role_id', 'event_id', 'event_type_id'];
3112 $componentBAO = 'CRM_Activity_BAO_Activity';
3113 $componentBAOName = 'Activity';
3114 $componentSubType = ['activity_type_id'];
3118 $componentBAO = 'CRM_Case_BAO_Case';
3119 $componentBAOName = 'Case';
3120 $componentSubType = ['case_type_id'];
3125 $params = ['id' => $componentId];
3127 //get the component values.
3128 CRM_Core_DAO
::commonRetrieve($componentBAO, $params, $values);
3129 if ($componentBAOName == 'Participant') {
3130 $values +
= ['event_type_id' => CRM_Core_DAO
::getFieldValue('CRM_Event_DAO_Event', $values['event_id'], 'event_type_id')];
3133 $formattedGroupTree = [];
3135 foreach ($fields as $name => $field) {
3136 $fldName = $isStandalone ?
$name : "field[$componentId][$name]";
3137 if (array_key_exists($name, $values)) {
3138 $defaults[$fldName] = $values[$name];
3140 elseif ($name == 'participant_note') {
3141 $noteDetails = CRM_Core_BAO_Note
::getNote($componentId, 'civicrm_participant');
3142 $defaults[$fldName] = array_pop($noteDetails);
3144 elseif (in_array($name, [
3146 'payment_instrument',
3147 'participant_status',
3150 $defaults[$fldName] = $values["{$name}_id"];
3152 elseif ($name == 'membership_type') {
3153 // since membership_type field is a hierselect -
3154 $defaults[$fldName][0]
3155 = CRM_Core_DAO
::getFieldValue('CRM_Member_DAO_MembershipType', $values['membership_type_id'], 'member_of_contact_id', 'id');
3156 $defaults[$fldName][1] = $values['membership_type_id'];
3158 elseif ($name == 'membership_status') {
3159 $defaults[$fldName] = $values['status_id'];
3161 elseif ($name == 'case_status') {
3162 $defaults[$fldName] = $values['case_status_id'];
3164 elseif (CRM_Core_BAO_CustomField
::getKeyID($name, TRUE) !== [NULL, NULL]) {
3165 if (empty($formattedGroupTree)) {
3166 //get the groupTree as per subTypes.
3168 foreach ($componentSubType as $subType) {
3169 $subTree = CRM_Core_BAO_CustomGroup
::getTree($componentBAOName, NULL,
3170 $componentId, 0, $values[$subType]
3172 $groupTree = CRM_Utils_Array
::crmArrayMerge($groupTree, $subTree);
3174 $formattedGroupTree = CRM_Core_BAO_CustomGroup
::formatGroupTree($groupTree, 1);
3175 CRM_Core_BAO_CustomGroup
::setDefaults($formattedGroupTree, $defaults);
3178 //FIX ME: We need to loop defaults, but once we move to custom_1_x convention this code can be simplified.
3179 foreach ($defaults as $customKey => $customValue) {
3180 if ($customFieldDetails = CRM_Core_BAO_CustomField
::getKeyID($customKey, TRUE)) {
3181 if ($name == 'custom_' . $customFieldDetails[0]) {
3183 //hack to set default for checkbox
3184 //basically this is for weired field name like field[33][custom_19]
3185 //we are converting this field name to array structure and assign value.
3188 foreach ($formattedGroupTree as $tree) {
3189 if (!empty($tree['fields'][$customFieldDetails[0]])) {
3190 if ('CheckBox' == CRM_Utils_Array
::value('html_type', $tree['fields'][$customFieldDetails[0]])) {
3192 $defaults['field'][$componentId][$name] = $customValue;
3195 elseif (CRM_Utils_Array
::value('data_type', $tree['fields'][$customFieldDetails[0]]) == 'Date') {
3198 // CRM-6681, $default contains formatted date, time values.
3199 $defaults[$fldName] = $customValue;
3200 if (!empty($defaults[$customKey . '_time'])) {
3201 $defaults['field'][$componentId][$name . '_time'] = $defaults[$customKey . '_time'];
3207 if (!$skipValue ||
$isStandalone) {
3208 $defaults[$fldName] = $customValue;
3210 unset($defaults[$customKey]);
3216 elseif (isset($values[$fldName])) {
3217 $defaults[$fldName] = $values[$fldName];
3223 * Retrieve groups of profiles.
3225 * @param int $profileID
3226 * Id of the profile.
3231 public static function profileGroups($profileID) {
3233 $profileTypes = CRM_Core_DAO
::getFieldValue('CRM_Core_DAO_UFGroup', $profileID, 'group_type');
3234 if ($profileTypes) {
3235 $groupTypeParts = explode(CRM_Core_DAO
::VALUE_SEPARATOR
, $profileTypes);
3236 $groupTypes = explode(',', $groupTypeParts[0]);
3242 * Alter contact params by filtering existing subscribed groups and returns
3243 * unsubscribed groups array for subscription.
3245 * @param array $params
3247 * @param int $contactId
3251 * This contains array of groups for subscription
3253 public static function getDoubleOptInGroupIds(&$params, $contactId = NULL) {
3254 $config = CRM_Core_Config
::singleton();
3255 $subscribeGroupIds = [];
3257 // process further only if profileDoubleOptIn enabled and if groups exist
3258 if (!array_key_exists('group', $params) ||
3259 !self
::isProfileDoubleOptin() ||
3260 CRM_Utils_System
::isNull($params['group'])
3262 return $subscribeGroupIds;
3265 //check if contact email exist.
3267 foreach ($params as $name => $value) {
3268 if (strpos($name, 'email-') !== FALSE) {
3274 //Proceed furthur only if email present
3276 return $subscribeGroupIds;
3279 //do check for already subscriptions.
3280 $contactGroups = [];
3284 FROM civicrm_group_contact
3285 WHERE status = 'Added'
3286 AND contact_id = %1";
3288 $dao = CRM_Core_DAO
::executeQuery($query, [1 => [$contactId, 'Integer']]);
3289 while ($dao->fetch()) {
3290 $contactGroups[$dao->group_id
] = $dao->group_id
;
3294 //since we don't have names, compare w/ label.
3295 $mailingListGroupType = array_search('Mailing List', CRM_Core_OptionGroup
::values('group_type'));
3297 //actual processing start.
3298 foreach ($params['group'] as $groupId => $isSelected) {
3299 //unset group those are not selected.
3301 unset($params['group'][$groupId]);
3305 $groupTypes = explode(CRM_Core_DAO
::VALUE_SEPARATOR
,
3306 CRM_Core_DAO
::getFieldValue('CRM_Contact_DAO_Group', $groupId, 'group_type', 'id')
3308 //get only mailing type group and unset it from params
3309 if (in_array($mailingListGroupType, $groupTypes) && !in_array($groupId, $contactGroups)) {
3310 $subscribeGroupIds[$groupId] = $groupId;
3311 unset($params['group'][$groupId]);
3315 return $subscribeGroupIds;
3319 * Check if we are rendering mixed profiles.
3321 * @param array $profileIds
3322 * Associated array of profile ids.
3325 * true if profile is mixed
3327 public static function checkForMixProfiles($profileIds) {
3328 $mixProfile = FALSE;
3330 $contactTypes = ['Individual', 'Household', 'Organization'];
3331 $subTypes = CRM_Contact_BAO_ContactType
::subTypes();
3333 $components = ['Contribution', 'Participant', 'Membership', 'Activity'];
3335 $typeCount = ['ctype' => [], 'subtype' => []];
3336 foreach ($profileIds as $gid) {
3337 $profileType = CRM_Core_BAO_UFField
::getProfileType($gid);
3338 // ignore profile of type Contact
3339 if ($profileType == 'Contact') {
3342 if (in_array($profileType, $contactTypes)) {
3343 if (!isset($typeCount['ctype'][$profileType])) {
3344 $typeCount['ctype'][$profileType] = 1;
3347 // check if we are rendering profile of different contact types
3348 if (count($typeCount['ctype']) == 2) {
3353 elseif (in_array($profileType, $components)) {
3358 if (!isset($typeCount['subtype'][$profileType])) {
3359 $typeCount['subtype'][$profileType] = 1;
3361 // check if we are rendering profile of different contact sub types
3362 if (count($typeCount['subtype']) == 2) {
3372 * Determine of we show overlay profile or not.
3375 * true if profile should be shown else false
3377 public static function showOverlayProfile() {
3378 $showOverlay = TRUE;
3380 // get the id of overlay profile
3381 $overlayProfileId = CRM_Core_DAO
::getFieldValue('CRM_Core_DAO_UFGroup', 'summary_overlay', 'id', 'name');
3382 $query = "SELECT count(id) FROM civicrm_uf_field WHERE uf_group_id = {$overlayProfileId} AND visibility IN ('Public Pages', 'Public Pages and Listings') ";
3384 $count = CRM_Core_DAO
::singleValueQuery($query);
3386 //check if there are no public fields and use is anonymous
3387 $session = CRM_Core_Session
::singleton();
3388 if (!$count && !$session->get('userID')) {
3389 $showOverlay = FALSE;
3392 return $showOverlay;
3396 * Get group type values of the profile.
3398 * @param int $profileId
3399 * @param string $groupType
3404 public static function groupTypeValues($profileId, $groupType = NULL) {
3405 $groupTypeValue = [];
3406 $groupTypes = CRM_Core_DAO
::getFieldValue('CRM_Core_DAO_UFGroup', $profileId, 'group_type');
3408 $groupTypeParts = explode(CRM_Core_DAO
::VALUE_SEPARATOR
, $groupTypes);
3409 if (empty($groupTypeParts[1])) {
3410 return $groupTypeValue;
3412 $participantExtends = ['ParticipantRole', 'ParticipantEventName', 'ParticipantEventType'];
3414 foreach (explode(',', $groupTypeParts[1]) as $groupTypeValues) {
3416 $valueParts = explode(':', $groupTypeValues);
3418 ($valueParts[0] != "{$groupType}Type" ||
3419 ($groupType == 'Participant' &&
3420 !in_array($valueParts[0], $participantExtends)
3426 foreach ($valueParts as $val) {
3427 if (CRM_Utils_Rule
::integer($val)) {
3428 $values[$val] = $val;
3431 if (!empty($values)) {
3432 $typeName = substr($valueParts[0], 0, -4);
3433 if (in_array($valueParts[0], $participantExtends)) {
3434 $typeName = $valueParts[0];
3436 $groupTypeValue[$typeName] = $values;
3440 return $groupTypeValue;
3444 * @return bool|object
3446 public static function isProfileDoubleOptin() {
3447 // check for double optin
3448 $config = CRM_Core_Config
::singleton();
3449 if (in_array('CiviMail', $config->enableComponents
)) {
3450 return Civi
::settings()->get('profile_double_optin');
3456 * @return bool|object
3458 public static function isProfileAddToGroupDoubleOptin() {
3459 // check for add to group double optin
3460 $config = CRM_Core_Config
::singleton();
3461 if (in_array('CiviMail', $config->enableComponents
)) {
3462 return Civi
::settings()->get('profile_add_to_group_double_optin');
3468 * Get profiles used for batch entry.
3471 * profileIds profile ids
3473 public static function getBatchProfiles() {
3475 FROM civicrm_uf_group
3476 WHERE name IN ('contribution_batch_entry', 'membership_batch_entry')";
3477 $dao = CRM_Core_DAO
::executeQuery($query);
3479 while ($dao->fetch()) {
3480 $profileIds[$dao->id
] = $dao->id
;
3487 * @param $destination
3488 * @param bool $returnMultiSummaryFields
3490 * @return array|null
3491 * @todo what do I do?
3493 public static function shiftMultiRecordFields(&$source, &$destination, $returnMultiSummaryFields = FALSE) {
3494 $multiSummaryFields = $returnMultiSummaryFields ?
[] : NULL;
3495 foreach ($source as $field => $properties) {
3496 if (!CRM_Core_BAO_CustomField
::getKeyID($field)) {
3499 if (CRM_Core_BAO_CustomField
::isMultiRecordField($field)) {
3500 $destination[$field] = $properties;
3501 if ($returnMultiSummaryFields) {
3502 if ($properties['is_multi_summary']) {
3503 $multiSummaryFields[$field] = $properties;
3506 unset($source[$field]);
3509 return $multiSummaryFields;
3513 * This is function is used to format pseudo fields.
3515 * @param array $fields
3516 * Associated array of profile fields.
3519 public static function reformatProfileFields(&$fields) {
3520 //reformat fields array
3521 foreach ($fields as $name => $field) {
3522 //reformat phone and extension field
3523 if (substr($field['name'], 0, 13) == 'phone_and_ext') {
3524 $fieldSuffix = str_replace('phone_and_ext-', '', $field['name']);
3526 // retain existing element properties and just update and replace key
3527 CRM_Utils_Array
::crmReplaceKey($fields, $name, "phone-{$fieldSuffix}");
3528 $fields["phone-{$fieldSuffix}"]['name'] = "phone-{$fieldSuffix}";
3529 $fields["phone-{$fieldSuffix}"]['where'] = 'civicrm_phone.phone';
3531 // add additional phone extension field
3532 $fields["phone_ext-{$fieldSuffix}"] = $field;
3533 $fields["phone_ext-{$fieldSuffix}"]['title'] = $field['title'] . ' - ' . ts('Ext.');
3534 $fields["phone_ext-{$fieldSuffix}"]['name'] = "phone_ext-{$fieldSuffix}";
3535 $fields["phone_ext-{$fieldSuffix}"]['where'] = 'civicrm_phone.phone_ext';
3536 $fields["phone_ext-{$fieldSuffix}"]['skipDisplay'] = 1;
3537 //ignore required for extension field
3538 $fields["phone_ext-{$fieldSuffix}"]['is_required'] = 0;
3544 * Get the frontend_title for the profile, falling back on 'title' if none.
3546 * @param int $profileID
3550 * @throws \CiviCRM_API3_Exception
3552 public static function getFrontEndTitle(int $profileID) {
3553 $profile = civicrm_api3('UFGroup', 'getsingle', ['id' => $profileID, 'return' => ['title', 'frontend_title']]);
3554 return $profile['frontend_title'] ??
$profile['title'];
3558 * Format custom field value for use in prepopulating a quickform profile field.
3560 * @param array $field
3562 * @param string $value
3566 * String or array, depending on the html type
3568 private static function formatCustomValue($field, $value) {
3569 if (CRM_Core_BAO_CustomField
::isSerialized($field)) {
3570 $value = CRM_Utils_Array
::explodePadded($value);
3572 // This may not be required now.
3573 if ($field['html_type'] === 'CheckBox') {
3575 foreach (array_filter($value) as $item) {
3576 $checkboxes[$item] = 1;
3577 // CRM-2969 seems like we need this for QF style checkboxes in profile where its multiindexed
3578 $checkboxes["[{$item}]"] = 1;