3 +--------------------------------------------------------------------+
5 +--------------------------------------------------------------------+
6 | Copyright CiviCRM LLC (c) 2004-2019 |
7 +--------------------------------------------------------------------+
8 | This file is a part of CiviCRM. |
10 | CiviCRM is free software; you can copy, modify, and distribute it |
11 | under the terms of the GNU Affero General Public License |
12 | Version 3, 19 November 2007 and the CiviCRM Licensing Exception. |
14 | CiviCRM is distributed in the hope that it will be useful, but |
15 | WITHOUT ANY WARRANTY; without even the implied warranty of |
16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
17 | See the GNU Affero General Public License for more details. |
19 | You should have received a copy of the GNU Affero General Public |
20 | License and the CiviCRM Licensing Exception along |
21 | with this program; if not, contact CiviCRM LLC |
22 | at info[AT]civicrm[DOT]org. If you have questions about the |
23 | GNU Affero General Public License or the licensing of CiviCRM, |
24 | see the CiviCRM license FAQ at http://civicrm.org/licensing |
25 +--------------------------------------------------------------------+
31 * @copyright CiviCRM LLC (c) 2004-2019
37 class CRM_Core_BAO_UFGroup
extends CRM_Core_DAO_UFGroup
{
39 const PUBLIC_VISIBILITY
= 1,
41 LISTINGS_VISIBILITY
= 4;
44 * Cache the match clause used in this transaction.
48 public static $_matchFields = NULL;
51 * Fetch object based on array of properties.
53 * @param array $params
54 * (reference) an assoc array of name/value pairs.
55 * @param array $defaults
56 * (reference) an assoc array to hold the flattened values.
59 * CRM_Core_DAO_UFGroup object
61 public static function retrieve(&$params, &$defaults) {
62 return CRM_Core_DAO
::commonRetrieve('CRM_Core_DAO_UFGroup', $params, $defaults);
66 * Retrieve the first non-generic contact type
74 public static function getContactType($id) {
76 $validTypes = array_filter(array_keys(CRM_Core_SelectValues
::contactType()));
77 $validSubTypes = CRM_Contact_BAO_ContactType
::subTypeInfo();
79 $typesParts = explode(CRM_Core_DAO
::VALUE_SEPARATOR
, CRM_Core_DAO
::getFieldValue('CRM_Core_DAO_UFGroup', $id, 'group_type'));
80 $types = explode(',', $typesParts[0]);
83 foreach ($types as $type) {
84 if (in_array($type, $validTypes)) {
87 elseif (array_key_exists($type, $validSubTypes)) {
88 $cType = CRM_Utils_Array
::value('parent', $validSubTypes[$type]);
108 public static function getTitle($id) {
109 return CRM_Core_DAO
::getFieldValue('CRM_Core_DAO_UFGroup', $id, 'title');
113 * Update the is_active flag in the db.
116 * Id of the database record.
117 * @param bool $is_active
118 * Value we want to set the is_active field.
121 * true if we found and updated the object, else false
123 public static function setIsActive($id, $is_active) {
124 return CRM_Core_DAO
::setFieldValue('CRM_Core_DAO_UFGroup', $id, 'is_active', $is_active);
128 * Get all the registration fields.
131 * What action are we doing.
135 * @param string $ctype
138 * the fields that are needed for registration
142 public static function getRegistrationFields($action, $mode, $ctype = NULL) {
143 if ($mode & CRM_Profile_Form
::MODE_REGISTER
) {
144 $ufGroups = CRM_Core_BAO_UFGroup
::getModuleUFGroup('User Registration');
147 $ufGroups = CRM_Core_BAO_UFGroup
::getModuleUFGroup('Profile');
150 if (!is_array($ufGroups)) {
156 foreach ($ufGroups as $id => $title) {
158 $fieldType = CRM_Core_BAO_UFField
::getProfileType($id);
159 if (($fieldType != 'Contact') &&
160 ($fieldType != $ctype) &&
161 !CRM_Contact_BAO_ContactType
::isExtendsContactType($fieldType, $ctype)
165 if (CRM_Contact_BAO_ContactType
::isaSubType($fieldType)) {
166 $profileSubType = $fieldType;
170 $subset = self
::getFields($id, TRUE, $action,
171 NULL, NULL, FALSE, NULL, TRUE, $ctype
174 // we do not allow duplicates. the first field is the winner
175 foreach ($subset as $name => $field) {
176 if (empty($fields[$name])) {
177 $fields[$name] = $field;
186 * Get all the listing fields.
189 * What action are we doing.
190 * @param int $visibility
191 * Visibility of fields we are interested in.
192 * @param bool $considerSelector
193 * Whether to consider the in_selector parameter.
194 * @param array $ufGroupIds
195 * @param bool $searchable
197 * @param null $restrict
198 * @param bool $skipPermission
199 * @param int $permissionType
202 * the fields that are listings related
206 public static function getListingFields(
209 $considerSelector = FALSE,
213 $skipPermission = FALSE,
214 $permissionType = CRM_Core_Permission
::SEARCH
217 $subset = self
::getFields($ufGroupIds, FALSE, $action,
218 $visibility, $searchable,
224 if ($considerSelector) {
225 // drop the fields not meant for the selector
226 foreach ($subset as $name => $field) {
227 if (!$field['in_selector']) {
228 unset($subset[$name]);
235 $ufGroups = CRM_Core_PseudoConstant
::get('CRM_Core_DAO_UFField', 'uf_group_id');
238 foreach ($ufGroups as $id => $title) {
239 $subset = self
::getFields($id, FALSE, $action,
240 $visibility, $searchable,
246 if ($considerSelector) {
247 // drop the fields not meant for the selector
248 foreach ($subset as $name => $field) {
249 if (!$field['in_selector']) {
250 unset($subset[$name]);
254 $fields = array_merge($fields, $subset);
261 * Get all the fields that belong to the group with the name title,
262 * and format for use with buildProfile. This is the SQL analog of
266 * The id of the UF group or ids of ufgroup.
267 * @param bool|int $register are we interested in registration fields
269 * What action are we doing.
270 * @param int $visibility
271 * Visibility of fields we are interested in.
273 * @param bool $showAll
274 * @param string $restrict
275 * Should we restrict based on a specified profile type.
276 * @param bool $skipPermission
278 * @param int $permissionType
279 * @param string $orderBy
280 * @param null $orderProfiles
282 * @param bool $eventProfile
285 * The fields that belong to this ufgroup(s)
287 * @throws \CRM_Core_Exception
289 public static function getFields(
297 $skipPermission = FALSE,
299 $permissionType = CRM_Core_Permission
::CREATE
,
300 $orderBy = 'field_name',
301 $orderProfiles = NULL,
302 $eventProfile = FALSE
304 if (!is_array($id)) {
305 $id = CRM_Utils_Type
::escape($id, 'Positive');
312 $gids = implode(',', $profileIds);
315 $query = "SELECT g.* from civicrm_uf_group g
316 LEFT JOIN civicrm_uf_join j ON (j.uf_group_id = g.id)
317 WHERE g.id IN ( {$gids} )
318 AND ((j.uf_group_id IN ( {$gids} ) AND j.module = %1) OR g.is_reserved = 1 )
320 $params = [1 => [$restrict, 'String']];
323 $query = "SELECT g.* from civicrm_uf_group g WHERE g.id IN ( {$gids} ) ";
327 $query .= " AND g.is_active = 1";
332 'administer CiviCRM',
333 'manage event profiles',
336 if ($eventProfile && CRM_Core_Permission
::check($checkPermission)) {
337 $skipPermission = TRUE;
340 // add permissioning for profiles only if not registration
341 if (!$skipPermission) {
342 $permissionClause = CRM_Core_Permission
::ufGroupClause($permissionType, 'g.');
343 $query .= " AND $permissionClause ";
346 if ($orderProfiles and count($profileIds) > 1) {
347 $query .= " ORDER BY FIELD( g.id, {$gids} )";
349 $group = CRM_Core_DAO
::executeQuery($query, $params);
353 while ($group->fetch()) {
355 $query = self
::createUFFieldQuery($group->id
, $searchable, $showAll, $visibility, $orderBy);
356 $field = CRM_Core_DAO
::executeQuery($query);
358 $importableFields = self
::getProfileFieldMetadata($showAll);
359 list($customFields, $addressCustomFields) = self
::getCustomFields($ctype);
361 while ($field->fetch()) {
362 list($name, $formattedField) = self
::formatUFField($group, $field, $customFields, $addressCustomFields, $importableFields, $permissionType);
363 if ($formattedField !== NULL) {
364 $fields[$name] = $formattedField;
369 if (empty($fields) && !$validGroup) {
370 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.',
371 [1 => implode(',', $profileIds)]
375 self
::reformatProfileFields($fields);
382 * Format a list of UFFields for use with buildProfile. This is the in-memory analog
385 * @param array $groupArr
386 * (mimic CRM_UF_DAO_UFGroup).
387 * @param array $fieldArrs
388 * List of fields (each mimics CRM_UF_DAO_UFField).
389 * @param bool $visibility
390 * Visibility of fields we are interested in.
391 * @param bool $searchable
392 * @param bool $showAll
394 * @param int $permissionType
397 * @see self::getFields
399 public static function formatUFFields(
406 $permissionType = CRM_Core_Permission
::CREATE
408 // $group = new CRM_Core_DAO_UFGroup();
409 // $group->copyValues($groupArr); // no... converts string('') to string('null')
410 $group = (object) $groupArr;
412 // Refactoring note: The $fieldArrs here may be slightly different than the $ufFields
413 // used by calculateGroupType, but I don't think the missing fields matter, and -- if
414 // they did -- the obvious fix would produce mutual recursion.
415 $ufGroupType = self
::_calculateGroupType($fieldArrs);
416 $profileType = CRM_Core_BAO_UFField
::calculateProfileType(implode(',', $ufGroupType));
417 $contactActivityProfile = CRM_Core_BAO_UFField
::checkContactActivityProfileTypeByGroupType(implode(',', $ufGroupType));
418 $importableFields = self
::getImportableFields($showAll, $profileType, $contactActivityProfile);
419 list($customFields, $addressCustomFields) = self
::getCustomFields($ctype);
421 $formattedFields = [];
422 foreach ($fieldArrs as $fieldArr) {
423 $field = (object) $fieldArr;
424 if (!self
::filterUFField($field, $searchable, $showAll, $visibility)) {
428 list($name, $formattedField) = self
::formatUFField($group, $field, $customFields, $addressCustomFields, $importableFields, $permissionType);
429 if ($formattedField !== NULL) {
430 $formattedFields[$name] = $formattedField;
433 return $formattedFields;
437 * Prepare a field for rendering with CRM_Core_BAO_UFGroup::buildProfile.
439 * @param CRM_Core_DAO_UFGroup|CRM_Core_DAO $group
440 * @param CRM_Core_DAO_UFField|CRM_Core_DAO $field
441 * @param array $customFields
442 * @param array $addressCustomFields
443 * @param array $importableFields
444 * @param int $permissionType
445 * Eg CRM_Core_Permission::CREATE.
449 protected static function formatUFField(
453 $addressCustomFields,
455 $permissionType = CRM_Core_Permission
::CREATE
457 $name = $field->field_name
;
458 $title = $field->label
;
460 $addressCustom = FALSE;
461 if (in_array($permissionType, [CRM_Core_Permission
::CREATE
, CRM_Core_Permission
::EDIT
]) &&
462 in_array($field->field_name
, array_keys($addressCustomFields))
464 $addressCustom = TRUE;
465 $name = "address_{$name}";
467 if ($field->field_name
== 'url') {
468 $name .= "-{$field->website_type_id}";
470 elseif (!empty($field->location_type_id
)) {
471 $name .= "-{$field->location_type_id}";
474 $locationFields = self
::getLocationFields();
475 if (in_array($field->field_name
, $locationFields) ||
$addressCustom) {
480 if (isset($field->phone_type_id
)) {
481 $name .= "-{$field->phone_type_id}";
483 $fieldMetaData = CRM_Utils_Array
::value($name, $importableFields, (isset($importableFields[$field->field_name
]) ?
$importableFields[$field->field_name
] : []));
485 // No lie: this is bizarre; why do we need to mix so many UFGroup properties into UFFields?
486 // I guess to make field self sufficient with all the required data and avoid additional calls
489 'groupTitle' => $group->title
,
490 'groupName' => $group->name
,
491 'groupDisplayTitle' => (!empty($group->frontend_title
)) ?
$group->frontend_title
: $group->title
,
492 'groupHelpPre' => empty($group->help_pre
) ?
'' : $group->help_pre
,
493 'groupHelpPost' => empty($group->help_post
) ?
'' : $group->help_post
,
495 'where' => CRM_Utils_Array
::value('where', CRM_Utils_Array
::value($field->field_name
, $importableFields)),
496 'attributes' => CRM_Core_DAO
::makeAttribute(CRM_Utils_Array
::value($field->field_name
, $importableFields)),
497 'is_required' => $field->is_required
,
498 'is_view' => $field->is_view
,
499 'help_pre' => $field->help_pre
,
500 'help_post' => $field->help_post
,
501 'visibility' => $field->visibility
,
502 'in_selector' => $field->in_selector
,
503 'rule' => CRM_Utils_Array
::value('rule', CRM_Utils_Array
::value($field->field_name
, $importableFields)),
504 'location_type_id' => isset($field->location_type_id
) ?
$field->location_type_id
: NULL,
505 'website_type_id' => isset($field->website_type_id
) ?
$field->website_type_id
: NULL,
506 'phone_type_id' => isset($field->phone_type_id
) ?
$field->phone_type_id
: NULL,
507 'group_id' => $group->id
,
508 'add_to_group_id' => isset($group->add_to_group_id
) ?
$group->add_to_group_id
: NULL,
509 'add_captcha' => isset($group->add_captcha
) ?
$group->add_captcha
: NULL,
510 'field_type' => $field->field_type
,
511 'field_id' => $field->id
,
512 'pseudoconstant' => CRM_Utils_Array
::value(
514 CRM_Utils_Array
::value($field->field_name
, $importableFields)
516 // obsolete this when we remove the name / dbName discrepancy with gender/suffix/prefix
517 'dbName' => CRM_Utils_Array
::value(
519 CRM_Utils_Array
::value($field->field_name
, $importableFields)
522 'data_type' => CRM_Utils_Type
::getDataTypeFromFieldMetadata($fieldMetaData),
523 'bao' => CRM_Utils_Array
::value('bao', $fieldMetaData),
526 $formattedField = CRM_Utils_Date
::addDateMetadataToField($fieldMetaData, $formattedField);
528 //adding custom field property
529 if (substr($field->field_name
, 0, 6) == 'custom' ||
530 substr($field->field_name
, 0, 14) === 'address_custom'
532 // if field is not present in customFields, that means the user
533 // DOES NOT HAVE permission to access that field
534 if (array_key_exists($field->field_name
, $customFields)) {
535 $formattedField['is_search_range'] = $customFields[$field->field_name
]['is_search_range'];
537 $formattedField['options_per_line'] = $customFields[$field->field_name
]['options_per_line'];
538 $formattedField['html_type'] = $customFields[$field->field_name
]['html_type'];
540 if (CRM_Utils_Array
::value('html_type', $formattedField) == 'Select Date') {
541 $formattedField['date_format'] = $customFields[$field->field_name
]['date_format'];
542 $formattedField['time_format'] = $customFields[$field->field_name
]['time_format'];
543 $formattedField['is_datetime_field'] = TRUE;
544 $formattedField['smarty_view_format'] = CRM_Utils_Date
::getDateFieldViewFormat($formattedField['date_format']);
547 $formattedField['is_multi_summary'] = $field->is_multi_summary
;
548 return [$name, $formattedField];
551 $formattedField = NULL;
552 return [$name, $formattedField];
555 return [$name, $formattedField];
559 * Create a query to find all visible UFFields in a UFGroup.
561 * This is the SQL-variant of checkUFFieldDisplayable().
563 * @param int $groupId
564 * @param bool $searchable
565 * @param bool $showAll
566 * @param int $visibility
567 * @param string $orderBy
568 * Comma-delimited list of SQL columns.
572 protected static function createUFFieldQuery($groupId, $searchable, $showAll, $visibility, $orderBy) {
573 $where = " WHERE uf_group_id = {$groupId}";
576 $where .= " AND is_searchable = 1";
580 $where .= " AND is_active = 1";
585 if ($visibility & self
::PUBLIC_VISIBILITY
) {
586 $clause[] = 'visibility = "Public Pages"';
588 if ($visibility & self
::ADMIN_VISIBILITY
) {
589 $clause[] = 'visibility = "User and User Admin Only"';
591 if ($visibility & self
::LISTINGS_VISIBILITY
) {
592 $clause[] = 'visibility = "Public Pages and Listings"';
594 if (!empty($clause)) {
595 $where .= ' AND ( ' . implode(' OR ', $clause) . ' ) ';
599 $query = "SELECT * FROM civicrm_uf_field $where ORDER BY weight";
601 $query .= ", " . $orderBy;
608 * Create a query to find all visible UFFields in a UFGroup.
610 * This is the PHP in-memory variant of createUFFieldQuery().
612 * @param CRM_Core_DAO_UFField|CRM_Core_DAO $field
613 * @param bool $searchable
614 * @param bool $showAll
615 * @param int $visibility
618 * TRUE if field is displayable
620 protected static function filterUFField($field, $searchable, $showAll, $visibility) {
621 if ($searchable && $field->is_searchable
!= 1) {
625 if (!$showAll && $field->is_active
!= 1) {
630 $allowedVisibilities = [];
631 if ($visibility & self
::PUBLIC_VISIBILITY
) {
632 $allowedVisibilities[] = 'Public Pages';
634 if ($visibility & self
::ADMIN_VISIBILITY
) {
635 $allowedVisibilities[] = 'User and User Admin Only';
637 if ($visibility & self
::LISTINGS_VISIBILITY
) {
638 $allowedVisibilities[] = 'Public Pages and Listings';
640 // !empty($allowedVisibilities) seems silly to me, but it is equivalent to the pre-existing SQL
641 if (!empty($allowedVisibilities) && !in_array($field->visibility
, $allowedVisibilities)) {
650 * Get a list of filtered field metadata.
653 * @param $profileType
654 * @param $contactActivityProfile
655 * @param bool $filterMode
656 * Filter mode means you are using importable fields for filtering rather than just getting metadata.
657 * With filter mode = FALSE BOTH activity fields and component fields are returned.
658 * I can't see why you would ever want to use this function in filter mode as the component fields are
659 * still unfiltered. However, I feel scared enough to leave it as it is. I have marked this function as
660 * deprecated and am recommending the wrapper 'getProfileFieldMetadata' in order to try to
661 * send this confusion to history.
664 * @deprecated use getProfileFieldMetadata
667 protected static function getImportableFields($showAll, $profileType, $contactActivityProfile, $filterMode = TRUE) {
669 $importableFields = CRM_Contact_BAO_Contact
::importableFields('All', FALSE, FALSE, FALSE, TRUE, TRUE);
672 $importableFields = CRM_Contact_BAO_Contact
::importableFields('All', FALSE, TRUE, FALSE, TRUE, TRUE);
675 $activityFields = CRM_Activity_BAO_Activity
::getProfileFields();
676 $componentFields = CRM_Core_Component
::getQueryFields();
677 if ($filterMode == TRUE) {
678 if ($profileType == 'Activity' ||
$contactActivityProfile) {
679 $importableFields = array_merge($importableFields, $activityFields);
682 $importableFields = array_merge($importableFields, $componentFields);
686 $importableFields = array_merge($importableFields, $activityFields, $componentFields);
689 $importableFields['group']['title'] = ts('Group(s)');
690 $importableFields['group']['where'] = NULL;
691 $importableFields['tag']['title'] = ts('Tag(s)');
692 $importableFields['tag']['where'] = NULL;
693 return $importableFields;
697 * Get the metadata for all potential profile fields.
699 * @param bool $isIncludeInactive
700 * Should disabled fields be included.
703 * Field metadata for all fields that might potentially be in a profile.
705 protected static function getProfileFieldMetadata($isIncludeInactive) {
706 return self
::getImportableFields($isIncludeInactive, NULL, NULL, NULL, TRUE);
710 * Get the fields relating to locations.
714 public static function getLocationFields() {
715 static $locationFields = [
717 'supplemental_address_1',
718 'supplemental_address_2',
719 'supplemental_address_3',
722 'postal_code_suffix',
735 return $locationFields;
743 protected static function getCustomFields($ctype) {
744 static $customFieldCache = [];
745 if (!isset($customFieldCache[$ctype])) {
746 $customFields = CRM_Core_BAO_CustomField
::getFieldsForImport($ctype, FALSE, FALSE, FALSE, TRUE, TRUE);
748 // hack to add custom data for components
749 $components = ['Contribution', 'Participant', 'Membership', 'Activity', 'Case'];
750 foreach ($components as $value) {
751 $customFields = array_merge($customFields, CRM_Core_BAO_CustomField
::getFieldsForImport($value));
753 $addressCustomFields = CRM_Core_BAO_CustomField
::getFieldsForImport('Address');
754 $customFields = array_merge($customFields, $addressCustomFields);
755 $customFieldCache[$ctype] = [$customFields, $addressCustomFields];
757 return $customFieldCache[$ctype];
761 * Check the data validity.
764 * The user id that we are actually editing.
765 * @param string $name
766 * The machine-name of the group we are interested in.
767 * @param bool $register
769 * The action of the form.
771 * @pram boolean $register is this the registrtion form
773 * true if form is valid
775 public static function isValid($userID, $name, $register = FALSE, $action = NULL) {
777 $controller = new CRM_Core_Controller_Simple('CRM_Profile_Form_Dynamic',
778 ts('Dynamic Form Creator'),
781 $controller->set('id', $userID);
782 $controller->set('register', 1);
783 $controller->process();
784 return $controller->validate();
787 // make sure we have a valid group
788 $group = new CRM_Core_DAO_UFGroup();
790 $group->name
= $name;
792 if ($group->find(TRUE) && $userID) {
793 $controller = new CRM_Core_Controller_Simple('CRM_Profile_Form_Dynamic', ts('Dynamic Form Creator'), $action);
794 $controller->set('gid', $group->id
);
795 $controller->set('id', $userID);
796 $controller->set('register', 0);
797 $controller->process();
798 return $controller->validate();
805 * Get the html for the form that represents this particular group.
808 * The user id that we are actually editing.
809 * @param string $title
810 * The title of the group we are interested in.
812 * The action of the form.
813 * @param bool $register
814 * Is this the registration form.
816 * Should we reset the form?.
817 * @param int $profileID
818 * Do we have the profile ID?.
820 * @param bool $doNotProcess
824 * the html for the form on success, otherwise empty string
826 public static function getEditHTML(
833 $doNotProcess = FALSE,
838 $controller = new CRM_Core_Controller_Simple('CRM_Profile_Form_Dynamic',
839 ts('Dynamic Form Creator'),
842 if ($reset ||
$doNotProcess) {
843 // hack to make sure we do not process this form
844 $oldQFDefault = CRM_Utils_Array
::value('_qf_default',
847 unset($_POST['_qf_default']);
848 unset($_REQUEST['_qf_default']);
850 $controller->reset();
854 $controller->set('id', $userID);
855 $controller->set('register', 1);
856 $controller->set('skipPermission', 1);
857 $controller->set('ctype', $ctype);
858 $controller->process();
859 if ($doNotProcess ||
!empty($_POST)) {
860 $controller->validate();
862 $controller->setEmbedded(TRUE);
864 //CRM-5839 - though we want to process form, get the control back.
865 $controller->setSkipRedirection(($doNotProcess) ?
FALSE : TRUE);
869 // we are done processing so restore the POST/REQUEST vars
870 if (($reset ||
$doNotProcess) && $oldQFDefault) {
871 $_POST['_qf_default'] = $_REQUEST['_qf_default'] = $oldQFDefault;
874 $template = CRM_Core_Smarty
::singleton();
876 // Hide CRM error messages if they are displayed using drupal form_set_error.
877 if (!empty($_POST)) {
878 $template->assign('suppressForm', TRUE);
881 return trim($template->fetch('CRM/Profile/Form/Dynamic.tpl'));
885 // make sure we have a valid group
886 $group = new CRM_Core_DAO_UFGroup();
888 $group->title
= $title;
890 if ($group->find(TRUE)) {
891 $profileID = $group->id
;
896 // make sure profileID and ctype match if ctype exists
898 $profileType = CRM_Core_BAO_UFField
::getProfileType($profileID);
899 if (CRM_Contact_BAO_ContactType
::isaSubType($profileType)) {
900 $profileType = CRM_Contact_BAO_ContactType
::getBasicType($profileType);
903 if (($profileType != 'Contact') && ($profileType != $ctype)) {
908 $controller = new CRM_Core_Controller_Simple('CRM_Profile_Form_Dynamic',
909 ts('Dynamic Form Creator'),
913 $controller->reset();
915 $controller->set('gid', $profileID);
916 $controller->set('id', $userID);
917 $controller->set('register', 0);
918 $controller->set('skipPermission', 1);
920 $controller->set('ctype', $ctype);
922 $controller->process();
923 $controller->setEmbedded(TRUE);
925 //CRM-5846 - give the control back to drupal.
926 $controller->setSkipRedirection(($doNotProcess) ?
FALSE : TRUE);
929 $template = CRM_Core_Smarty
::singleton();
931 // Hide CRM error messages if they are displayed using drupal form_set_error.
932 if (!empty($_POST) && CRM_Core_Config
::singleton()->userFramework
== 'Drupal') {
933 if (arg(0) == 'user' ||
(arg(0) == 'admin' && arg(1) == 'people')) {
934 $template->assign('suppressForm', TRUE);
938 $templateFile = "CRM/Profile/Form/{$profileID}/Dynamic.tpl";
939 if (!$template->template_exists($templateFile)) {
940 $templateFile = 'CRM/Profile/Form/Dynamic.tpl';
942 return trim($template->fetch($templateFile));
945 $userEmail = CRM_Contact_BAO_Contact_Location
::getEmailDetails($userID);
947 // if post not empty then only proceed
948 if (!empty($_POST)) {
950 $config = CRM_Core_Config
::singleton();
951 $email = CRM_Utils_Array
::value('mail', $_POST);
953 if (CRM_Utils_Rule
::email($email) && ($email != $userEmail[1])) {
954 CRM_Core_BAO_UFMatch
::updateContactEmail($userID, $email);
963 * Given a contact id and a field set, return the values from the db.
966 * @param array $fields
967 * The profile fields of interest.
968 * @param array $values
969 * The values for the above fields.
970 * @param bool $searchable
972 * @param array $componentWhere
973 * Component condition.
974 * @param bool $absolute
975 * Return urls in absolute form (useful when sending an email).
976 * @param null $additionalWhereClause
980 public static function getValues(
981 $cid, &$fields, &$values,
982 $searchable = TRUE, $componentWhere = NULL,
983 $absolute = FALSE, $additionalWhereClause = NULL
985 if (empty($cid) && empty($componentWhere)) {
989 // get the contact details (hier)
990 $returnProperties = CRM_Contact_BAO_Contact
::makeHierReturnProperties($fields);
991 $params = $cid ?
[['contact_id', '=', $cid, 0, 0]] : [];
993 // add conditions specified by components. eg partcipant_id etc
994 if (!empty($componentWhere)) {
995 $params = array_merge($params, $componentWhere);
998 $query = new CRM_Contact_BAO_Query($params, $returnProperties, $fields);
1000 $details = $query->searchQuery(0, 0, NULL, FALSE, FALSE,
1001 FALSE, FALSE, FALSE, $additionalWhereClause);
1002 while ($details->fetch()) {
1007 $query->convertToPseudoNames($details);
1008 $config = CRM_Core_Config
::singleton();
1010 $locationTypes = CRM_Core_PseudoConstant
::get('CRM_Core_DAO_Address', 'location_type_id');
1011 $imProviders = CRM_Core_PseudoConstant
::get('CRM_Core_DAO_IM', 'provider_id');
1012 $websiteTypes = CRM_Core_PseudoConstant
::get('CRM_Core_DAO_Website', 'website_type_id');
1014 $multipleFields = ['url'];
1016 //start of code to set the default values
1017 foreach ($fields as $name => $field) {
1019 if ($name == 'id') {
1020 $name = 'contact_id';
1023 // skip fields that should not be displayed separately
1024 if (!empty($field['skipDisplay'])) {
1028 // Create a unique, non-empty index for each field.
1029 $index = $field['title'];
1030 if ($index === '') {
1033 while (array_key_exists($index, $values)) {
1037 $params[$index] = $values[$index] = '';
1038 $customFieldName = NULL;
1040 if (isset($details->$name) ||
$name == 'group' ||
$name == 'tag') {
1041 // to handle gender / suffix / prefix
1042 if (in_array(substr($name, 0, -3), ['gender', 'prefix', 'suffix'])) {
1043 $params[$index] = $details->$name;
1044 $values[$index] = $details->$name;
1046 elseif (in_array($name, CRM_Contact_BAO_Contact
::$_greetingTypes)) {
1047 $dname = $name . '_display';
1048 $values[$index] = $details->$dname;
1049 $name = $name . '_id';
1050 $params[$index] = $details->$name;
1052 elseif (in_array($name, [
1057 $values[$index] = $details->$name;
1058 $idx = $name . '_id';
1059 $params[$index] = $details->$idx;
1061 elseif ($name === 'preferred_language') {
1062 $params[$index] = $details->$name;
1063 $values[$index] = CRM_Core_PseudoConstant
::getLabel('CRM_Contact_DAO_Contact', 'preferred_language', $details->$name);
1065 elseif ($name == 'group') {
1066 $groups = CRM_Contact_BAO_GroupContact
::getContactGroup($cid, 'Added', NULL, FALSE, TRUE);
1069 foreach ($groups as $g) {
1070 // CRM-8362: User and User Admin visibility groups should be included in display if user has
1071 // VIEW permission on that group
1072 $groupPerm = CRM_Contact_BAO_Group
::checkPermission($g['group_id'], TRUE);
1074 if ($g['visibility'] != 'User and User Admin Only' ||
1075 CRM_Utils_Array
::key(CRM_Core_Permission
::VIEW
, $groupPerm)
1077 $title[] = $g['title'];
1078 if ($g['visibility'] == 'Public Pages') {
1079 $ids[] = $g['group_id'];
1083 $values[$index] = implode(', ', $title);
1084 $params[$index] = implode(',', $ids);
1086 elseif ($name == 'tag') {
1087 $entityTags = CRM_Core_BAO_EntityTag
::getTag($cid);
1088 $allTags = CRM_Core_PseudoConstant
::get('CRM_Core_DAO_EntityTag', 'tag_id', ['onlyActive' => FALSE]);
1090 foreach ($entityTags as $tagId) {
1091 $title[] = $allTags[$tagId];
1093 $values[$index] = implode(', ', $title);
1094 $params[$index] = implode(',', $entityTags);
1096 elseif ($name == 'activity_status_id') {
1097 $activityStatus = CRM_Core_PseudoConstant
::activityStatus();
1098 $values[$index] = $activityStatus[$details->$name];
1099 $params[$index] = $details->$name;
1101 elseif ($name == 'activity_date_time') {
1102 $values[$index] = CRM_Utils_Date
::customFormat($details->$name);
1103 $params[$index] = $details->$name;
1105 elseif ($name == 'contact_sub_type') {
1106 $contactSubTypeNames = explode(CRM_Core_DAO
::VALUE_SEPARATOR
, $details->$name);
1107 if (!empty($contactSubTypeNames)) {
1108 $contactSubTypeLabels = [];
1109 // get all contact subtypes
1110 $allContactSubTypes = CRM_Contact_BAO_ContactType
::subTypeInfo();
1111 // build contact subtype labels array
1112 foreach ($contactSubTypeNames as $cstName) {
1114 $contactSubTypeLabels[] = $allContactSubTypes[$cstName]['label'];
1117 $values[$index] = implode(',', $contactSubTypeLabels);
1120 $params[$index] = $details->$name;
1123 if (substr($name, 0, 7) === 'do_not_' ||
substr($name, 0, 3) === 'is_') {
1124 if ($details->$name) {
1125 $values[$index] = '[ x ]';
1129 if ($cfID = CRM_Core_BAO_CustomField
::getKeyID($name)) {
1130 $htmlType = $field['html_type'];
1132 // field_type is only set when we are retrieving profile values
1133 // when sending email, we call the same function to get custom field
1134 // values etc, i.e. emulating a profile
1135 $fieldType = CRM_Utils_Array
::value('field_type', $field);
1137 if ($htmlType == 'File') {
1140 $fieldType == 'Activity' && !empty($componentWhere[0][2])
1142 $entityId = $componentWhere[0][2];
1145 $fileURL = CRM_Core_BAO_CustomField
::getFileURL($entityId,
1149 $additionalWhereClause
1151 $params[$index] = $values[$index] = $fileURL['file_url'];
1155 if (isset($dao) && property_exists($dao, 'data_type') &&
1156 ($dao->data_type
== 'Int' ||
1157 $dao->data_type
== 'Boolean'
1160 $customVal = (int ) ($details->{$name});
1162 elseif (isset($dao) && property_exists($dao, 'data_type')
1163 && $dao->data_type
== 'Float'
1165 $customVal = (float ) ($details->{$name});
1167 elseif (!CRM_Utils_System
::isNull(explode(CRM_Core_DAO
::VALUE_SEPARATOR
,
1171 $customVal = $details->{$name};
1175 if (CRM_Utils_System
::isNull($customVal)) {
1179 $params[$index] = $customVal;
1180 $values[$index] = CRM_Core_BAO_CustomField
::displayValue($customVal, $cfID);
1181 if ($field['data_type'] == 'ContactReference') {
1182 $params[$index] = $values[$index];
1184 if (CRM_Core_DAO
::getFieldValue('CRM_Core_DAO_CustomField',
1185 $cfID, 'is_search_range'
1188 $customFieldName = "{$name}_from";
1192 elseif ($name == 'image_URL') {
1193 list($width, $height) = getimagesize(CRM_Utils_String
::unstupifyUrl($details->$name));
1194 list($thumbWidth, $thumbHeight) = CRM_Contact_BAO_Contact
::getThumbSize($width, $height);
1196 $image_URL = '<img src="' . $details->$name . '" height= ' . $thumbHeight . ' width= ' . $thumbWidth . ' />';
1197 $values[$index] = "<a href='#' onclick='contactImagePopUp(\"{$details->$name}\", {$width}, {$height});'>{$image_URL}</a>";
1199 elseif (in_array($name, [
1203 // @todo this set should be determined from metadata, not hard-coded.
1204 $values[$index] = CRM_Utils_Date
::customFormat($details->$name);
1205 $params[$index] = CRM_Utils_Date
::isoToMysql($details->$name);
1209 if ($index == 'Campaign') {
1210 $dao = 'CRM_Campaign_DAO_Campaign';
1212 elseif ($index == 'Contribution Page') {
1213 $dao = 'CRM_Contribute_DAO_ContributionPage';
1216 $value = CRM_Core_DAO
::getFieldValue($dao, $details->$name, 'title');
1219 $value = $details->$name;
1221 $values[$index] = $value;
1226 elseif (strpos($name, '-') !== FALSE) {
1227 list($fieldName, $id, $type) = CRM_Utils_System
::explode('-', $name, 3);
1229 if (!in_array($fieldName, $multipleFields)) {
1230 if ($id == 'Primary') {
1232 // not sure why we'd every use Primary location type id
1233 // we need to fix the source if we are using it
1234 // $locationTypeName = CRM_Contact_BAO_Contact::getPrimaryLocationType( $cid );
1235 $locationTypeName = 1;
1238 $locationTypeName = CRM_Utils_Array
::value($id, $locationTypes);
1241 if (!$locationTypeName) {
1245 $detailName = "{$locationTypeName}-{$fieldName}";
1246 $detailName = str_replace(' ', '_', $detailName);
1248 if (in_array($fieldName, [
1255 $detailName .= "-{$type}";
1259 if (in_array($fieldName, [
1264 $values[$index] = $details->$detailName;
1265 $idx = $detailName . '_id';
1266 $params[$index] = $details->$idx;
1268 elseif ($fieldName == 'im') {
1269 $providerId = $detailName . '-provider_id';
1270 if (isset($imProviders[$details->$providerId])) {
1271 $values[$index] = $details->$detailName . " (" . $imProviders[$details->$providerId] . ")";
1274 $values[$index] = $details->$detailName;
1276 $params[$index] = $details->$detailName;
1278 elseif ($fieldName == 'phone') {
1279 $phoneExtField = str_replace('phone', 'phone_ext', $detailName);
1280 if (isset($details->$phoneExtField)) {
1281 $values[$index] = $details->$detailName . " (" . $details->$phoneExtField . ")";
1284 $values[$index] = $details->$detailName;
1286 $params[$index] = $details->$detailName;
1289 $values[$index] = $params[$index] = $details->$detailName;
1293 $detailName = "website-{$id}-{$fieldName}";
1294 $url = CRM_Utils_System
::fixURL($details->$detailName);
1295 if ($details->$detailName) {
1296 $websiteTypeId = "website-{$id}-website_type_id";
1297 $websiteType = $websiteTypes[$details->$websiteTypeId];
1298 $values[$index] = "<a href=\"$url\">{$details->$detailName} ( {$websiteType} )</a>";
1301 $values[$index] = '';
1306 if ((CRM_Utils_Array
::value('visibility', $field) == 'Public Pages and Listings') &&
1307 CRM_Core_Permission
::check('profile listings and forms')
1310 if (CRM_Utils_System
::isNull($params[$index])) {
1311 $params[$index] = $values[$index];
1313 if (!isset($params[$index])) {
1316 if (!$customFieldName) {
1317 $fieldName = $field['name'];
1320 $fieldName = $customFieldName;
1324 if (CRM_Core_BAO_CustomField
::getKeyID($field['name'])) {
1325 $htmlType = $field['html_type'];
1326 if ($htmlType == 'Link') {
1327 $url = $params[$index];
1329 elseif (in_array($htmlType, [
1332 'Multi-Select State/Province',
1333 'Multi-Select Country',
1335 $valSeperator = CRM_Core_DAO
::VALUE_SEPARATOR
;
1336 $selectedOptions = explode($valSeperator, $params[$index]);
1338 foreach ($selectedOptions as $key => $multiOption) {
1340 $url[] = CRM_Utils_System
::url('civicrm/profile',
1341 'reset=1&force=1&gid=' . $field['group_id'] . '&' .
1342 urlencode($fieldName) .
1344 urlencode($multiOption)
1350 $url = CRM_Utils_System
::url('civicrm/profile',
1351 'reset=1&force=1&gid=' . $field['group_id'] . '&' .
1352 urlencode($fieldName) .
1354 urlencode($params[$index])
1359 $url = CRM_Utils_System
::url('civicrm/profile',
1360 'reset=1&force=1&gid=' . $field['group_id'] . '&' .
1361 urlencode($fieldName) .
1363 urlencode($params[$index])
1368 !empty($values[$index]) &&
1372 if (is_array($url) && !empty($url)) {
1374 $eachMultiValue = explode(', ', $values[$index]);
1375 foreach ($eachMultiValue as $key => $valueLabel) {
1376 $links[] = '<a href="' . $url[$key] . '">' . $valueLabel . '</a>';
1378 $values[$index] = implode(', ', $links);
1381 $values[$index] = '<a href="' . $url . '">' . $values[$index] . '</a>';
1389 * Check if profile Group used by any module.
1397 public static function usedByModule($id) {
1398 //check whether this group is used by any module(check uf join records)
1400 FROM civicrm_uf_join
1401 WHERE civicrm_uf_join.uf_group_id=$id";
1403 $dao = new CRM_Core_DAO();
1405 if ($dao->fetch()) {
1414 * Delete the profile Group.
1422 public static function del($id) {
1423 //check whether this group contains any profile fields
1424 $profileField = new CRM_Core_DAO_UFField();
1425 $profileField->uf_group_id
= $id;
1426 $profileField->find();
1427 while ($profileField->fetch()) {
1428 CRM_Core_BAO_UFField
::del($profileField->id
);
1431 //delete records from uf join table
1432 $ufJoin = new CRM_Core_DAO_UFJoin();
1433 $ufJoin->uf_group_id
= $id;
1436 //delete profile group
1437 $group = new CRM_Core_DAO_UFGroup();
1446 * @param array $params
1447 * Reference array contains the values submitted by the form.
1449 * Reference array contains the id.
1454 public static function add(&$params, $ids = []) {
1464 foreach ($fields as $field) {
1465 $params[$field] = CRM_Utils_Array
::value($field, $params, FALSE);
1468 $params['limit_listings_group_id'] = CRM_Utils_Array
::value('group', $params);
1469 $params['add_to_group_id'] = CRM_Utils_Array
::value('add_contact_to_group', $params);
1472 if (!empty($params['group_type']) && is_array($params['group_type'])) {
1473 $params['group_type'] = implode(',', $params['group_type']);
1475 $ufGroup = new CRM_Core_DAO_UFGroup();
1476 $ufGroup->copyValues($params);
1478 $ufGroupID = CRM_Utils_Array
::value('ufgroup', $ids, CRM_Utils_Array
::value('id', $params));
1479 if (!$ufGroupID && empty($params['name'])) {
1480 $ufGroup->name
= CRM_Utils_String
::munge($ufGroup->title
, '_', 56);
1482 $ufGroup->id
= $ufGroupID;
1486 if (!$ufGroupID && empty($params['name'])) {
1487 $ufGroup->name
= $ufGroup->name
. "_{$ufGroup->id}";
1495 * Make uf join entries for an uf group.
1497 * @param array $params
1498 * (reference) an assoc array of name/value pairs.
1499 * @param int $ufGroupId
1502 public static function createUFJoin(&$params, $ufGroupId) {
1503 $groupTypes = CRM_Utils_Array
::value('uf_group_type', $params);
1505 // get ufjoin records for uf group
1506 $ufGroupRecord = CRM_Core_BAO_UFGroup
::getUFJoinRecord($ufGroupId);
1508 // get the list of all ufgroup types
1509 $allUFGroupType = CRM_Core_SelectValues
::ufGroupTypes();
1511 // this fix is done to prevent warning generated by array_key_exits incase of empty array is given as input
1512 if (!is_array($groupTypes)) {
1516 // this fix is done to prevent warning generated by array_key_exits incase of empty array is given as input
1517 if (!is_array($ufGroupRecord)) {
1518 $ufGroupRecord = [];
1521 // check which values has to be inserted/deleted for contact
1522 $menuRebuild = FALSE;
1523 foreach ($allUFGroupType as $key => $value) {
1525 $joinParams['uf_group_id'] = $ufGroupId;
1526 $joinParams['module'] = $key;
1527 if ($key == 'User Account') {
1528 $menuRebuild = TRUE;
1530 if (array_key_exists($key, $groupTypes) && !in_array($key, $ufGroupRecord)) {
1531 // insert a new record
1532 CRM_Core_BAO_UFGroup
::addUFJoin($joinParams);
1534 elseif (!array_key_exists($key, $groupTypes) && in_array($key, $ufGroupRecord)) {
1535 // delete a record for existing ufgroup
1536 CRM_Core_BAO_UFGroup
::delUFJoin($joinParams);
1542 UPDATE civicrm_uf_join
1544 WHERE uf_group_id = %2
1545 AND ( entity_id IS NULL OR entity_id <= 0 )
1548 1 => [$params['weight'], 'Integer'],
1549 2 => [$ufGroupId, 'Integer'],
1551 CRM_Core_DAO
::executeQuery($query, $p);
1553 // Do a menu rebuild, so it gets all the new menu entries for user account
1555 $config = CRM_Core_Config
::singleton();
1556 $config->userSystem
->updateCategories();
1561 * Get the UF Join records for an ufgroup id.
1563 * @param int $ufGroupId
1565 * @param int $displayName
1566 * If set return display name in array.
1567 * @param int $status
1568 * If set return module other than default modules (User Account/User registration/Profile).
1573 public static function getUFJoinRecord($ufGroupId = NULL, $displayName = NULL, $status = NULL) {
1576 $UFGroupType = CRM_Core_SelectValues
::ufGroupTypes();
1580 $dao = new CRM_Core_DAO_UFJoin();
1583 $dao->uf_group_id
= $ufGroupId;
1589 while ($dao->fetch()) {
1590 if (!$displayName) {
1591 $ufJoin[$dao->id
] = $dao->module
;
1594 if (isset($UFGroupType[$dao->module
])) {
1595 // skip the default modules
1597 $ufJoin[$dao->id
] = $UFGroupType[$dao->module
];
1599 // added for CRM-1475
1601 elseif (!CRM_Utils_Array
::key($dao->module
, $ufJoin)) {
1602 $ufJoin[$dao->id
] = $dao->module
;
1610 * Function takes an associative array and creates a ufjoin record for ufgroup.
1612 * @param array $params
1613 * (reference) an assoc array of name/value pairs.
1615 * @return CRM_Core_BAO_UFJoin
1617 public static function addUFJoin(&$params) {
1618 $ufJoin = new CRM_Core_DAO_UFJoin();
1619 $ufJoin->copyValues($params);
1625 * Delete the uf join record for an uf group.
1627 * @param array $params
1628 * (reference) an assoc array of name/value pairs.
1630 public static function delUFJoin(&$params) {
1631 $ufJoin = new CRM_Core_DAO_UFJoin();
1632 $ufJoin->copyValues($params);
1637 * Get the weight for ufjoin record.
1639 * @param int $ufGroupId
1640 * If $ufGroupId get update weight or add weight.
1643 * weight of the UFGroup
1645 public static function getWeight($ufGroupId = NULL) {
1646 //calculate the weight
1649 $queryString = "SELECT ( MAX(civicrm_uf_join.weight)+1) as new_weight
1650 FROM civicrm_uf_join
1651 WHERE module = 'User Registration' OR module = 'User Account' OR module = 'Profile'";
1654 $queryString = "SELECT MAX(civicrm_uf_join.weight) as new_weight
1655 FROM civicrm_uf_join
1656 WHERE civicrm_uf_join.uf_group_id = %1
1657 AND ( entity_id IS NULL OR entity_id <= 0 )";
1658 $p[1] = [$ufGroupId, 'Integer'];
1661 $dao = CRM_Core_DAO
::executeQuery($queryString, $p);
1663 return ($dao->new_weight
) ?
$dao->new_weight
: 1;
1667 * Get the uf group for a module.
1669 * @param string $moduleName
1672 * No to increment the weight.
1673 * @param bool $skipPermission
1675 * Which operation (view, edit, create, etc) to check permission for.
1676 * @param array|NULL $returnFields list of UFGroup fields to return; NULL for default
1679 * array of ufgroups for a module
1681 public static function getModuleUFGroup($moduleName = NULL, $count = 0, $skipPermission = TRUE, $op = CRM_Core_Permission
::VIEW
, $returnFields = NULL) {
1682 $selectFields = ['id', 'title', 'created_id', 'is_active', 'is_reserved', 'group_type'];
1684 if (CRM_Core_BAO_SchemaHandler
::checkIfFieldExists('civicrm_uf_group', 'description')) {
1685 // CRM-13555, since description field was added later (4.4), and to avoid any problems with upgrade
1686 $selectFields[] = 'description';
1689 if (CRM_Core_BAO_SchemaHandler
::checkIfFieldExists('civicrm_uf_group', 'frontend_title')) {
1690 $selectFields[] = 'frontend_title';
1693 if (!empty($returnFields)) {
1694 $selectFields = array_merge($returnFields, array_diff($selectFields, $returnFields));
1697 $queryString = 'SELECT civicrm_uf_group.' . implode(', civicrm_uf_group.', $selectFields) . '
1698 FROM civicrm_uf_group
1699 LEFT JOIN civicrm_uf_join ON (civicrm_uf_group.id = uf_group_id)';
1702 $queryString .= ' AND civicrm_uf_group.is_active = 1
1703 WHERE civicrm_uf_join.module = %2';
1704 $p[2] = [$moduleName, 'String'];
1707 // add permissioning for profiles only if not registration
1708 if (!$skipPermission) {
1709 $permissionClause = CRM_Core_Permission
::ufGroupClause($op, 'civicrm_uf_group.');
1710 if (strpos($queryString, 'WHERE') !== FALSE) {
1711 $queryString .= " AND $permissionClause ";
1714 $queryString .= " $permissionClause ";
1718 $queryString .= ' ORDER BY civicrm_uf_join.weight, civicrm_uf_group.title';
1719 $dao = CRM_Core_DAO
::executeQuery($queryString, $p);
1722 while ($dao->fetch()) {
1723 //skip mix profiles in user Registration / User Account
1724 if (($moduleName === 'User Registration' ||
$moduleName === 'User Account') &&
1725 CRM_Core_BAO_UFField
::checkProfileType($dao->id
)
1729 foreach ($selectFields as $key => $field) {
1730 if ($field === 'id') {
1733 $ufGroups[$dao->id
][$field] = $dao->$field;
1737 // Allow other modules to alter/override the UFGroups.
1738 CRM_Utils_Hook
::buildUFGroupsForModule($moduleName, $ufGroups);
1744 * Filter ufgroups based on logged in user contact type.
1746 * @param int $ufGroupId
1747 * Uf group id (profile id).
1748 * @param int $contactID
1753 public static function filterUFGroups($ufGroupId, $contactID = NULL) {
1755 $session = CRM_Core_Session
::singleton();
1756 $contactID = $session->get('userID');
1760 //get the contact type
1761 $contactType = CRM_Contact_BAO_Contact
::getContactType($contactID);
1763 //match if exixting contact type is same as profile contact type
1764 $profileType = CRM_Core_BAO_UFField
::getProfileType($ufGroupId);
1766 if (CRM_Contact_BAO_ContactType
::isaSubType($profileType)) {
1767 $profileType = CRM_Contact_BAO_ContactType
::getBasicType($profileType);
1769 //in some cases getBasicType() returns a cached array instead of string. Example: array ('sponsor' => 'organization')
1770 if (is_array($profileType)) {
1771 $profileType = array_shift($profileType);
1775 //allow special mix profiles for Contribution and Participant
1776 $specialProfiles = ['Contribution', 'Participant', 'Membership'];
1778 if (in_array($profileType, $specialProfiles)) {
1782 if (($contactType == $profileType) ||
$profileType == 'Contact') {
1791 * Add profile field to a form.
1793 * @param CRM_Core_Form $form
1794 * @param array $field
1798 * @param int $contactId
1799 * @param bool $online
1800 * @param string $usedFor
1801 * For building up prefixed fieldname for special cases (e.g. onBehalf, Honor).
1802 * @param int $rowNumber
1803 * @param string $prefix
1807 public static function buildProfile(
1817 $defaultValues = [];
1818 $fieldName = $field['name'];
1819 $title = $field['title'];
1820 $attributes = $field['attributes'];
1821 $rule = $field['rule'];
1822 $view = $field['is_view'];
1823 $required = ($mode == CRM_Profile_Form
::MODE_SEARCH
) ?
FALSE : $field['is_required'];
1824 $search = ($mode == CRM_Profile_Form
::MODE_SEARCH
) ?
TRUE : FALSE;
1825 $isShared = CRM_Utils_Array
::value('is_shared', $field, 0);
1827 // do not display view fields in drupal registration form
1829 if ($view && $mode == CRM_Profile_Form
::MODE_REGISTER
) {
1833 if ($usedFor == 'onbehalf') {
1834 $name = "onbehalf[$fieldName]";
1836 elseif ($usedFor == 'honor') {
1837 $name = "honor[$fieldName]";
1839 elseif ($contactId && !$online) {
1840 $name = "field[$contactId][$fieldName]";
1842 elseif ($rowNumber) {
1843 $name = "field[$rowNumber][$fieldName]";
1845 elseif (!empty($prefix)) {
1846 $name = $prefix . "[$fieldName]";
1852 $selectAttributes = ['class' => 'crm-select2', 'placeholder' => TRUE];
1854 if ($fieldName == 'image_URL' && $mode == CRM_Profile_Form
::MODE_EDIT
) {
1855 $deleteExtra = json_encode(ts('Are you sure you want to delete contact image.'));
1857 CRM_Core_Action
::DELETE
=> [
1858 'name' => ts('Delete Contact Image'),
1859 'url' => 'civicrm/contact/image',
1860 'qs' => 'reset=1&id=%%id%%&gid=%%gid%%&action=delete',
1861 'extra' => 'onclick = "' . htmlspecialchars("if (confirm($deleteExtra)) this.href+='&confirmed=1'; else return false;") . '"',
1864 $deleteURL = CRM_Core_Action
::formLink($deleteURL,
1865 CRM_Core_Action
::DELETE
,
1867 'id' => $form->get('id'),
1868 'gid' => $form->get('gid'),
1872 'contact.profileimage.delete',
1876 $form->assign('deleteURL', $deleteURL);
1878 $addressOptions = CRM_Core_BAO_Setting
::valueOptions(CRM_Core_BAO_Setting
::SYSTEM_PREFERENCES_NAME
,
1879 'address_options', TRUE, NULL, TRUE
1882 if (substr($fieldName, 0, 14) === 'state_province') {
1883 $form->addChainSelect($name, ['label' => $title, 'required' => $required]);
1884 $config = CRM_Core_Config
::singleton();
1885 if (!in_array($mode, [CRM_Profile_Form
::MODE_EDIT
, CRM_Profile_Form
::MODE_SEARCH
]) &&
1886 $config->defaultContactStateProvince
1888 $defaultValues[$name] = $config->defaultContactStateProvince
;
1889 $form->setDefaults($defaultValues);
1892 elseif (substr($fieldName, 0, 7) === 'country') {
1893 $form->add('select', $name, $title, ['' => ts('- select -')] + CRM_Core_PseudoConstant
::country(), $required, $selectAttributes);
1894 $config = CRM_Core_Config
::singleton();
1895 if (!in_array($mode, [CRM_Profile_Form
::MODE_EDIT
, CRM_Profile_Form
::MODE_SEARCH
]) &&
1896 $config->defaultContactCountry
1898 $defaultValues[$name] = $config->defaultContactCountry
;
1899 $form->setDefaults($defaultValues);
1902 elseif (substr($fieldName, 0, 6) === 'county') {
1903 if ($addressOptions['county']) {
1904 $form->addChainSelect($name, ['label' => $title, 'required' => $required]);
1907 elseif (substr($fieldName, 0, 9) === 'image_URL') {
1908 $form->add('file', $name, $title, $attributes, $required);
1909 $form->addUploadElement($name);
1911 elseif (substr($fieldName, 0, 2) === 'im') {
1912 $form->add('text', $name, $title, $attributes, $required);
1915 if (substr($name, -1) === ']') {
1916 $providerName = substr($name, 0, -1) . '-provider_id]';
1918 $form->add('select', $providerName, NULL,
1920 '' => ts('- select -'),
1921 ] + CRM_Core_PseudoConstant
::get('CRM_Core_DAO_IM', 'provider_id'), $required
1925 $form->add('select', $name . '-provider_id', $title,
1927 '' => ts('- select -'),
1928 ] + CRM_Core_PseudoConstant
::get('CRM_Core_DAO_IM', 'provider_id'), $required
1932 if ($view && $mode != CRM_Profile_Form
::MODE_SEARCH
) {
1933 $form->freeze($name . '-provider_id');
1937 elseif (CRM_Utils_Array
::value('name', $field) == 'membership_type') {
1938 list($orgInfo, $types) = CRM_Member_BAO_MembershipType
::getMembershipTypeInfo();
1939 $sel = &$form->addElement('hierselect', $name, $title);
1940 $select = ['' => ts('- select -')];
1941 if (count($orgInfo) == 1 && $field['is_required']) {
1942 // we only have one org - so we should default to it. Not sure about defaulting to first type
1943 // as it could be missed - so adding a select
1944 // however, possibly that is more similar to the membership form
1945 if (count($types[1]) > 1) {
1946 $types[1] = $select +
$types[1];
1950 $orgInfo = $select +
$orgInfo;
1952 $sel->setOptions([$orgInfo, $types]);
1954 elseif (CRM_Utils_Array
::value('name', $field) == 'membership_status') {
1955 $form->add('select', $name, $title,
1957 '' => ts('- select -'),
1958 ] + CRM_Member_PseudoConstant
::membershipStatus(NULL, NULL, 'label'), $required
1961 elseif (in_array($fieldName, ['gender_id', 'communication_style_id'])) {
1963 $pseudoValues = CRM_Core_PseudoConstant
::get('CRM_Contact_DAO_Contact', $fieldName);
1964 foreach ($pseudoValues as $key => $var) {
1965 $options[$key] = $form->createElement('radio', NULL, ts($title), $var, $key);
1967 $group = $form->addGroup($options, $name, $title);
1969 $form->addRule($name, ts('%1 is a required field.', [1 => $title]), 'required');
1972 $group->setAttribute('allowClear', TRUE);
1975 elseif ($fieldName === 'prefix_id' ||
$fieldName === 'suffix_id') {
1976 $form->addSelect($name, [
1978 'entity' => 'contact',
1979 'field' => $fieldName,
1981 'placeholder' => '',
1984 elseif ($fieldName === 'contact_sub_type') {
1985 $gId = $form->get('gid') ?
$form->get('gid') : CRM_Utils_Array
::value('group_id', $field);
1986 if ($usedFor == 'onbehalf') {
1987 $profileType = 'Organization';
1989 elseif ($usedFor == 'honor') {
1990 $profileType = CRM_Core_BAO_UFField
::getProfileType($form->_params
['honoree_profile_id']);
1993 $profileType = $gId ? CRM_Core_BAO_UFField
::getProfileType($gId) : NULL;
1994 if ($profileType == 'Contact') {
1995 $profileType = 'Individual';
1999 $setSubtype = FALSE;
2000 if (CRM_Contact_BAO_ContactType
::isaSubType($profileType)) {
2001 $setSubtype = $profileType;
2002 $profileType = CRM_Contact_BAO_ContactType
::getBasicType($profileType);
2005 $subtypes = $profileType ? CRM_Contact_BAO_ContactType
::subTypePairs($profileType) : [];
2009 $subtypeList[$setSubtype] = $subtypes[$setSubtype];
2012 $subtypeList = $subtypes;
2015 $form->add('select', $name, $title, $subtypeList, $required, ['class' => 'crm-select2', 'multiple' => TRUE]);
2017 elseif (in_array($fieldName, CRM_Contact_BAO_Contact
::$_greetingTypes)) {
2018 // Get contact type for greeting selector
2019 $gId = $form->get('gid') ?
: CRM_Utils_Array
::value('group_id', $field);
2020 $profileType = CRM_Core_BAO_UFField
::getProfileType($gId, TRUE, FALSE, TRUE);
2022 if (!$profileType ||
in_array($profileType, ['Contact', 'Contribution', 'Participant', 'Membership'])) {
2023 $profileType = ($profileType == 'Contact' && $form->get('id')) ? CRM_Contact_BAO_Contact
::getContactType($form->get('id')) : 'Individual';
2025 if (CRM_Contact_BAO_ContactType
::isaSubType($profileType)) {
2026 $profileType = CRM_Contact_BAO_ContactType
::getBasicType($profileType);
2029 'contact_type' => $profileType,
2030 'greeting_type' => $fieldName,
2032 $form->add('select', $name, $title, ['' => ts('- select -')] + CRM_Core_PseudoConstant
::greeting($greeting), $required);
2033 // add custom greeting element
2034 $form->add('text', $fieldName . '_custom', ts('Custom %1', [1 => ucwords(str_replace('_', ' ', $fieldName))]),
2038 elseif ($fieldName === 'preferred_communication_method') {
2039 $communicationFields = CRM_Core_PseudoConstant
::get('CRM_Contact_DAO_Contact', 'preferred_communication_method');
2040 foreach ($communicationFields as $key => $var) {
2044 $communicationOptions[] = $form->createElement('checkbox', $key, NULL, $var);
2046 $form->addGroup($communicationOptions, $name, $title, '<br/>');
2048 elseif ($fieldName === 'preferred_mail_format') {
2049 $form->add('select', $name, $title, CRM_Core_SelectValues
::pmf());
2051 elseif ($fieldName === 'preferred_language') {
2052 $form->add('select', $name, $title, ['' => ts('- select -')] + CRM_Contact_BAO_Contact
::buildOptions('preferred_language'));
2054 elseif ($fieldName == 'external_identifier') {
2055 $form->add('text', $name, $title, $attributes, $required);
2056 $contID = $contactId;
2058 $contID = $form->get('id');
2060 $form->addRule($name,
2061 ts('External ID already exists in Database.'),
2063 ['CRM_Contact_DAO_Contact', $contID, 'external_identifier']
2066 elseif ($fieldName === 'group') {
2067 CRM_Contact_Form_Edit_TagsAndGroups
::buildQuickForm($form, $contactId,
2068 CRM_Contact_Form_Edit_TagsAndGroups
::GROUP
,
2073 elseif ($fieldName === 'tag') {
2074 CRM_Contact_Form_Edit_TagsAndGroups
::buildQuickForm($form, $contactId,
2075 CRM_Contact_Form_Edit_TagsAndGroups
::TAG
,
2080 elseif (substr($fieldName, 0, 4) === 'url-') {
2081 $form->add('text', $name, $title, CRM_Core_DAO
::getAttribute('CRM_Core_DAO_Website', 'url'), $required);
2082 $form->addRule($name, ts('Enter a valid web address beginning with \'http://\' or \'https://\'.'), 'url');
2084 // Note should be rendered as textarea
2085 elseif (substr($fieldName, -4) == 'note') {
2086 $form->add('textarea', $name, $title, $attributes, $required);
2088 elseif (substr($fieldName, 0, 6) === 'custom') {
2089 $customFieldID = CRM_Core_BAO_CustomField
::getKeyID($fieldName);
2090 if ($customFieldID) {
2091 CRM_Core_BAO_CustomField
::addQuickFormElement($form, $name, $customFieldID, $required, $search, $title);
2094 elseif (substr($fieldName, 0, 14) === 'address_custom') {
2095 list($fName, $locTypeId) = CRM_Utils_System
::explode('-', $fieldName, 2);
2096 $customFieldID = CRM_Core_BAO_CustomField
::getKeyID(substr($fName, 8));
2097 if ($customFieldID) {
2098 CRM_Core_BAO_CustomField
::addQuickFormElement($form, $name, $customFieldID, $required, $search, $title);
2101 elseif ($fieldName == 'send_receipt') {
2102 $form->addElement('checkbox', $name, $title);
2104 elseif ($fieldName == 'soft_credit') {
2105 $form->addEntityRef("soft_credit_contact_id[$rowNumber]", ts('Soft Credit To'), ['create' => TRUE]);
2106 $form->addMoney("soft_credit_amount[{$rowNumber}]", ts('Amount'), FALSE, NULL, FALSE);
2108 elseif ($fieldName === 'product_name') {
2109 list($products, $options) = CRM_Contribute_BAO_Premium
::getPremiumProductInfo();
2110 $sel = &$form->addElement('hierselect', $name, $title);
2111 $products = ['0' => ts('- select -')] +
$products;
2112 $sel->setOptions([$products, $options]);
2114 elseif ($fieldName === 'payment_instrument') {
2115 $form->add('select', $name, $title,
2116 ['' => ts('- select -')] + CRM_Contribute_PseudoConstant
::paymentInstrument(), $required);
2118 elseif ($fieldName === 'financial_type') {
2119 $form->add('select', $name, $title,
2121 '' => ts('- select -'),
2122 ] + CRM_Contribute_PseudoConstant
::financialType(), $required
2125 elseif ($fieldName === 'contribution_status_id') {
2126 $contributionStatuses = CRM_Contribute_PseudoConstant
::contributionStatus(NULL, 'label');
2127 $statusName = CRM_Contribute_PseudoConstant
::contributionStatus(NULL, 'name');
2128 foreach (['In Progress', 'Overdue', 'Refunded'] as $suppress) {
2129 unset($contributionStatuses[CRM_Utils_Array
::key($suppress, $statusName)]);
2132 $form->add('select', $name, $title,
2134 '' => ts('- select -'),
2135 ] +
$contributionStatuses, $required
2138 elseif ($fieldName === 'soft_credit_type') {
2139 $name = "soft_credit_type[$rowNumber]";
2140 $form->add('select', $name, $title,
2142 '' => ts('- select -'),
2143 ] + CRM_Core_OptionGroup
::values("soft_credit_type")
2145 //CRM-15350: choose SCT field default value as 'Gift' for membership use
2146 //else (for contribution), use configured SCT default value
2147 $SCTDefaultValue = CRM_Core_OptionGroup
::getDefaultValue("soft_credit_type");
2148 if ($field['field_type'] == 'Membership') {
2149 $SCTDefaultValue = CRM_Core_PseudoConstant
::getKey('CRM_Contribute_BAO_ContributionSoft', 'soft_credit_type_id', 'gift');
2151 $form->addElement('hidden', 'sct_default_id', $SCTDefaultValue, ['id' => 'sct_default_id']);
2153 elseif ($fieldName == 'contribution_soft_credit_pcp_id') {
2154 CRM_Contribute_Form_SoftCredit
::addPCPFields($form, "[$rowNumber]");
2156 elseif ($fieldName == 'currency') {
2157 $form->addCurrency($name, $title, $required, NULL, FALSE, FALSE);
2159 elseif ($fieldName == 'contribution_page_id') {
2160 $form->add('select', $name, $title,
2162 '' => ts('- select -'),
2163 ] + CRM_Contribute_PseudoConstant
::contributionPage(), $required, 'class="big"'
2166 elseif ($fieldName == 'activity_status_id') {
2167 $form->add('select', $name, $title,
2169 '' => ts('- select -'),
2170 ] + CRM_Core_PseudoConstant
::activityStatus(), $required
2173 elseif ($fieldName == 'activity_engagement_level') {
2174 $form->add('select', $name, $title,
2176 '' => ts('- select -'),
2177 ] + CRM_Campaign_PseudoConstant
::engagementLevel(), $required
2180 elseif ($fieldName == 'participant_status') {
2182 if ($online == TRUE) {
2183 $cond = 'visibility_id = 1';
2185 $form->add('select', $name, $title,
2187 '' => ts('- select -'),
2188 ] + CRM_Event_PseudoConstant
::participantStatus(NULL, $cond, 'label'), $required
2191 elseif ($fieldName == 'participant_role') {
2192 if (!empty($field['is_multiple'])) {
2193 $form->addCheckBox($name, $title, CRM_Event_PseudoConstant
::participantRole(), NULL, NULL, NULL, NULL, ' ', TRUE);
2196 $form->add('select', $name, $title,
2198 '' => ts('- select -'),
2199 ] + CRM_Event_PseudoConstant
::participantRole(), $required
2203 elseif ($fieldName == 'world_region') {
2204 $form->add('select', $name, $title, CRM_Core_PseudoConstant
::worldRegion(), $required, $selectAttributes);
2206 elseif ($fieldName == 'signature_html') {
2207 $form->add('wysiwyg', $name, $title, CRM_Core_DAO
::getAttribute('CRM_Core_DAO_Email', $fieldName));
2209 elseif ($fieldName == 'signature_text') {
2210 $form->add('textarea', $name, $title, CRM_Core_DAO
::getAttribute('CRM_Core_DAO_Email', $fieldName));
2212 elseif (substr($fieldName, -11) == 'campaign_id') {
2213 if (CRM_Campaign_BAO_Campaign
::isCampaignEnable()) {
2214 $campaigns = CRM_Campaign_BAO_Campaign
::getCampaigns(CRM_Utils_Array
::value($contactId,
2215 $form->_componentCampaigns
2217 $form->add('select', $name, $title,
2219 '' => ts('- select -'),
2220 ] +
$campaigns, $required, 'class="crm-select2 big"'
2224 elseif ($fieldName == 'activity_details') {
2225 $form->add('wysiwyg', $fieldName, $title, ['rows' => 4, 'cols' => 60], $required);
2227 elseif ($fieldName == 'activity_duration') {
2228 $form->add('text', $name, $title, $attributes, $required);
2229 $form->addRule($name, ts('Please enter the duration as number of minutes (integers only).'), 'positiveInteger');
2231 elseif ($fieldName == 'case_status') {
2232 $form->add('select', $name, $title,
2234 '' => ts('- select -'),
2235 ] + CRM_Case_BAO_Case
::buildOptions('case_status_id', 'create'),
2240 if (substr($fieldName, 0, 3) === 'is_' or substr($fieldName, 0, 7) === 'do_not_') {
2241 $form->add('advcheckbox', $name, $title, $attributes, $required);
2243 elseif (CRM_Utils_Array
::value('html_type', $field) === 'Select Date') {
2244 $extra = isset($field['datepicker']) ?
$field['datepicker']['extra'] : CRM_Utils_Date
::getDatePickerExtra($field);
2245 $attributes = isset($field['datepicker']) ?
$field['datepicker']['attributes'] : CRM_Utils_Date
::getDatePickerAttributes($field);
2246 $form->add('datepicker', $name, $title, $attributes, $required, $extra);
2249 $form->add('text', $name, $title, $attributes, $required);
2253 static $hiddenSubtype = FALSE;
2254 if (!$hiddenSubtype && CRM_Contact_BAO_ContactType
::isaSubType($field['field_type'])) {
2255 // In registration mode params are submitted via POST and we don't have any clue
2256 // about profile-id or the profile-type (which could be a subtype)
2257 // To generalize the behavior and simplify the process,
2258 // lets always add the hidden
2259 //subtype value if there is any, and we won't have to
2260 // compute it while processing.
2262 $form->addElement('hidden', $usedFor . '[contact_sub_type]', $field['field_type']);
2265 $form->addElement('hidden', 'contact_sub_type_hidden', $field['field_type']);
2267 $hiddenSubtype = TRUE;
2270 if (($view && $mode != CRM_Profile_Form
::MODE_SEARCH
) ||
$isShared) {
2271 $form->freeze($name);
2275 if (in_array($fieldName, [
2276 'non_deductible_amount',
2281 $form->addRule($name, ts('Please enter a valid amount.'), 'money');
2284 if (!($rule == 'email' && $mode == CRM_Profile_Form
::MODE_SEARCH
)) {
2285 $form->addRule($name, ts('Please enter a valid %1', [1 => $title]), $rule);
2291 * Set profile defaults.
2293 * @param int $contactId
2295 * @param array $fields
2296 * Associative array of fields.
2297 * @param array $defaults
2299 * @param bool $singleProfile
2300 * True for single profile else false(Update multiple items).
2301 * @param int $componentId
2302 * Id for specific components like contribute, event etc.
2303 * @param null $component
2305 public static function setProfileDefaults(
2306 $contactId, &$fields, &$defaults,
2307 $singleProfile = TRUE, $componentId = NULL, $component = NULL
2309 if (!$componentId) {
2310 //get the contact details
2311 list($contactDetails, $options) = CRM_Contact_BAO_Contact
::getHierContactDetails($contactId, $fields);
2312 $details = CRM_Utils_Array
::value($contactId, $contactDetails);
2313 $multipleFields = ['website' => 'url'];
2315 //start of code to set the default values
2316 foreach ($fields as $name => $field) {
2317 // skip pseudo fields
2318 if (substr($name, 0, 9) == 'phone_ext') {
2322 //set the field name depending upon the profile mode(single/multiple)
2323 if ($singleProfile) {
2327 $fldName = "field[$contactId][$name]";
2330 if ($name == 'group') {
2331 CRM_Contact_Form_Edit_TagsAndGroups
::setDefaults($contactId, $defaults, CRM_Contact_Form_Edit_TagsAndGroups
::GROUP
, $fldName);
2333 if ($name == 'tag') {
2334 CRM_Contact_Form_Edit_TagsAndGroups
::setDefaults($contactId, $defaults, CRM_Contact_Form_Edit_TagsAndGroups
::TAG
, $fldName);
2337 if (!empty($details[$name]) ||
isset($details[$name])) {
2338 //to handle custom data (checkbox) to be written
2339 // to handle birth/deceased date, greeting_type and few other fields
2340 if (in_array($name, CRM_Contact_BAO_Contact
::$_greetingTypes)) {
2341 $defaults[$fldName] = $details[$name . '_id'];
2342 $defaults[$name . '_custom'] = $details[$name . '_custom'];
2344 elseif ($name == 'preferred_communication_method') {
2345 $v = $details[$name];
2346 if (!is_array($details[$name])) {
2347 $v = explode(CRM_Core_DAO
::VALUE_SEPARATOR
, $v);
2349 foreach ($v as $item) {
2351 $defaults[$fldName . "[$item]"] = 1;
2355 elseif ($name == 'contact_sub_type') {
2356 $defaults[$fldName] = explode(CRM_Core_DAO
::VALUE_SEPARATOR
, trim($details[$name], CRM_Core_DAO
::VALUE_SEPARATOR
));
2358 elseif ($name == 'world_region') {
2359 $defaults[$fldName] = $details['worldregion_id'];
2361 elseif ($customFieldId = CRM_Core_BAO_CustomField
::getKeyID($name)) {
2362 // @todo retrieving the custom fields here seems obsolete - $field holds more data for the fields.
2363 $customFields = CRM_Core_BAO_CustomField
::getFields(CRM_Utils_Array
::value('contact_type', $details));
2365 // hack to add custom data for components
2366 $components = ['Contribution', 'Participant', 'Membership', 'Activity'];
2367 foreach ($components as $value) {
2368 $customFields = CRM_Utils_Array
::crmArrayMerge($customFields,
2369 CRM_Core_BAO_CustomField
::getFieldsForImport($value)
2373 switch ($customFields[$customFieldId]['html_type']) {
2374 case 'Multi-Select State/Province':
2375 case 'Multi-Select Country':
2376 case 'Multi-Select':
2377 $v = explode(CRM_Core_DAO
::VALUE_SEPARATOR
, $details[$name]);
2378 foreach ($v as $item) {
2380 $defaults[$fldName][$item] = $item;
2386 $v = explode(CRM_Core_DAO
::VALUE_SEPARATOR
, $details[$name]);
2387 foreach ($v as $item) {
2389 $defaults[$fldName][$item] = 1;
2390 // seems like we need this for QF style checkboxes in profile where its multiindexed
2392 $defaults["{$fldName}[{$item}]"] = 1;
2398 $defaults[$fldName] = $details[$name];
2403 $defaults[$fldName] = $details[$name];
2407 $blocks = ['email', 'phone', 'im', 'openid'];
2408 list($fieldName, $locTypeId, $phoneTypeId) = CRM_Utils_System
::explode('-', $name, 3);
2409 if (!in_array($fieldName, $multipleFields)) {
2410 if (is_array($details)) {
2411 foreach ($details as $key => $value) {
2412 // when we fixed CRM-5319 - get primary loc
2413 // type as per loc field and removed below code.
2414 $primaryLocationType = FALSE;
2415 if ($locTypeId == 'Primary') {
2416 if (is_array($value) && array_key_exists($fieldName, $value)) {
2417 $primaryLocationType = TRUE;
2418 if (in_array($fieldName, $blocks)) {
2419 $locTypeId = CRM_Contact_BAO_Contact
::getPrimaryLocationType($contactId, FALSE, $fieldName);
2422 $locTypeId = CRM_Contact_BAO_Contact
::getPrimaryLocationType($contactId, FALSE, 'address');
2427 // fixed for CRM-665
2428 if (is_numeric($locTypeId)) {
2429 if ($primaryLocationType ||
$locTypeId == CRM_Utils_Array
::value('location_type_id', $value)) {
2430 if (!empty($value[$fieldName])) {
2431 //to handle stateprovince and country
2432 if ($fieldName == 'state_province') {
2433 $defaults[$fldName] = $value['state_province_id'];
2435 elseif ($fieldName == 'county') {
2436 $defaults[$fldName] = $value['county_id'];
2438 elseif ($fieldName == 'country') {
2439 if (!isset($value['country_id']) ||
!$value['country_id']) {
2440 $config = CRM_Core_Config
::singleton();
2441 if ($config->defaultContactCountry
) {
2442 $defaults[$fldName] = $config->defaultContactCountry
;
2446 $defaults[$fldName] = $value['country_id'];
2449 elseif ($fieldName == 'phone') {
2451 if (isset($value['phone'][$phoneTypeId])) {
2452 $defaults[$fldName] = $value['phone'][$phoneTypeId];
2454 if (isset($value['phone_ext'][$phoneTypeId])) {
2455 $defaults[str_replace('phone', 'phone_ext', $fldName)] = $value['phone_ext'][$phoneTypeId];
2459 $phoneDefault = CRM_Utils_Array
::value('phone', $value);
2461 if (!is_array($phoneDefault)) {
2462 $defaults[$fldName] = $phoneDefault;
2466 elseif ($fieldName == 'email') {
2467 //adding the first email (currently we don't support multiple emails of same location type)
2468 $defaults[$fldName] = $value['email'];
2470 elseif ($fieldName == 'im') {
2471 //adding the first im (currently we don't support multiple ims of same location type)
2472 $defaults[$fldName] = $value['im'];
2473 $defaults[$fldName . '-provider_id'] = $value['im_provider_id'];
2476 $defaults[$fldName] = $value[$fieldName];
2479 elseif (substr($fieldName, 0, 14) === 'address_custom' &&
2480 CRM_Utils_Array
::value(substr($fieldName, 8), $value)
2482 $defaults[$fldName] = $value[substr($fieldName, 8)];
2490 if (is_array($details)) {
2491 if ($fieldName === 'url'
2492 && !empty($details['website'])
2493 && !empty($details['website'][$locTypeId])
2495 $defaults[$fldName] = CRM_Utils_Array
::value('url', $details['website'][$locTypeId]);
2503 // Handling Contribution Part of the batch profile
2504 if (CRM_Core_Permission
::access('CiviContribute') && $component == 'Contribute') {
2505 self
::setComponentDefaults($fields, $componentId, $component, $defaults);
2508 // Handling Event Participation Part of the batch profile
2509 if (CRM_Core_Permission
::access('CiviEvent') && $component == 'Event') {
2510 self
::setComponentDefaults($fields, $componentId, $component, $defaults);
2513 // Handling membership Part of the batch profile
2514 if (CRM_Core_Permission
::access('CiviMember') && $component == 'Membership') {
2515 self
::setComponentDefaults($fields, $componentId, $component, $defaults);
2518 // Handling Activity Part of the batch profile
2519 if ($component == 'Activity') {
2520 self
::setComponentDefaults($fields, $componentId, $component, $defaults);
2523 // Handling Case Part of the batch profile
2524 if (CRM_Core_Permission
::access('CiviCase') && $component == 'Case') {
2525 self
::setComponentDefaults($fields, $componentId, $component, $defaults);
2530 * Get profiles by type eg: pure Individual etc
2532 * @param array $types
2533 * Associative array of types eg: types('Individual').
2534 * @param bool $onlyPure
2535 * True if only pure profiles are required.
2538 * associative array of profiles
2540 public static function getProfiles($types, $onlyPure = FALSE) {
2542 $ufGroups = CRM_Core_PseudoConstant
::get('CRM_Core_DAO_UFField', 'uf_group_id');
2544 CRM_Utils_Hook
::aclGroup(CRM_Core_Permission
::ADMIN
, NULL, 'civicrm_uf_group', $ufGroups, $ufGroups);
2546 // Exclude Batch Data Entry profiles - CRM-10901
2547 $batchProfiles = CRM_Core_BAO_UFGroup
::getBatchProfiles();
2549 foreach ($ufGroups as $id => $title) {
2550 $ptype = CRM_Core_BAO_UFField
::getProfileType($id, FALSE, $onlyPure);
2551 if (in_array($ptype, $types) && !array_key_exists($id, $batchProfiles)) {
2552 $profiles[$id] = $title;
2559 * Check whether a profile is valid combination of
2560 * required and/or optional profile types
2562 * @param array $required
2563 * Array of types those are required.
2564 * @param array $optional
2565 * Array of types those are optional.
2568 * associative array of profiles
2570 public static function getValidProfiles($required, $optional = NULL) {
2571 if (!is_array($required) ||
empty($required)) {
2576 $ufGroups = CRM_Core_PseudoConstant
::get('CRM_Core_DAO_UFField', 'uf_group_id');
2578 CRM_Utils_Hook
::aclGroup(CRM_Core_Permission
::ADMIN
, NULL, 'civicrm_uf_group', $ufGroups, $ufGroups);
2580 foreach ($ufGroups as $id => $title) {
2581 $type = CRM_Core_BAO_UFField
::checkValidProfileType($id, $required, $optional);
2583 $profiles[$id] = $title;
2591 * Check whether a profile is valid combination of
2592 * required profile fields
2594 * @param array $ufId
2595 * Integer id of the profile.
2596 * @param array $required
2597 * Array of fields those are required in the profile.
2600 * associative array of profiles
2602 public static function checkValidProfile($ufId, $required = NULL) {
2603 $validProfile = FALSE;
2605 return $validProfile;
2608 if (!CRM_Core_DAO
::getFieldValue('CRM_Core_DAO_UFGroup', $ufId, 'is_active')) {
2609 return $validProfile;
2612 $profileFields = self
::getFields($ufId, FALSE, CRM_Core_Action
::VIEW
, NULL,
2613 NULL, FALSE, NULL, FALSE, NULL,
2614 CRM_Core_Permission
::CREATE
, NULL
2618 if (!empty($profileFields)) {
2619 $fields = array_keys($profileFields);
2620 foreach ($fields as $val) {
2621 foreach ($required as $key => $field) {
2622 if (strpos($val, $field) === 0) {
2623 unset($required[$key]);
2628 $validProfile = (empty($required)) ?
TRUE : FALSE;
2631 return $validProfile;
2635 * Get default value for Register.
2637 * @param array $fields
2638 * @param array $defaults
2642 public static function setRegisterDefaults(&$fields, &$defaults) {
2643 $config = CRM_Core_Config
::singleton();
2644 foreach ($fields as $name => $field) {
2645 if (substr($name, 0, 8) == 'country-') {
2646 if (!empty($config->defaultContactCountry
)) {
2647 $defaults[$name] = $config->defaultContactCountry
;
2650 elseif (substr($name, 0, 15) == 'state_province-') {
2651 if (!empty($config->defaultContactStateProvince
)) {
2652 $defaults[$name] = $config->defaultContactStateProvince
;
2660 * make a copy of a profile, including
2661 * all the fields in the profile
2664 * The profile id to copy.
2666 * @return \CRM_Core_DAO
2668 public static function copy($id) {
2669 $maxId = CRM_Core_DAO
::singleValueQuery("SELECT max(id) FROM civicrm_uf_group");
2671 $title = ts('[Copy id %1]', [1 => $maxId +
1]);
2674 'title' => ' ' . $title,
2675 'name' => '__Copy_id_' . ($maxId +
1) . '_',
2679 $copy = CRM_Core_DAO
::copyGeneric('CRM_Core_DAO_UFGroup',
2685 if ($pos = strrpos($copy->name
, "_{$id}")) {
2686 $copy->name
= substr_replace($copy->name
, '', $pos);
2688 $copy->name
= CRM_Utils_String
::munge($copy->name
, '_', 56) . "_{$copy->id}";
2691 $copyUFJoin = CRM_Core_DAO
::copyGeneric('CRM_Core_DAO_UFJoin',
2692 ['uf_group_id' => $id],
2693 ['uf_group_id' => $copy->id
],
2698 $copyUFField = CRM_Core_DAO
::copyGeneric('CRM_Core_BAO_UFField',
2699 ['uf_group_id' => $id],
2700 ['uf_group_id' => $copy->id
]
2703 $maxWeight = CRM_Utils_Weight
::getMax('CRM_Core_DAO_UFJoin', NULL, 'weight');
2707 UPDATE civicrm_uf_join
2709 WHERE uf_group_id = %2
2710 AND ( entity_id IS NULL OR entity_id <= 0 )
2713 1 => [$maxWeight +
1, 'Integer'],
2714 2 => [$copy->id
, 'Integer'],
2716 CRM_Core_DAO
::executeQuery($query, $p);
2717 if ($copy->is_reserved
) {
2718 $query = "UPDATE civicrm_uf_group SET is_reserved = 0 WHERE id = %1";
2719 $params = [1 => [$copy->id
, 'Integer']];
2720 CRM_Core_DAO
::executeQuery($query, $params);
2722 CRM_Utils_Hook
::copy('UFGroup', $copy);
2728 * Process that send notification e-mails
2730 * @param int $contactID
2732 * @param array $values
2733 * Associative array of name/value pair.
2735 public static function commonSendMail($contactID, &$values) {
2736 if (!$contactID ||
!$values) {
2740 $template = CRM_Core_Smarty
::singleton();
2742 $displayName = CRM_Core_DAO
::getFieldValue('CRM_Contact_DAO_Contact',
2747 self
::profileDisplay($values['id'], $values['values'], $template);
2748 $emailList = explode(',', $values['email']);
2750 $contactLink = CRM_Utils_System
::url('civicrm/contact/view',
2751 "reset=1&cid=$contactID",
2752 TRUE, NULL, FALSE, FALSE, TRUE
2755 //get the default domain email address.
2756 list($domainEmailName, $domainEmailAddress) = CRM_Core_BAO_Domain
::getNameAndEmail();
2758 if (!$domainEmailAddress ||
$domainEmailAddress == 'info@EXAMPLE.ORG') {
2759 $fixUrl = CRM_Utils_System
::url('civicrm/admin/domain', 'action=update&reset=1');
2760 CRM_Core_Error
::fatal(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]));
2763 foreach ($emailList as $emailTo) {
2764 // FIXME: take the below out of the foreach loop
2765 CRM_Core_BAO_MessageTemplate
::sendTemplate(
2767 'groupName' => 'msg_tpl_workflow_uf',
2768 'valueName' => 'uf_notify',
2769 'contactId' => $contactID,
2771 'displayName' => $displayName,
2772 'currentDate' => date('r'),
2773 'contactLink' => $contactLink,
2775 'from' => "$domainEmailName <$domainEmailAddress>",
2776 'toEmail' => $emailTo,
2783 * Given a contact id and a group id, returns the field values from the db
2784 * for this group and notify email only if group's notify field is
2785 * set and field values are not empty
2791 * @param array $params
2792 * @param bool $skipCheck
2796 public function checkFieldsEmptyValues($gid, $cid, $params, $skipCheck = FALSE) {
2798 if (CRM_Core_BAO_UFGroup
::filterUFGroups($gid, $cid) ||
$skipCheck) {
2800 $fields = CRM_Core_BAO_UFGroup
::getFields($gid, FALSE, CRM_Core_Action
::VIEW
);
2801 CRM_Core_BAO_UFGroup
::getValues($cid, $fields, $values, FALSE, $params, TRUE);
2803 $email = CRM_Core_DAO
::getFieldValue('CRM_Core_DAO_UFGroup', $gid, 'notify');
2805 if (!empty($values) &&
2810 'values' => $values,
2821 * Assign uf fields to template.
2825 * @param array $values
2826 * @param CRM_Core_Smarty $template
2828 public static function profileDisplay($gid, $values, $template) {
2829 $groupTitle = CRM_Core_DAO
::getFieldValue('CRM_Core_DAO_UFGroup', $gid, 'title');
2830 $template->assign('grouptitle', $groupTitle);
2831 if (count($values)) {
2832 $template->assign('values', $values);
2837 * Format fields for dupe Contact Matching.
2839 * @param array $params
2841 * @param int $contactId
2844 * associated formatted array
2846 public static function formatFields($params, $contactId = NULL) {
2848 // get the primary location type id and email
2849 list($name, $primaryEmail, $primaryLocationType) = CRM_Contact_BAO_Contact_Location
::getEmailDetails($contactId);
2852 $defaultLocationType = CRM_Core_BAO_LocationType
::getDefault();
2853 $primaryLocationType = $defaultLocationType->id
;
2859 $primaryLocation = 0;
2860 foreach ($params as $key => $value) {
2861 list($fieldName, $locTypeId, $phoneTypeId) = explode('-', $key);
2863 if ($locTypeId == 'Primary') {
2864 $locTypeId = $primaryLocationType;
2867 if (is_numeric($locTypeId)) {
2868 if (!in_array($locTypeId, $locationType)) {
2869 $locationType[$count] = $locTypeId;
2872 $loc = CRM_Utils_Array
::key($locTypeId, $locationType);
2874 $data['location'][$loc]['location_type_id'] = $locTypeId;
2876 // if we are getting in a new primary email, dont overwrite the new one
2877 if ($locTypeId == $primaryLocationType) {
2878 if (!empty($params['email-' . $primaryLocationType])) {
2879 $data['location'][$loc]['email'][$loc]['email'] = $fields['email-' . $primaryLocationType];
2881 elseif (isset($primaryEmail)) {
2882 $data['location'][$loc]['email'][$loc]['email'] = $primaryEmail;
2888 $data['location'][$loc]['is_primary'] = 1;
2890 if ($fieldName == 'phone') {
2892 $data['location'][$loc]['phone'][$loc]['phone_type_id'] = $phoneTypeId;
2895 $data['location'][$loc]['phone'][$loc]['phone_type_id'] = '';
2897 $data['location'][$loc]['phone'][$loc]['phone'] = $value;
2899 elseif ($fieldName == 'email') {
2900 $data['location'][$loc]['email'][$loc]['email'] = $value;
2902 elseif ($fieldName == 'im') {
2903 $data['location'][$loc]['im'][$loc]['name'] = $value;
2906 if ($fieldName === 'state_province') {
2907 $data['location'][$loc]['address']['state_province_id'] = $value;
2909 elseif ($fieldName === 'country') {
2910 $data['location'][$loc]['address']['country_id'] = $value;
2913 $data['location'][$loc]['address'][$fieldName] = $value;
2918 // TODO: prefix, suffix and gender translation may no longer be necessary - check inputs
2919 if ($key === 'individual_suffix') {
2920 $data['suffix_id'] = $value;
2922 elseif ($key === 'individual_prefix') {
2923 $data['prefix_id'] = $value;
2925 elseif ($key === 'gender') {
2926 $data['gender_id'] = $value;
2928 elseif (substr($key, 0, 6) === 'custom') {
2929 if ($customFieldID = CRM_Core_BAO_CustomField
::getKeyID($key)) {
2931 if ($customFields[$customFieldID]['html_type'] == 'CheckBox') {
2932 $value = implode(CRM_Core_DAO
::VALUE_SEPARATOR
, array_keys($value));
2934 // fix the date field
2935 if ($customFields[$customFieldID]['data_type'] == 'Date') {
2936 $date = CRM_Utils_Date
::format($value);
2943 $data['custom'][$customFieldID] = [
2946 'extends' => $customFields[$customFieldID]['extends'],
2947 'type' => $customFields[$customFieldID]['data_type'],
2948 'custom_field_id' => $customFieldID,
2952 elseif ($key == 'edit') {
2956 $data[$key] = $value;
2961 if (!$primaryLocation) {
2963 $data['location'][$loc]['email'][$loc]['email'] = $primaryEmail;
2970 * Calculate the profile type 'group_type' as per profile fields.
2974 * @param bool $includeTypeValues
2975 * @param int $ignoreFieldId
2976 * Ignore particular profile field.
2979 * list of calculated group type
2981 public static function calculateGroupType($gId, $includeTypeValues = FALSE, $ignoreFieldId = NULL) {
2982 //get the profile fields.
2983 $ufFields = self
::getFields($gId, FALSE, NULL, NULL, NULL, TRUE, NULL, TRUE);
2984 return self
::_calculateGroupType($ufFields, $includeTypeValues, $ignoreFieldId);
2988 * Calculate the profile type 'group_type' as per profile fields.
2991 * @param bool $includeTypeValues
2992 * @param int $ignoreFieldId
2993 * Ignore perticular profile field.
2996 * list of calculated group type
2998 public static function _calculateGroupType($ufFields, $includeTypeValues = FALSE, $ignoreFieldId = NULL) {
2999 $groupType = $groupTypeValues = $customFieldIds = [];
3000 if (!empty($ufFields)) {
3001 foreach ($ufFields as $fieldName => $fieldValue) {
3002 //ignore field from group type when provided.
3003 //in case of update profile field.
3004 if ($ignoreFieldId && ($ignoreFieldId == $fieldValue['field_id'])) {
3007 if (!in_array($fieldValue['field_type'], $groupType)) {
3008 $groupType[$fieldValue['field_type']] = $fieldValue['field_type'];
3011 if ($includeTypeValues && ($fldId = CRM_Core_BAO_CustomField
::getKeyID($fieldName))) {
3012 $customFieldIds[$fldId] = $fldId;
3017 if (!empty($customFieldIds)) {
3018 $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) . ')';
3020 $customGroups = CRM_Core_DAO
::executeQuery($query);
3021 while ($customGroups->fetch()) {
3022 if (!$customGroups->extends_entity_column_value
) {
3026 $groupTypeName = "{$customGroups->extends}Type";
3027 if ($customGroups->extends == 'Participant' && $customGroups->extends_entity_column_id
) {
3028 $groupTypeName = CRM_Core_PseudoConstant
::getName('CRM_Core_DAO_CustomGroup', 'extends_entity_column_id', $customGroups->extends_entity_column_id
);
3031 foreach (explode(CRM_Core_DAO
::VALUE_SEPARATOR
, $customGroups->extends_entity_column_value
) as $val) {
3033 $groupTypeValues[$groupTypeName][$val] = $val;
3038 if (!empty($groupTypeValues)) {
3039 $groupType = array_merge($groupType, $groupTypeValues);
3047 * Update the profile type 'group_type' as per profile fields including group types and group subtype values.
3048 * Build and store string like: group_type1,group_type2[VALUE_SEPERATOR]group_type1Type:1:2:3,group_type2Type:1:2
3051 * BirthDate + Email Individual,Contact
3052 * BirthDate + Subject Individual,Activity
3053 * BirthDate + Subject + SurveyOnlyField Individual,Activity\0ActivityType:28
3054 * BirthDate + Subject + SurveyOnlyField + PhoneOnlyField (Not allowed)
3055 * BirthDate + SurveyOnlyField Individual,Activity\0ActivityType:28
3056 * BirthDate + Subject + SurveyOrPhoneField Individual,Activity\0ActivityType:2:28
3057 * BirthDate + SurveyOrPhoneField Individual,Activity\0ActivityType:2:28
3058 * BirthDate + SurveyOrPhoneField + SurveyOnlyField Individual,Activity\0ActivityType:2:28
3059 * BirthDate + StudentField + Subject + SurveyOnlyField Individual,Activity,Student\0ActivityType:28
3062 * @param array $groupTypes
3063 * With key having group type names.
3067 public static function updateGroupTypes($gId, $groupTypes = []) {
3068 if (!is_array($groupTypes) ||
!$gId) {
3072 // If empty group types set group_type as 'null'
3073 if (empty($groupTypes)) {
3074 return CRM_Core_DAO
::setFieldValue('CRM_Core_DAO_UFGroup', $gId, 'group_type', 'null');
3077 $componentGroupTypes = ['Contribution', 'Participant', 'Membership', 'Activity', 'Case'];
3078 $validGroupTypes = array_merge([
3083 ], $componentGroupTypes, CRM_Contact_BAO_ContactType
::subTypes());
3085 $gTypes = $gTypeValues = [];
3087 $participantExtends = ['ParticipantRole', 'ParticipantEventName', 'ParticipantEventType'];
3088 // Get valid group type and group subtypes
3089 foreach ($groupTypes as $groupType => $value) {
3090 if (in_array($groupType, $validGroupTypes) && !in_array($groupType, $gTypes)) {
3091 $gTypes[] = $groupType;
3096 if (in_array($groupType, $participantExtends)) {
3097 $subTypesOf = $groupType;
3099 elseif (strpos($groupType, 'Type') > 0) {
3100 $subTypesOf = substr($groupType, 0, strpos($groupType, 'Type'));
3106 if (!empty($value) &&
3107 (in_array($subTypesOf, $componentGroupTypes) ||
3108 in_array($subTypesOf, $participantExtends)
3111 $gTypeValues[$subTypesOf] = $groupType . ":" . implode(':', $value);
3115 if (empty($gTypes)) {
3119 // Build String to store group types and group subtypes
3120 $groupTypeString = implode(',', $gTypes);
3121 if (!empty($gTypeValues)) {
3122 $groupTypeString .= CRM_Core_DAO
::VALUE_SEPARATOR
. implode(',', $gTypeValues);
3125 return CRM_Core_DAO
::setFieldValue('CRM_Core_DAO_UFGroup', $gId, 'group_type', $groupTypeString);
3129 * Create a "group_type" string.
3131 * @param array $coreTypes
3132 * E.g. array('Individual','Contact','Student').
3133 * @param array $subTypes
3134 * E.g. array('ActivityType' => array(7, 11)).
3135 * @param string $delim
3138 * @throws CRM_Core_Exception
3140 public static function encodeGroupType($coreTypes, $subTypes, $delim = CRM_Core_DAO
::VALUE_SEPARATOR
) {
3141 $groupTypeExpr = '';
3143 $groupTypeExpr .= implode(',', $coreTypes);
3146 //CRM-15427 Allow Multiple subtype filtering
3147 //if (count($subTypes) > 1) {
3148 //throw new CRM_Core_Exception("Multiple subtype filtering is not currently supported by widget.");
3150 foreach ($subTypes as $subType => $subTypeIds) {
3151 $groupTypeExpr .= $delim . $subType . ':' . implode(':', $subTypeIds);
3154 return $groupTypeExpr;
3158 * setDefault componet specific profile fields.
3160 * @param array $fields
3162 * @param int $componentId
3164 * @param string $component
3166 * @param array $defaults
3167 * An array of default values.
3169 * @param bool $isStandalone
3171 public static function setComponentDefaults(&$fields, $componentId, $component, &$defaults, $isStandalone = FALSE) {
3172 if (!$componentId ||
3173 !in_array($component, ['Contribute', 'Membership', 'Event', 'Activity', 'Case'])
3178 $componentBAO = $componentSubType = NULL;
3179 switch ($component) {
3181 $componentBAO = 'CRM_Member_BAO_Membership';
3182 $componentBAOName = 'Membership';
3183 $componentSubType = ['membership_type_id'];
3187 $componentBAO = 'CRM_Contribute_BAO_Contribution';
3188 $componentBAOName = 'Contribution';
3189 $componentSubType = ['financial_type_id'];
3193 $componentBAO = 'CRM_Event_BAO_Participant';
3194 $componentBAOName = 'Participant';
3195 $componentSubType = ['role_id', 'event_id', 'event_type_id'];
3199 $componentBAO = 'CRM_Activity_BAO_Activity';
3200 $componentBAOName = 'Activity';
3201 $componentSubType = ['activity_type_id'];
3205 $componentBAO = 'CRM_Case_BAO_Case';
3206 $componentBAOName = 'Case';
3207 $componentSubType = ['case_type_id'];
3212 $params = ['id' => $componentId];
3214 //get the component values.
3215 CRM_Core_DAO
::commonRetrieve($componentBAO, $params, $values);
3216 if ($componentBAOName == 'Participant') {
3217 $values +
= ['event_type_id' => CRM_Core_DAO
::getFieldValue('CRM_Event_DAO_Event', $values['event_id'], 'event_type_id')];
3220 $formattedGroupTree = [];
3222 foreach ($fields as $name => $field) {
3223 $fldName = $isStandalone ?
$name : "field[$componentId][$name]";
3224 if (array_key_exists($name, $values)) {
3225 $defaults[$fldName] = $values[$name];
3227 elseif ($name == 'participant_note') {
3228 $noteDetails = CRM_Core_BAO_Note
::getNote($componentId, 'civicrm_participant');
3229 $defaults[$fldName] = array_pop($noteDetails);
3231 elseif (in_array($name, [
3233 'payment_instrument',
3234 'participant_status',
3237 $defaults[$fldName] = $values["{$name}_id"];
3239 elseif ($name == 'membership_type') {
3240 // since membership_type field is a hierselect -
3241 $defaults[$fldName][0]
3242 = CRM_Core_DAO
::getFieldValue('CRM_Member_DAO_MembershipType', $values['membership_type_id'], 'member_of_contact_id', 'id');
3243 $defaults[$fldName][1] = $values['membership_type_id'];
3245 elseif ($name == 'membership_status') {
3246 $defaults[$fldName] = $values['status_id'];
3248 elseif ($name == 'case_status') {
3249 $defaults[$fldName] = $values['case_status_id'];
3251 elseif (CRM_Core_BAO_CustomField
::getKeyID($name, TRUE) !== [NULL, NULL]) {
3252 if (empty($formattedGroupTree)) {
3253 //get the groupTree as per subTypes.
3255 foreach ($componentSubType as $subType) {
3256 $subTree = CRM_Core_BAO_CustomGroup
::getTree($componentBAOName, NULL,
3257 $componentId, 0, $values[$subType]
3259 $groupTree = CRM_Utils_Array
::crmArrayMerge($groupTree, $subTree);
3261 $formattedGroupTree = CRM_Core_BAO_CustomGroup
::formatGroupTree($groupTree, 1);
3262 CRM_Core_BAO_CustomGroup
::setDefaults($formattedGroupTree, $defaults);
3265 //FIX ME: We need to loop defaults, but once we move to custom_1_x convention this code can be simplified.
3266 foreach ($defaults as $customKey => $customValue) {
3267 if ($customFieldDetails = CRM_Core_BAO_CustomField
::getKeyID($customKey, TRUE)) {
3268 if ($name == 'custom_' . $customFieldDetails[0]) {
3270 //hack to set default for checkbox
3271 //basically this is for weired field name like field[33][custom_19]
3272 //we are converting this field name to array structure and assign value.
3275 foreach ($formattedGroupTree as $tree) {
3276 if (!empty($tree['fields'][$customFieldDetails[0]])) {
3277 if ('CheckBox' == CRM_Utils_Array
::value('html_type', $tree['fields'][$customFieldDetails[0]])) {
3279 $defaults['field'][$componentId][$name] = $customValue;
3282 elseif (CRM_Utils_Array
::value('data_type', $tree['fields'][$customFieldDetails[0]]) == 'Date') {
3285 // CRM-6681, $default contains formatted date, time values.
3286 $defaults[$fldName] = $customValue;
3287 if (!empty($defaults[$customKey . '_time'])) {
3288 $defaults['field'][$componentId][$name . '_time'] = $defaults[$customKey . '_time'];
3294 if (!$skipValue ||
$isStandalone) {
3295 $defaults[$fldName] = $customValue;
3297 unset($defaults[$customKey]);
3303 elseif (isset($values[$fldName])) {
3304 $defaults[$fldName] = $values[$fldName];
3310 * Retrieve groups of profiles.
3312 * @param int $profileID
3313 * Id of the profile.
3318 public static function profileGroups($profileID) {
3320 $profileTypes = CRM_Core_DAO
::getFieldValue('CRM_Core_DAO_UFGroup', $profileID, 'group_type');
3321 if ($profileTypes) {
3322 $groupTypeParts = explode(CRM_Core_DAO
::VALUE_SEPARATOR
, $profileTypes);
3323 $groupTypes = explode(',', $groupTypeParts[0]);
3329 * Alter contact params by filtering existing subscribed groups and returns
3330 * unsubscribed groups array for subscription.
3332 * @param array $params
3334 * @param int $contactId
3338 * This contains array of groups for subscription
3340 public static function getDoubleOptInGroupIds(&$params, $contactId = NULL) {
3341 $config = CRM_Core_Config
::singleton();
3342 $subscribeGroupIds = [];
3344 // process further only if profileDoubleOptIn enabled and if groups exist
3345 if (!array_key_exists('group', $params) ||
3346 !self
::isProfileDoubleOptin() ||
3347 CRM_Utils_System
::isNull($params['group'])
3349 return $subscribeGroupIds;
3352 //check if contact email exist.
3354 foreach ($params as $name => $value) {
3355 if (strpos($name, 'email-') !== FALSE) {
3361 //Proceed furthur only if email present
3363 return $subscribeGroupIds;
3366 //do check for already subscriptions.
3367 $contactGroups = [];
3371 FROM civicrm_group_contact
3372 WHERE status = 'Added'
3373 AND contact_id = %1";
3375 $dao = CRM_Core_DAO
::executeQuery($query, [1 => [$contactId, 'Integer']]);
3376 while ($dao->fetch()) {
3377 $contactGroups[$dao->group_id
] = $dao->group_id
;
3381 //since we don't have names, compare w/ label.
3382 $mailingListGroupType = array_search('Mailing List', CRM_Core_OptionGroup
::values('group_type'));
3384 //actual processing start.
3385 foreach ($params['group'] as $groupId => $isSelected) {
3386 //unset group those are not selected.
3388 unset($params['group'][$groupId]);
3392 $groupTypes = explode(CRM_Core_DAO
::VALUE_SEPARATOR
,
3393 CRM_Core_DAO
::getFieldValue('CRM_Contact_DAO_Group', $groupId, 'group_type', 'id')
3395 //get only mailing type group and unset it from params
3396 if (in_array($mailingListGroupType, $groupTypes) && !in_array($groupId, $contactGroups)) {
3397 $subscribeGroupIds[$groupId] = $groupId;
3398 unset($params['group'][$groupId]);
3402 return $subscribeGroupIds;
3406 * Check if we are rendering mixed profiles.
3408 * @param array $profileIds
3409 * Associated array of profile ids.
3412 * true if profile is mixed
3414 public static function checkForMixProfiles($profileIds) {
3415 $mixProfile = FALSE;
3417 $contactTypes = ['Individual', 'Household', 'Organization'];
3418 $subTypes = CRM_Contact_BAO_ContactType
::subTypes();
3420 $components = ['Contribution', 'Participant', 'Membership', 'Activity'];
3422 $typeCount = ['ctype' => [], 'subtype' => []];
3423 foreach ($profileIds as $gid) {
3424 $profileType = CRM_Core_BAO_UFField
::getProfileType($gid);
3425 // ignore profile of type Contact
3426 if ($profileType == 'Contact') {
3429 if (in_array($profileType, $contactTypes)) {
3430 if (!isset($typeCount['ctype'][$profileType])) {
3431 $typeCount['ctype'][$profileType] = 1;
3434 // check if we are rendering profile of different contact types
3435 if (count($typeCount['ctype']) == 2) {
3440 elseif (in_array($profileType, $components)) {
3445 if (!isset($typeCount['subtype'][$profileType])) {
3446 $typeCount['subtype'][$profileType] = 1;
3448 // check if we are rendering profile of different contact sub types
3449 if (count($typeCount['subtype']) == 2) {
3459 * Determine of we show overlay profile or not.
3462 * true if profile should be shown else false
3464 public static function showOverlayProfile() {
3465 $showOverlay = TRUE;
3467 // get the id of overlay profile
3468 $overlayProfileId = CRM_Core_DAO
::getFieldValue('CRM_Core_DAO_UFGroup', 'summary_overlay', 'id', 'name');
3469 $query = "SELECT count(id) FROM civicrm_uf_field WHERE uf_group_id = {$overlayProfileId} AND visibility IN ('Public Pages', 'Public Pages and Listings') ";
3471 $count = CRM_Core_DAO
::singleValueQuery($query);
3473 //check if there are no public fields and use is anonymous
3474 $session = CRM_Core_Session
::singleton();
3475 if (!$count && !$session->get('userID')) {
3476 $showOverlay = FALSE;
3479 return $showOverlay;
3483 * Get group type values of the profile.
3485 * @param int $profileId
3486 * @param string $groupType
3491 public static function groupTypeValues($profileId, $groupType = NULL) {
3492 $groupTypeValue = [];
3493 $groupTypes = CRM_Core_DAO
::getFieldValue('CRM_Core_DAO_UFGroup', $profileId, 'group_type');
3495 $groupTypeParts = explode(CRM_Core_DAO
::VALUE_SEPARATOR
, $groupTypes);
3496 if (empty($groupTypeParts[1])) {
3497 return $groupTypeValue;
3499 $participantExtends = ['ParticipantRole', 'ParticipantEventName', 'ParticipantEventType'];
3501 foreach (explode(',', $groupTypeParts[1]) as $groupTypeValues) {
3503 $valueParts = explode(':', $groupTypeValues);
3505 ($valueParts[0] != "{$groupType}Type" ||
3506 ($groupType == 'Participant' &&
3507 !in_array($valueParts[0], $participantExtends)
3513 foreach ($valueParts as $val) {
3514 if (CRM_Utils_Rule
::integer($val)) {
3515 $values[$val] = $val;
3518 if (!empty($values)) {
3519 $typeName = substr($valueParts[0], 0, -4);
3520 if (in_array($valueParts[0], $participantExtends)) {
3521 $typeName = $valueParts[0];
3523 $groupTypeValue[$typeName] = $values;
3527 return $groupTypeValue;
3531 * @return bool|object
3533 public static function isProfileDoubleOptin() {
3534 // check for double optin
3535 $config = CRM_Core_Config
::singleton();
3536 if (in_array('CiviMail', $config->enableComponents
)) {
3537 return Civi
::settings()->get('profile_double_optin');
3543 * @return bool|object
3545 public static function isProfileAddToGroupDoubleOptin() {
3546 // check for add to group double optin
3547 $config = CRM_Core_Config
::singleton();
3548 if (in_array('CiviMail', $config->enableComponents
)) {
3549 return Civi
::settings()->get('profile_add_to_group_double_optin');
3555 * Get profiles used for batch entry.
3558 * profileIds profile ids
3560 public static function getBatchProfiles() {
3562 FROM civicrm_uf_group
3563 WHERE name IN ('contribution_batch_entry', 'membership_batch_entry')";
3564 $dao = CRM_Core_DAO
::executeQuery($query);
3566 while ($dao->fetch()) {
3567 $profileIds[$dao->id
] = $dao->id
;
3574 * @param $destination
3575 * @param bool $returnMultiSummaryFields
3577 * @return array|null
3578 * @todo what do I do?
3580 public static function shiftMultiRecordFields(&$source, &$destination, $returnMultiSummaryFields = FALSE) {
3581 $multiSummaryFields = $returnMultiSummaryFields ?
[] : NULL;
3582 foreach ($source as $field => $properties) {
3583 if (!CRM_Core_BAO_CustomField
::getKeyID($field)) {
3586 if (CRM_Core_BAO_CustomField
::isMultiRecordField($field)) {
3587 $destination[$field] = $properties;
3588 if ($returnMultiSummaryFields) {
3589 if ($properties['is_multi_summary']) {
3590 $multiSummaryFields[$field] = $properties;
3593 unset($source[$field]);
3596 return $multiSummaryFields;
3600 * This is function is used to format pseudo fields.
3602 * @param array $fields
3603 * Associated array of profile fields.
3606 public static function reformatProfileFields(&$fields) {
3607 //reformat fields array
3608 foreach ($fields as $name => $field) {
3609 //reformat phone and extension field
3610 if (substr($field['name'], 0, 13) == 'phone_and_ext') {
3611 $fieldSuffix = str_replace('phone_and_ext-', '', $field['name']);
3613 // retain existing element properties and just update and replace key
3614 CRM_Utils_Array
::crmReplaceKey($fields, $name, "phone-{$fieldSuffix}");
3615 $fields["phone-{$fieldSuffix}"]['name'] = "phone-{$fieldSuffix}";
3616 $fields["phone-{$fieldSuffix}"]['where'] = 'civicrm_phone.phone';
3618 // add additional phone extension field
3619 $fields["phone_ext-{$fieldSuffix}"] = $field;
3620 $fields["phone_ext-{$fieldSuffix}"]['title'] = $field['title'] . ' - ' . ts('Ext.');
3621 $fields["phone_ext-{$fieldSuffix}"]['name'] = "phone_ext-{$fieldSuffix}";
3622 $fields["phone_ext-{$fieldSuffix}"]['where'] = 'civicrm_phone.phone_ext';
3623 $fields["phone_ext-{$fieldSuffix}"]['skipDisplay'] = 1;
3624 //ignore required for extension field
3625 $fields["phone_ext-{$fieldSuffix}"]['is_required'] = 0;
3631 * Get the frontend_title for the profile, falling back on 'title' if none.
3633 * @param int $profileID
3637 * @throws \CiviCRM_API3_Exception
3639 public static function getFrontEndTitle(int $profileID) {
3640 $profile = civicrm_api3('UFGroup', 'getsingle', ['id' => $profileID, 'return' => ['title', 'frontend_title']]);
3641 return $profile['frontend_title'] ??
$profile['title'];