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)
288 public static function getFields(
296 $skipPermission = FALSE,
298 $permissionType = CRM_Core_Permission
::CREATE
,
299 $orderBy = 'field_name',
300 $orderProfiles = NULL,
301 $eventProfile = FALSE
303 if (!is_array($id)) {
304 $id = CRM_Utils_Type
::escape($id, 'Positive');
311 $gids = implode(',', $profileIds);
314 $query = "SELECT g.* from civicrm_uf_group g
315 LEFT JOIN civicrm_uf_join j ON (j.uf_group_id = g.id)
316 WHERE g.id IN ( {$gids} )
317 AND ((j.uf_group_id IN ( {$gids} ) AND j.module = %1) OR g.is_reserved = 1 )
319 $params = [1 => [$restrict, 'String']];
322 $query = "SELECT g.* from civicrm_uf_group g WHERE g.id IN ( {$gids} ) ";
326 $query .= " AND g.is_active = 1";
331 'administer CiviCRM',
332 'manage event profiles',
335 if ($eventProfile && CRM_Core_Permission
::check($checkPermission)) {
336 $skipPermission = TRUE;
339 // add permissioning for profiles only if not registration
340 if (!$skipPermission) {
341 $permissionClause = CRM_Core_Permission
::ufGroupClause($permissionType, 'g.');
342 $query .= " AND $permissionClause ";
345 if ($orderProfiles and count($profileIds) > 1) {
346 $query .= " ORDER BY FIELD( g.id, {$gids} )";
348 $group = CRM_Core_DAO
::executeQuery($query, $params);
352 while ($group->fetch()) {
354 $query = self
::createUFFieldQuery($group->id
, $searchable, $showAll, $visibility, $orderBy);
355 $field = CRM_Core_DAO
::executeQuery($query);
357 $importableFields = self
::getProfileFieldMetadata($showAll);
358 list($customFields, $addressCustomFields) = self
::getCustomFields($ctype);
360 while ($field->fetch()) {
361 list($name, $formattedField) = self
::formatUFField($group, $field, $customFields, $addressCustomFields, $importableFields, $permissionType);
362 if ($formattedField !== NULL) {
363 $fields[$name] = $formattedField;
368 if (empty($fields) && !$validGroup) {
369 CRM_Core_Error
::fatal(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.',
370 [1 => implode(',', $profileIds)]
374 self
::reformatProfileFields($fields);
381 * Format a list of UFFields for use with buildProfile. This is the in-memory analog
384 * @param array $groupArr
385 * (mimic CRM_UF_DAO_UFGroup).
386 * @param array $fieldArrs
387 * List of fields (each mimics CRM_UF_DAO_UFField).
388 * @param bool $visibility
389 * Visibility of fields we are interested in.
390 * @param bool $searchable
391 * @param bool $showAll
393 * @param int $permissionType
396 * @see self::getFields
398 public static function formatUFFields(
405 $permissionType = CRM_Core_Permission
::CREATE
407 // $group = new CRM_Core_DAO_UFGroup();
408 // $group->copyValues($groupArr); // no... converts string('') to string('null')
409 $group = (object) $groupArr;
411 // Refactoring note: The $fieldArrs here may be slightly different than the $ufFields
412 // used by calculateGroupType, but I don't think the missing fields matter, and -- if
413 // they did -- the obvious fix would produce mutual recursion.
414 $ufGroupType = self
::_calculateGroupType($fieldArrs);
415 $profileType = CRM_Core_BAO_UFField
::calculateProfileType(implode(',', $ufGroupType));
416 $contactActivityProfile = CRM_Core_BAO_UFField
::checkContactActivityProfileTypeByGroupType(implode(',', $ufGroupType));
417 $importableFields = self
::getImportableFields($showAll, $profileType, $contactActivityProfile);
418 list($customFields, $addressCustomFields) = self
::getCustomFields($ctype);
420 $formattedFields = [];
421 foreach ($fieldArrs as $fieldArr) {
422 $field = (object) $fieldArr;
423 if (!self
::filterUFField($field, $searchable, $showAll, $visibility)) {
427 list($name, $formattedField) = self
::formatUFField($group, $field, $customFields, $addressCustomFields, $importableFields, $permissionType);
428 if ($formattedField !== NULL) {
429 $formattedFields[$name] = $formattedField;
432 return $formattedFields;
436 * Prepare a field for rendering with CRM_Core_BAO_UFGroup::buildProfile.
438 * @param CRM_Core_DAO_UFGroup|CRM_Core_DAO $group
439 * @param CRM_Core_DAO_UFField|CRM_Core_DAO $field
440 * @param array $customFields
441 * @param array $addressCustomFields
442 * @param array $importableFields
443 * @param int $permissionType
444 * Eg CRM_Core_Permission::CREATE.
448 protected static function formatUFField(
452 $addressCustomFields,
454 $permissionType = CRM_Core_Permission
::CREATE
456 $name = $field->field_name
;
457 $title = $field->label
;
459 $addressCustom = FALSE;
460 if (in_array($permissionType, [CRM_Core_Permission
::CREATE
, CRM_Core_Permission
::EDIT
]) &&
461 in_array($field->field_name
, array_keys($addressCustomFields))
463 $addressCustom = TRUE;
464 $name = "address_{$name}";
466 if ($field->field_name
== 'url') {
467 $name .= "-{$field->website_type_id}";
469 elseif (!empty($field->location_type_id
)) {
470 $name .= "-{$field->location_type_id}";
473 $locationFields = self
::getLocationFields();
474 if (in_array($field->field_name
, $locationFields) ||
$addressCustom) {
479 if (isset($field->phone_type_id
)) {
480 $name .= "-{$field->phone_type_id}";
482 $fieldMetaData = CRM_Utils_Array
::value($name, $importableFields, (isset($importableFields[$field->field_name
]) ?
$importableFields[$field->field_name
] : []));
484 // No lie: this is bizarre; why do we need to mix so many UFGroup properties into UFFields?
485 // I guess to make field self sufficient with all the required data and avoid additional calls
488 'groupTitle' => $group->title
,
489 'groupName' => $group->name
,
490 'groupDisplayTitle' => (!empty($group->frontend_title
)) ?
$group->frontend_title
: $group->title
,
491 'groupHelpPre' => empty($group->help_pre
) ?
'' : $group->help_pre
,
492 'groupHelpPost' => empty($group->help_post
) ?
'' : $group->help_post
,
494 'where' => CRM_Utils_Array
::value('where', CRM_Utils_Array
::value($field->field_name
, $importableFields)),
495 'attributes' => CRM_Core_DAO
::makeAttribute(CRM_Utils_Array
::value($field->field_name
, $importableFields)),
496 'is_required' => $field->is_required
,
497 'is_view' => $field->is_view
,
498 'help_pre' => $field->help_pre
,
499 'help_post' => $field->help_post
,
500 'visibility' => $field->visibility
,
501 'in_selector' => $field->in_selector
,
502 'rule' => CRM_Utils_Array
::value('rule', CRM_Utils_Array
::value($field->field_name
, $importableFields)),
503 'location_type_id' => isset($field->location_type_id
) ?
$field->location_type_id
: NULL,
504 'website_type_id' => isset($field->website_type_id
) ?
$field->website_type_id
: NULL,
505 'phone_type_id' => isset($field->phone_type_id
) ?
$field->phone_type_id
: NULL,
506 'group_id' => $group->id
,
507 'add_to_group_id' => isset($group->add_to_group_id
) ?
$group->add_to_group_id
: NULL,
508 'add_captcha' => isset($group->add_captcha
) ?
$group->add_captcha
: NULL,
509 'field_type' => $field->field_type
,
510 'field_id' => $field->id
,
511 'pseudoconstant' => CRM_Utils_Array
::value(
513 CRM_Utils_Array
::value($field->field_name
, $importableFields)
515 // obsolete this when we remove the name / dbName discrepancy with gender/suffix/prefix
516 'dbName' => CRM_Utils_Array
::value(
518 CRM_Utils_Array
::value($field->field_name
, $importableFields)
521 'data_type' => CRM_Utils_Type
::getDataTypeFromFieldMetadata($fieldMetaData),
522 'bao' => CRM_Utils_Array
::value('bao', $fieldMetaData),
525 $formattedField = CRM_Utils_Date
::addDateMetadataToField($fieldMetaData, $formattedField);
527 //adding custom field property
528 if (substr($field->field_name
, 0, 6) == 'custom' ||
529 substr($field->field_name
, 0, 14) === 'address_custom'
531 // if field is not present in customFields, that means the user
532 // DOES NOT HAVE permission to access that field
533 if (array_key_exists($field->field_name
, $customFields)) {
534 $formattedField['is_search_range'] = $customFields[$field->field_name
]['is_search_range'];
536 $formattedField['options_per_line'] = $customFields[$field->field_name
]['options_per_line'];
537 $formattedField['html_type'] = $customFields[$field->field_name
]['html_type'];
539 if (CRM_Utils_Array
::value('html_type', $formattedField) == 'Select Date') {
540 $formattedField['date_format'] = $customFields[$field->field_name
]['date_format'];
541 $formattedField['time_format'] = $customFields[$field->field_name
]['time_format'];
542 $formattedField['is_datetime_field'] = TRUE;
543 $formattedField['smarty_view_format'] = CRM_Utils_Date
::getDateFieldViewFormat($formattedField['date_format']);
546 $formattedField['is_multi_summary'] = $field->is_multi_summary
;
547 return [$name, $formattedField];
550 $formattedField = NULL;
551 return [$name, $formattedField];
554 return [$name, $formattedField];
558 * Create a query to find all visible UFFields in a UFGroup.
560 * This is the SQL-variant of checkUFFieldDisplayable().
562 * @param int $groupId
563 * @param bool $searchable
564 * @param bool $showAll
565 * @param int $visibility
566 * @param string $orderBy
567 * Comma-delimited list of SQL columns.
571 protected static function createUFFieldQuery($groupId, $searchable, $showAll, $visibility, $orderBy) {
572 $where = " WHERE uf_group_id = {$groupId}";
575 $where .= " AND is_searchable = 1";
579 $where .= " AND is_active = 1";
584 if ($visibility & self
::PUBLIC_VISIBILITY
) {
585 $clause[] = 'visibility = "Public Pages"';
587 if ($visibility & self
::ADMIN_VISIBILITY
) {
588 $clause[] = 'visibility = "User and User Admin Only"';
590 if ($visibility & self
::LISTINGS_VISIBILITY
) {
591 $clause[] = 'visibility = "Public Pages and Listings"';
593 if (!empty($clause)) {
594 $where .= ' AND ( ' . implode(' OR ', $clause) . ' ) ';
598 $query = "SELECT * FROM civicrm_uf_field $where ORDER BY weight";
600 $query .= ", " . $orderBy;
607 * Create a query to find all visible UFFields in a UFGroup.
609 * This is the PHP in-memory variant of createUFFieldQuery().
611 * @param CRM_Core_DAO_UFField|CRM_Core_DAO $field
612 * @param bool $searchable
613 * @param bool $showAll
614 * @param int $visibility
617 * TRUE if field is displayable
619 protected static function filterUFField($field, $searchable, $showAll, $visibility) {
620 if ($searchable && $field->is_searchable
!= 1) {
624 if (!$showAll && $field->is_active
!= 1) {
629 $allowedVisibilities = [];
630 if ($visibility & self
::PUBLIC_VISIBILITY
) {
631 $allowedVisibilities[] = 'Public Pages';
633 if ($visibility & self
::ADMIN_VISIBILITY
) {
634 $allowedVisibilities[] = 'User and User Admin Only';
636 if ($visibility & self
::LISTINGS_VISIBILITY
) {
637 $allowedVisibilities[] = 'Public Pages and Listings';
639 // !empty($allowedVisibilities) seems silly to me, but it is equivalent to the pre-existing SQL
640 if (!empty($allowedVisibilities) && !in_array($field->visibility
, $allowedVisibilities)) {
649 * Get a list of filtered field metadata.
652 * @param $profileType
653 * @param $contactActivityProfile
654 * @param bool $filterMode
655 * Filter mode means you are using importable fields for filtering rather than just getting metadata.
656 * With filter mode = FALSE BOTH activity fields and component fields are returned.
657 * I can't see why you would ever want to use this function in filter mode as the component fields are
658 * still unfiltered. However, I feel scared enough to leave it as it is. I have marked this function as
659 * deprecated and am recommending the wrapper 'getProfileFieldMetadata' in order to try to
660 * send this confusion to history.
663 * @deprecated use getProfileFieldMetadata
666 protected static function getImportableFields($showAll, $profileType, $contactActivityProfile, $filterMode = TRUE) {
668 $importableFields = CRM_Contact_BAO_Contact
::importableFields('All', FALSE, FALSE, FALSE, TRUE, TRUE);
671 $importableFields = CRM_Contact_BAO_Contact
::importableFields('All', FALSE, TRUE, FALSE, TRUE, TRUE);
674 $activityFields = CRM_Activity_BAO_Activity
::getProfileFields();
675 $componentFields = CRM_Core_Component
::getQueryFields();
676 if ($filterMode == TRUE) {
677 if ($profileType == 'Activity' ||
$contactActivityProfile) {
678 $importableFields = array_merge($importableFields, $activityFields);
681 $importableFields = array_merge($importableFields, $componentFields);
685 $importableFields = array_merge($importableFields, $activityFields, $componentFields);
688 $importableFields['group']['title'] = ts('Group(s)');
689 $importableFields['group']['where'] = NULL;
690 $importableFields['tag']['title'] = ts('Tag(s)');
691 $importableFields['tag']['where'] = NULL;
692 return $importableFields;
696 * Get the metadata for all potential profile fields.
698 * @param bool $isIncludeInactive
699 * Should disabled fields be included.
702 * Field metadata for all fields that might potentially be in a profile.
704 protected static function getProfileFieldMetadata($isIncludeInactive) {
705 return self
::getImportableFields($isIncludeInactive, NULL, NULL, NULL, TRUE);
709 * Get the fields relating to locations.
713 public static function getLocationFields() {
714 static $locationFields = [
716 'supplemental_address_1',
717 'supplemental_address_2',
718 'supplemental_address_3',
721 'postal_code_suffix',
734 return $locationFields;
742 protected static function getCustomFields($ctype) {
743 static $customFieldCache = [];
744 if (!isset($customFieldCache[$ctype])) {
745 $customFields = CRM_Core_BAO_CustomField
::getFieldsForImport($ctype, FALSE, FALSE, FALSE, TRUE, TRUE);
747 // hack to add custom data for components
748 $components = ['Contribution', 'Participant', 'Membership', 'Activity', 'Case'];
749 foreach ($components as $value) {
750 $customFields = array_merge($customFields, CRM_Core_BAO_CustomField
::getFieldsForImport($value));
752 $addressCustomFields = CRM_Core_BAO_CustomField
::getFieldsForImport('Address');
753 $customFields = array_merge($customFields, $addressCustomFields);
754 $customFieldCache[$ctype] = [$customFields, $addressCustomFields];
756 return $customFieldCache[$ctype];
760 * Check the data validity.
763 * The user id that we are actually editing.
764 * @param string $name
765 * The machine-name of the group we are interested in.
766 * @param bool $register
768 * The action of the form.
770 * @pram boolean $register is this the registrtion form
772 * true if form is valid
774 public static function isValid($userID, $name, $register = FALSE, $action = NULL) {
776 $controller = new CRM_Core_Controller_Simple('CRM_Profile_Form_Dynamic',
777 ts('Dynamic Form Creator'),
780 $controller->set('id', $userID);
781 $controller->set('register', 1);
782 $controller->process();
783 return $controller->validate();
786 // make sure we have a valid group
787 $group = new CRM_Core_DAO_UFGroup();
789 $group->name
= $name;
791 if ($group->find(TRUE) && $userID) {
792 $controller = new CRM_Core_Controller_Simple('CRM_Profile_Form_Dynamic', ts('Dynamic Form Creator'), $action);
793 $controller->set('gid', $group->id
);
794 $controller->set('id', $userID);
795 $controller->set('register', 0);
796 $controller->process();
797 return $controller->validate();
804 * Get the html for the form that represents this particular group.
807 * The user id that we are actually editing.
808 * @param string $title
809 * The title of the group we are interested in.
811 * The action of the form.
812 * @param bool $register
813 * Is this the registration form.
815 * Should we reset the form?.
816 * @param int $profileID
817 * Do we have the profile ID?.
819 * @param bool $doNotProcess
823 * the html for the form on success, otherwise empty string
825 public static function getEditHTML(
832 $doNotProcess = FALSE,
837 $controller = new CRM_Core_Controller_Simple('CRM_Profile_Form_Dynamic',
838 ts('Dynamic Form Creator'),
841 if ($reset ||
$doNotProcess) {
842 // hack to make sure we do not process this form
843 $oldQFDefault = CRM_Utils_Array
::value('_qf_default',
846 unset($_POST['_qf_default']);
847 unset($_REQUEST['_qf_default']);
849 $controller->reset();
853 $controller->set('id', $userID);
854 $controller->set('register', 1);
855 $controller->set('skipPermission', 1);
856 $controller->set('ctype', $ctype);
857 $controller->process();
858 if ($doNotProcess ||
!empty($_POST)) {
859 $controller->validate();
861 $controller->setEmbedded(TRUE);
863 //CRM-5839 - though we want to process form, get the control back.
864 $controller->setSkipRedirection(($doNotProcess) ?
FALSE : TRUE);
868 // we are done processing so restore the POST/REQUEST vars
869 if (($reset ||
$doNotProcess) && $oldQFDefault) {
870 $_POST['_qf_default'] = $_REQUEST['_qf_default'] = $oldQFDefault;
873 $template = CRM_Core_Smarty
::singleton();
875 // Hide CRM error messages if they are displayed using drupal form_set_error.
876 if (!empty($_POST)) {
877 $template->assign('suppressForm', TRUE);
880 return trim($template->fetch('CRM/Profile/Form/Dynamic.tpl'));
884 // make sure we have a valid group
885 $group = new CRM_Core_DAO_UFGroup();
887 $group->title
= $title;
889 if ($group->find(TRUE)) {
890 $profileID = $group->id
;
895 // make sure profileID and ctype match if ctype exists
897 $profileType = CRM_Core_BAO_UFField
::getProfileType($profileID);
898 if (CRM_Contact_BAO_ContactType
::isaSubType($profileType)) {
899 $profileType = CRM_Contact_BAO_ContactType
::getBasicType($profileType);
902 if (($profileType != 'Contact') && ($profileType != $ctype)) {
907 $controller = new CRM_Core_Controller_Simple('CRM_Profile_Form_Dynamic',
908 ts('Dynamic Form Creator'),
912 $controller->reset();
914 $controller->set('gid', $profileID);
915 $controller->set('id', $userID);
916 $controller->set('register', 0);
917 $controller->set('skipPermission', 1);
919 $controller->set('ctype', $ctype);
921 $controller->process();
922 $controller->setEmbedded(TRUE);
924 //CRM-5846 - give the control back to drupal.
925 $controller->setSkipRedirection(($doNotProcess) ?
FALSE : TRUE);
928 $template = CRM_Core_Smarty
::singleton();
930 // Hide CRM error messages if they are displayed using drupal form_set_error.
931 if (!empty($_POST) && CRM_Core_Config
::singleton()->userFramework
== 'Drupal') {
932 if (arg(0) == 'user' ||
(arg(0) == 'admin' && arg(1) == 'people')) {
933 $template->assign('suppressForm', TRUE);
937 $templateFile = "CRM/Profile/Form/{$profileID}/Dynamic.tpl";
938 if (!$template->template_exists($templateFile)) {
939 $templateFile = 'CRM/Profile/Form/Dynamic.tpl';
941 return trim($template->fetch($templateFile));
944 $userEmail = CRM_Contact_BAO_Contact_Location
::getEmailDetails($userID);
946 // if post not empty then only proceed
947 if (!empty($_POST)) {
949 $config = CRM_Core_Config
::singleton();
950 $email = CRM_Utils_Array
::value('mail', $_POST);
952 if (CRM_Utils_Rule
::email($email) && ($email != $userEmail[1])) {
953 CRM_Core_BAO_UFMatch
::updateContactEmail($userID, $email);
962 * Given a contact id and a field set, return the values from the db.
965 * @param array $fields
966 * The profile fields of interest.
967 * @param array $values
968 * The values for the above fields.
969 * @param bool $searchable
971 * @param array $componentWhere
972 * Component condition.
973 * @param bool $absolute
974 * Return urls in absolute form (useful when sending an email).
975 * @param null $additionalWhereClause
979 public static function getValues(
980 $cid, &$fields, &$values,
981 $searchable = TRUE, $componentWhere = NULL,
982 $absolute = FALSE, $additionalWhereClause = NULL
984 if (empty($cid) && empty($componentWhere)) {
988 // get the contact details (hier)
989 $returnProperties = CRM_Contact_BAO_Contact
::makeHierReturnProperties($fields);
990 $params = $cid ?
[['contact_id', '=', $cid, 0, 0]] : [];
992 // add conditions specified by components. eg partcipant_id etc
993 if (!empty($componentWhere)) {
994 $params = array_merge($params, $componentWhere);
997 $query = new CRM_Contact_BAO_Query($params, $returnProperties, $fields);
999 $details = $query->searchQuery(0, 0, NULL, FALSE, FALSE,
1000 FALSE, FALSE, FALSE, $additionalWhereClause);
1001 while ($details->fetch()) {
1006 $query->convertToPseudoNames($details);
1007 $config = CRM_Core_Config
::singleton();
1009 $locationTypes = CRM_Core_PseudoConstant
::get('CRM_Core_DAO_Address', 'location_type_id');
1010 $imProviders = CRM_Core_PseudoConstant
::get('CRM_Core_DAO_IM', 'provider_id');
1011 $websiteTypes = CRM_Core_PseudoConstant
::get('CRM_Core_DAO_Website', 'website_type_id');
1013 $multipleFields = ['url'];
1015 //start of code to set the default values
1016 foreach ($fields as $name => $field) {
1018 if ($name == 'id') {
1019 $name = 'contact_id';
1022 // skip fields that should not be displayed separately
1023 if (!empty($field['skipDisplay'])) {
1027 // Create a unique, non-empty index for each field.
1028 $index = $field['title'];
1029 if ($index === '') {
1032 while (array_key_exists($index, $values)) {
1036 $params[$index] = $values[$index] = '';
1037 $customFieldName = NULL;
1039 if (isset($details->$name) ||
$name == 'group' ||
$name == 'tag') {
1040 // to handle gender / suffix / prefix
1041 if (in_array(substr($name, 0, -3), ['gender', 'prefix', 'suffix'])) {
1042 $params[$index] = $details->$name;
1043 $values[$index] = $details->$name;
1045 elseif (in_array($name, CRM_Contact_BAO_Contact
::$_greetingTypes)) {
1046 $dname = $name . '_display';
1047 $values[$index] = $details->$dname;
1048 $name = $name . '_id';
1049 $params[$index] = $details->$name;
1051 elseif (in_array($name, [
1056 $values[$index] = $details->$name;
1057 $idx = $name . '_id';
1058 $params[$index] = $details->$idx;
1060 elseif ($name === 'preferred_language') {
1061 $params[$index] = $details->$name;
1062 $values[$index] = CRM_Core_PseudoConstant
::getLabel('CRM_Contact_DAO_Contact', 'preferred_language', $details->$name);
1064 elseif ($name == 'group') {
1065 $groups = CRM_Contact_BAO_GroupContact
::getContactGroup($cid, 'Added', NULL, FALSE, TRUE);
1068 foreach ($groups as $g) {
1069 // CRM-8362: User and User Admin visibility groups should be included in display if user has
1070 // VIEW permission on that group
1071 $groupPerm = CRM_Contact_BAO_Group
::checkPermission($g['group_id'], TRUE);
1073 if ($g['visibility'] != 'User and User Admin Only' ||
1074 CRM_Utils_Array
::key(CRM_Core_Permission
::VIEW
, $groupPerm)
1076 $title[] = $g['title'];
1077 if ($g['visibility'] == 'Public Pages') {
1078 $ids[] = $g['group_id'];
1082 $values[$index] = implode(', ', $title);
1083 $params[$index] = implode(',', $ids);
1085 elseif ($name == 'tag') {
1086 $entityTags = CRM_Core_BAO_EntityTag
::getTag($cid);
1087 $allTags = CRM_Core_PseudoConstant
::get('CRM_Core_DAO_EntityTag', 'tag_id', ['onlyActive' => FALSE]);
1089 foreach ($entityTags as $tagId) {
1090 $title[] = $allTags[$tagId];
1092 $values[$index] = implode(', ', $title);
1093 $params[$index] = implode(',', $entityTags);
1095 elseif ($name == 'activity_status_id') {
1096 $activityStatus = CRM_Core_PseudoConstant
::activityStatus();
1097 $values[$index] = $activityStatus[$details->$name];
1098 $params[$index] = $details->$name;
1100 elseif ($name == 'activity_date_time') {
1101 $values[$index] = CRM_Utils_Date
::customFormat($details->$name);
1102 $params[$index] = $details->$name;
1104 elseif ($name == 'contact_sub_type') {
1105 $contactSubTypeNames = explode(CRM_Core_DAO
::VALUE_SEPARATOR
, $details->$name);
1106 if (!empty($contactSubTypeNames)) {
1107 $contactSubTypeLabels = [];
1108 // get all contact subtypes
1109 $allContactSubTypes = CRM_Contact_BAO_ContactType
::subTypeInfo();
1110 // build contact subtype labels array
1111 foreach ($contactSubTypeNames as $cstName) {
1113 $contactSubTypeLabels[] = $allContactSubTypes[$cstName]['label'];
1116 $values[$index] = implode(',', $contactSubTypeLabels);
1119 $params[$index] = $details->$name;
1122 if (substr($name, 0, 7) === 'do_not_' ||
substr($name, 0, 3) === 'is_') {
1123 if ($details->$name) {
1124 $values[$index] = '[ x ]';
1128 if ($cfID = CRM_Core_BAO_CustomField
::getKeyID($name)) {
1129 $htmlType = $field['html_type'];
1131 // field_type is only set when we are retrieving profile values
1132 // when sending email, we call the same function to get custom field
1133 // values etc, i.e. emulating a profile
1134 $fieldType = CRM_Utils_Array
::value('field_type', $field);
1136 if ($htmlType == 'File') {
1139 $fieldType == 'Activity' && !empty($componentWhere[0][2])
1141 $entityId = $componentWhere[0][2];
1144 $fileURL = CRM_Core_BAO_CustomField
::getFileURL($entityId,
1148 $additionalWhereClause
1150 $params[$index] = $values[$index] = $fileURL['file_url'];
1154 if (isset($dao) && property_exists($dao, 'data_type') &&
1155 ($dao->data_type
== 'Int' ||
1156 $dao->data_type
== 'Boolean'
1159 $customVal = (int ) ($details->{$name});
1161 elseif (isset($dao) && property_exists($dao, 'data_type')
1162 && $dao->data_type
== 'Float'
1164 $customVal = (float ) ($details->{$name});
1166 elseif (!CRM_Utils_System
::isNull(explode(CRM_Core_DAO
::VALUE_SEPARATOR
,
1170 $customVal = $details->{$name};
1174 if (CRM_Utils_System
::isNull($customVal)) {
1178 $params[$index] = $customVal;
1179 $values[$index] = CRM_Core_BAO_CustomField
::displayValue($customVal, $cfID);
1180 if ($field['data_type'] == 'ContactReference') {
1181 $params[$index] = $values[$index];
1183 if (CRM_Core_DAO
::getFieldValue('CRM_Core_DAO_CustomField',
1184 $cfID, 'is_search_range'
1187 $customFieldName = "{$name}_from";
1191 elseif ($name == 'image_URL') {
1192 list($width, $height) = getimagesize(CRM_Utils_String
::unstupifyUrl($details->$name));
1193 list($thumbWidth, $thumbHeight) = CRM_Contact_BAO_Contact
::getThumbSize($width, $height);
1195 $image_URL = '<img src="' . $details->$name . '" height= ' . $thumbHeight . ' width= ' . $thumbWidth . ' />';
1196 $values[$index] = "<a href='#' onclick='contactImagePopUp(\"{$details->$name}\", {$width}, {$height});'>{$image_URL}</a>";
1198 elseif (in_array($name, [
1202 // @todo this set should be determined from metadata, not hard-coded.
1203 $values[$index] = CRM_Utils_Date
::customFormat($details->$name);
1204 $params[$index] = CRM_Utils_Date
::isoToMysql($details->$name);
1208 if ($index == 'Campaign') {
1209 $dao = 'CRM_Campaign_DAO_Campaign';
1211 elseif ($index == 'Contribution Page') {
1212 $dao = 'CRM_Contribute_DAO_ContributionPage';
1215 $value = CRM_Core_DAO
::getFieldValue($dao, $details->$name, 'title');
1218 $value = $details->$name;
1220 $values[$index] = $value;
1225 elseif (strpos($name, '-') !== FALSE) {
1226 list($fieldName, $id, $type) = CRM_Utils_System
::explode('-', $name, 3);
1228 if (!in_array($fieldName, $multipleFields)) {
1229 if ($id == 'Primary') {
1231 // not sure why we'd every use Primary location type id
1232 // we need to fix the source if we are using it
1233 // $locationTypeName = CRM_Contact_BAO_Contact::getPrimaryLocationType( $cid );
1234 $locationTypeName = 1;
1237 $locationTypeName = CRM_Utils_Array
::value($id, $locationTypes);
1240 if (!$locationTypeName) {
1244 $detailName = "{$locationTypeName}-{$fieldName}";
1245 $detailName = str_replace(' ', '_', $detailName);
1247 if (in_array($fieldName, [
1254 $detailName .= "-{$type}";
1258 if (in_array($fieldName, [
1263 $values[$index] = $details->$detailName;
1264 $idx = $detailName . '_id';
1265 $params[$index] = $details->$idx;
1267 elseif ($fieldName == 'im') {
1268 $providerId = $detailName . '-provider_id';
1269 if (isset($imProviders[$details->$providerId])) {
1270 $values[$index] = $details->$detailName . " (" . $imProviders[$details->$providerId] . ")";
1273 $values[$index] = $details->$detailName;
1275 $params[$index] = $details->$detailName;
1277 elseif ($fieldName == 'phone') {
1278 $phoneExtField = str_replace('phone', 'phone_ext', $detailName);
1279 if (isset($details->$phoneExtField)) {
1280 $values[$index] = $details->$detailName . " (" . $details->$phoneExtField . ")";
1283 $values[$index] = $details->$detailName;
1285 $params[$index] = $details->$detailName;
1288 $values[$index] = $params[$index] = $details->$detailName;
1292 $detailName = "website-{$id}-{$fieldName}";
1293 $url = CRM_Utils_System
::fixURL($details->$detailName);
1294 if ($details->$detailName) {
1295 $websiteTypeId = "website-{$id}-website_type_id";
1296 $websiteType = $websiteTypes[$details->$websiteTypeId];
1297 $values[$index] = "<a href=\"$url\">{$details->$detailName} ( {$websiteType} )</a>";
1300 $values[$index] = '';
1305 if ((CRM_Utils_Array
::value('visibility', $field) == 'Public Pages and Listings') &&
1306 CRM_Core_Permission
::check('profile listings and forms')
1309 if (CRM_Utils_System
::isNull($params[$index])) {
1310 $params[$index] = $values[$index];
1312 if (!isset($params[$index])) {
1315 if (!$customFieldName) {
1316 $fieldName = $field['name'];
1319 $fieldName = $customFieldName;
1323 if (CRM_Core_BAO_CustomField
::getKeyID($field['name'])) {
1324 $htmlType = $field['html_type'];
1325 if ($htmlType == 'Link') {
1326 $url = $params[$index];
1328 elseif (in_array($htmlType, [
1331 'Multi-Select State/Province',
1332 'Multi-Select Country',
1334 $valSeperator = CRM_Core_DAO
::VALUE_SEPARATOR
;
1335 $selectedOptions = explode($valSeperator, $params[$index]);
1337 foreach ($selectedOptions as $key => $multiOption) {
1339 $url[] = CRM_Utils_System
::url('civicrm/profile',
1340 'reset=1&force=1&gid=' . $field['group_id'] . '&' .
1341 urlencode($fieldName) .
1343 urlencode($multiOption)
1349 $url = CRM_Utils_System
::url('civicrm/profile',
1350 'reset=1&force=1&gid=' . $field['group_id'] . '&' .
1351 urlencode($fieldName) .
1353 urlencode($params[$index])
1358 $url = CRM_Utils_System
::url('civicrm/profile',
1359 'reset=1&force=1&gid=' . $field['group_id'] . '&' .
1360 urlencode($fieldName) .
1362 urlencode($params[$index])
1367 !empty($values[$index]) &&
1371 if (is_array($url) && !empty($url)) {
1373 $eachMultiValue = explode(', ', $values[$index]);
1374 foreach ($eachMultiValue as $key => $valueLabel) {
1375 $links[] = '<a href="' . $url[$key] . '">' . $valueLabel . '</a>';
1377 $values[$index] = implode(', ', $links);
1380 $values[$index] = '<a href="' . $url . '">' . $values[$index] . '</a>';
1388 * Check if profile Group used by any module.
1396 public static function usedByModule($id) {
1397 //check whether this group is used by any module(check uf join records)
1399 FROM civicrm_uf_join
1400 WHERE civicrm_uf_join.uf_group_id=$id";
1402 $dao = new CRM_Core_DAO();
1404 if ($dao->fetch()) {
1413 * Delete the profile Group.
1421 public static function del($id) {
1422 //check whether this group contains any profile fields
1423 $profileField = new CRM_Core_DAO_UFField();
1424 $profileField->uf_group_id
= $id;
1425 $profileField->find();
1426 while ($profileField->fetch()) {
1427 CRM_Core_BAO_UFField
::del($profileField->id
);
1430 //delete records from uf join table
1431 $ufJoin = new CRM_Core_DAO_UFJoin();
1432 $ufJoin->uf_group_id
= $id;
1435 //delete profile group
1436 $group = new CRM_Core_DAO_UFGroup();
1445 * @param array $params
1446 * Reference array contains the values submitted by the form.
1448 * Reference array contains the id.
1453 public static function add(&$params, $ids = []) {
1463 foreach ($fields as $field) {
1464 $params[$field] = CRM_Utils_Array
::value($field, $params, FALSE);
1467 $params['limit_listings_group_id'] = CRM_Utils_Array
::value('group', $params);
1468 $params['add_to_group_id'] = CRM_Utils_Array
::value('add_contact_to_group', $params);
1471 if (!empty($params['group_type']) && is_array($params['group_type'])) {
1472 $params['group_type'] = implode(',', $params['group_type']);
1474 $ufGroup = new CRM_Core_DAO_UFGroup();
1475 $ufGroup->copyValues($params);
1477 $ufGroupID = CRM_Utils_Array
::value('ufgroup', $ids, CRM_Utils_Array
::value('id', $params));
1478 if (!$ufGroupID && empty($params['name'])) {
1479 $ufGroup->name
= CRM_Utils_String
::munge($ufGroup->title
, '_', 56);
1481 $ufGroup->id
= $ufGroupID;
1485 if (!$ufGroupID && empty($params['name'])) {
1486 $ufGroup->name
= $ufGroup->name
. "_{$ufGroup->id}";
1494 * Make uf join entries for an uf group.
1496 * @param array $params
1497 * (reference) an assoc array of name/value pairs.
1498 * @param int $ufGroupId
1501 public static function createUFJoin(&$params, $ufGroupId) {
1502 $groupTypes = CRM_Utils_Array
::value('uf_group_type', $params);
1504 // get ufjoin records for uf group
1505 $ufGroupRecord = CRM_Core_BAO_UFGroup
::getUFJoinRecord($ufGroupId);
1507 // get the list of all ufgroup types
1508 $allUFGroupType = CRM_Core_SelectValues
::ufGroupTypes();
1510 // this fix is done to prevent warning generated by array_key_exits incase of empty array is given as input
1511 if (!is_array($groupTypes)) {
1515 // this fix is done to prevent warning generated by array_key_exits incase of empty array is given as input
1516 if (!is_array($ufGroupRecord)) {
1517 $ufGroupRecord = [];
1520 // check which values has to be inserted/deleted for contact
1521 $menuRebuild = FALSE;
1522 foreach ($allUFGroupType as $key => $value) {
1524 $joinParams['uf_group_id'] = $ufGroupId;
1525 $joinParams['module'] = $key;
1526 if ($key == 'User Account') {
1527 $menuRebuild = TRUE;
1529 if (array_key_exists($key, $groupTypes) && !in_array($key, $ufGroupRecord)) {
1530 // insert a new record
1531 CRM_Core_BAO_UFGroup
::addUFJoin($joinParams);
1533 elseif (!array_key_exists($key, $groupTypes) && in_array($key, $ufGroupRecord)) {
1534 // delete a record for existing ufgroup
1535 CRM_Core_BAO_UFGroup
::delUFJoin($joinParams);
1541 UPDATE civicrm_uf_join
1543 WHERE uf_group_id = %2
1544 AND ( entity_id IS NULL OR entity_id <= 0 )
1547 1 => [$params['weight'], 'Integer'],
1548 2 => [$ufGroupId, 'Integer'],
1550 CRM_Core_DAO
::executeQuery($query, $p);
1552 // Do a menu rebuild, so it gets all the new menu entries for user account
1554 $config = CRM_Core_Config
::singleton();
1555 $config->userSystem
->updateCategories();
1560 * Get the UF Join records for an ufgroup id.
1562 * @param int $ufGroupId
1564 * @param int $displayName
1565 * If set return display name in array.
1566 * @param int $status
1567 * If set return module other than default modules (User Account/User registration/Profile).
1572 public static function getUFJoinRecord($ufGroupId = NULL, $displayName = NULL, $status = NULL) {
1575 $UFGroupType = CRM_Core_SelectValues
::ufGroupTypes();
1579 $dao = new CRM_Core_DAO_UFJoin();
1582 $dao->uf_group_id
= $ufGroupId;
1588 while ($dao->fetch()) {
1589 if (!$displayName) {
1590 $ufJoin[$dao->id
] = $dao->module
;
1593 if (isset($UFGroupType[$dao->module
])) {
1594 // skip the default modules
1596 $ufJoin[$dao->id
] = $UFGroupType[$dao->module
];
1598 // added for CRM-1475
1600 elseif (!CRM_Utils_Array
::key($dao->module
, $ufJoin)) {
1601 $ufJoin[$dao->id
] = $dao->module
;
1609 * Function takes an associative array and creates a ufjoin record for ufgroup.
1611 * @param array $params
1612 * (reference) an assoc array of name/value pairs.
1614 * @return CRM_Core_BAO_UFJoin
1616 public static function addUFJoin(&$params) {
1617 $ufJoin = new CRM_Core_DAO_UFJoin();
1618 $ufJoin->copyValues($params);
1624 * Delete the uf join record for an uf group.
1626 * @param array $params
1627 * (reference) an assoc array of name/value pairs.
1629 public static function delUFJoin(&$params) {
1630 $ufJoin = new CRM_Core_DAO_UFJoin();
1631 $ufJoin->copyValues($params);
1636 * Get the weight for ufjoin record.
1638 * @param int $ufGroupId
1639 * If $ufGroupId get update weight or add weight.
1642 * weight of the UFGroup
1644 public static function getWeight($ufGroupId = NULL) {
1645 //calculate the weight
1648 $queryString = "SELECT ( MAX(civicrm_uf_join.weight)+1) as new_weight
1649 FROM civicrm_uf_join
1650 WHERE module = 'User Registration' OR module = 'User Account' OR module = 'Profile'";
1653 $queryString = "SELECT MAX(civicrm_uf_join.weight) as new_weight
1654 FROM civicrm_uf_join
1655 WHERE civicrm_uf_join.uf_group_id = %1
1656 AND ( entity_id IS NULL OR entity_id <= 0 )";
1657 $p[1] = [$ufGroupId, 'Integer'];
1660 $dao = CRM_Core_DAO
::executeQuery($queryString, $p);
1662 return ($dao->new_weight
) ?
$dao->new_weight
: 1;
1666 * Get the uf group for a module.
1668 * @param string $moduleName
1671 * No to increment the weight.
1672 * @param bool $skipPermission
1674 * Which operation (view, edit, create, etc) to check permission for.
1675 * @param array|NULL $returnFields list of UFGroup fields to return; NULL for default
1678 * array of ufgroups for a module
1680 public static function getModuleUFGroup($moduleName = NULL, $count = 0, $skipPermission = TRUE, $op = CRM_Core_Permission
::VIEW
, $returnFields = NULL) {
1681 $selectFields = ['id', 'title', 'created_id', 'is_active', 'is_reserved', 'group_type'];
1683 if (CRM_Core_BAO_SchemaHandler
::checkIfFieldExists('civicrm_uf_group', 'description')) {
1684 // CRM-13555, since description field was added later (4.4), and to avoid any problems with upgrade
1685 $selectFields[] = 'description';
1688 if (CRM_Core_BAO_SchemaHandler
::checkIfFieldExists('civicrm_uf_group', 'frontend_title')) {
1689 $selectFields[] = 'frontend_title';
1692 if (!empty($returnFields)) {
1693 $selectFields = array_merge($returnFields, array_diff($selectFields, $returnFields));
1696 $queryString = 'SELECT civicrm_uf_group.' . implode(', civicrm_uf_group.', $selectFields) . '
1697 FROM civicrm_uf_group
1698 LEFT JOIN civicrm_uf_join ON (civicrm_uf_group.id = uf_group_id)';
1701 $queryString .= ' AND civicrm_uf_group.is_active = 1
1702 WHERE civicrm_uf_join.module = %2';
1703 $p[2] = [$moduleName, 'String'];
1706 // add permissioning for profiles only if not registration
1707 if (!$skipPermission) {
1708 $permissionClause = CRM_Core_Permission
::ufGroupClause($op, 'civicrm_uf_group.');
1709 if (strpos($queryString, 'WHERE') !== FALSE) {
1710 $queryString .= " AND $permissionClause ";
1713 $queryString .= " $permissionClause ";
1717 $queryString .= ' ORDER BY civicrm_uf_join.weight, civicrm_uf_group.title';
1718 $dao = CRM_Core_DAO
::executeQuery($queryString, $p);
1721 while ($dao->fetch()) {
1722 //skip mix profiles in user Registration / User Account
1723 if (($moduleName === 'User Registration' ||
$moduleName === 'User Account') &&
1724 CRM_Core_BAO_UFField
::checkProfileType($dao->id
)
1728 foreach ($selectFields as $key => $field) {
1729 if ($field === 'id') {
1732 $ufGroups[$dao->id
][$field] = $dao->$field;
1736 // Allow other modules to alter/override the UFGroups.
1737 CRM_Utils_Hook
::buildUFGroupsForModule($moduleName, $ufGroups);
1743 * Filter ufgroups based on logged in user contact type.
1745 * @param int $ufGroupId
1746 * Uf group id (profile id).
1747 * @param int $contactID
1752 public static function filterUFGroups($ufGroupId, $contactID = NULL) {
1754 $session = CRM_Core_Session
::singleton();
1755 $contactID = $session->get('userID');
1759 //get the contact type
1760 $contactType = CRM_Contact_BAO_Contact
::getContactType($contactID);
1762 //match if exixting contact type is same as profile contact type
1763 $profileType = CRM_Core_BAO_UFField
::getProfileType($ufGroupId);
1765 if (CRM_Contact_BAO_ContactType
::isaSubType($profileType)) {
1766 $profileType = CRM_Contact_BAO_ContactType
::getBasicType($profileType);
1768 //in some cases getBasicType() returns a cached array instead of string. Example: array ('sponsor' => 'organization')
1769 if (is_array($profileType)) {
1770 $profileType = array_shift($profileType);
1774 //allow special mix profiles for Contribution and Participant
1775 $specialProfiles = ['Contribution', 'Participant', 'Membership'];
1777 if (in_array($profileType, $specialProfiles)) {
1781 if (($contactType == $profileType) ||
$profileType == 'Contact') {
1790 * Add profile field to a form.
1792 * @param CRM_Core_Form $form
1793 * @param array $field
1797 * @param int $contactId
1798 * @param bool $online
1799 * @param string $usedFor
1800 * For building up prefixed fieldname for special cases (e.g. onBehalf, Honor).
1801 * @param int $rowNumber
1802 * @param string $prefix
1806 public static function buildProfile(
1816 $defaultValues = [];
1817 $fieldName = $field['name'];
1818 $title = $field['title'];
1819 $attributes = $field['attributes'];
1820 $rule = $field['rule'];
1821 $view = $field['is_view'];
1822 $required = ($mode == CRM_Profile_Form
::MODE_SEARCH
) ?
FALSE : $field['is_required'];
1823 $search = ($mode == CRM_Profile_Form
::MODE_SEARCH
) ?
TRUE : FALSE;
1824 $isShared = CRM_Utils_Array
::value('is_shared', $field, 0);
1826 // do not display view fields in drupal registration form
1828 if ($view && $mode == CRM_Profile_Form
::MODE_REGISTER
) {
1832 if ($usedFor == 'onbehalf') {
1833 $name = "onbehalf[$fieldName]";
1835 elseif ($usedFor == 'honor') {
1836 $name = "honor[$fieldName]";
1838 elseif ($contactId && !$online) {
1839 $name = "field[$contactId][$fieldName]";
1841 elseif ($rowNumber) {
1842 $name = "field[$rowNumber][$fieldName]";
1844 elseif (!empty($prefix)) {
1845 $name = $prefix . "[$fieldName]";
1851 $selectAttributes = ['class' => 'crm-select2', 'placeholder' => TRUE];
1853 if ($fieldName == 'image_URL' && $mode == CRM_Profile_Form
::MODE_EDIT
) {
1854 $deleteExtra = json_encode(ts('Are you sure you want to delete contact image.'));
1856 CRM_Core_Action
::DELETE
=> [
1857 'name' => ts('Delete Contact Image'),
1858 'url' => 'civicrm/contact/image',
1859 'qs' => 'reset=1&id=%%id%%&gid=%%gid%%&action=delete',
1860 'extra' => 'onclick = "' . htmlspecialchars("if (confirm($deleteExtra)) this.href+='&confirmed=1'; else return false;") . '"',
1863 $deleteURL = CRM_Core_Action
::formLink($deleteURL,
1864 CRM_Core_Action
::DELETE
,
1866 'id' => $form->get('id'),
1867 'gid' => $form->get('gid'),
1871 'contact.profileimage.delete',
1875 $form->assign('deleteURL', $deleteURL);
1877 $addressOptions = CRM_Core_BAO_Setting
::valueOptions(CRM_Core_BAO_Setting
::SYSTEM_PREFERENCES_NAME
,
1878 'address_options', TRUE, NULL, TRUE
1881 if (substr($fieldName, 0, 14) === 'state_province') {
1882 $form->addChainSelect($name, ['label' => $title, 'required' => $required]);
1883 $config = CRM_Core_Config
::singleton();
1884 if (!in_array($mode, [CRM_Profile_Form
::MODE_EDIT
, CRM_Profile_Form
::MODE_SEARCH
]) &&
1885 $config->defaultContactStateProvince
1887 $defaultValues[$name] = $config->defaultContactStateProvince
;
1888 $form->setDefaults($defaultValues);
1891 elseif (substr($fieldName, 0, 7) === 'country') {
1892 $form->add('select', $name, $title, ['' => ts('- select -')] + CRM_Core_PseudoConstant
::country(), $required, $selectAttributes);
1893 $config = CRM_Core_Config
::singleton();
1894 if (!in_array($mode, [CRM_Profile_Form
::MODE_EDIT
, CRM_Profile_Form
::MODE_SEARCH
]) &&
1895 $config->defaultContactCountry
1897 $defaultValues[$name] = $config->defaultContactCountry
;
1898 $form->setDefaults($defaultValues);
1901 elseif (substr($fieldName, 0, 6) === 'county') {
1902 if ($addressOptions['county']) {
1903 $form->addChainSelect($name, ['label' => $title, 'required' => $required]);
1906 elseif (substr($fieldName, 0, 9) === 'image_URL') {
1907 $form->add('file', $name, $title, $attributes, $required);
1908 $form->addUploadElement($name);
1910 elseif (substr($fieldName, 0, 2) === 'im') {
1911 $form->add('text', $name, $title, $attributes, $required);
1914 if (substr($name, -1) === ']') {
1915 $providerName = substr($name, 0, -1) . '-provider_id]';
1917 $form->add('select', $providerName, NULL,
1919 '' => ts('- select -'),
1920 ] + CRM_Core_PseudoConstant
::get('CRM_Core_DAO_IM', 'provider_id'), $required
1924 $form->add('select', $name . '-provider_id', $title,
1926 '' => ts('- select -'),
1927 ] + CRM_Core_PseudoConstant
::get('CRM_Core_DAO_IM', 'provider_id'), $required
1931 if ($view && $mode != CRM_Profile_Form
::MODE_SEARCH
) {
1932 $form->freeze($name . '-provider_id');
1936 elseif (CRM_Utils_Array
::value('name', $field) == 'membership_type') {
1937 list($orgInfo, $types) = CRM_Member_BAO_MembershipType
::getMembershipTypeInfo();
1938 $sel = &$form->addElement('hierselect', $name, $title);
1939 $select = ['' => ts('- select -')];
1940 if (count($orgInfo) == 1 && $field['is_required']) {
1941 // we only have one org - so we should default to it. Not sure about defaulting to first type
1942 // as it could be missed - so adding a select
1943 // however, possibly that is more similar to the membership form
1944 if (count($types[1]) > 1) {
1945 $types[1] = $select +
$types[1];
1949 $orgInfo = $select +
$orgInfo;
1951 $sel->setOptions([$orgInfo, $types]);
1953 elseif (CRM_Utils_Array
::value('name', $field) == 'membership_status') {
1954 $form->add('select', $name, $title,
1956 '' => ts('- select -'),
1957 ] + CRM_Member_PseudoConstant
::membershipStatus(NULL, NULL, 'label'), $required
1960 elseif (in_array($fieldName, ['gender_id', 'communication_style_id'])) {
1962 $pseudoValues = CRM_Core_PseudoConstant
::get('CRM_Contact_DAO_Contact', $fieldName);
1963 foreach ($pseudoValues as $key => $var) {
1964 $options[$key] = $form->createElement('radio', NULL, ts($title), $var, $key);
1966 $group = $form->addGroup($options, $name, $title);
1968 $form->addRule($name, ts('%1 is a required field.', [1 => $title]), 'required');
1971 $group->setAttribute('allowClear', TRUE);
1974 elseif ($fieldName === 'prefix_id' ||
$fieldName === 'suffix_id') {
1975 $form->addSelect($name, [
1977 'entity' => 'contact',
1978 'field' => $fieldName,
1980 'placeholder' => '',
1983 elseif ($fieldName === 'contact_sub_type') {
1984 $gId = $form->get('gid') ?
$form->get('gid') : CRM_Utils_Array
::value('group_id', $field);
1985 if ($usedFor == 'onbehalf') {
1986 $profileType = 'Organization';
1988 elseif ($usedFor == 'honor') {
1989 $profileType = CRM_Core_BAO_UFField
::getProfileType($form->_params
['honoree_profile_id']);
1992 $profileType = $gId ? CRM_Core_BAO_UFField
::getProfileType($gId) : NULL;
1993 if ($profileType == 'Contact') {
1994 $profileType = 'Individual';
1998 $setSubtype = FALSE;
1999 if (CRM_Contact_BAO_ContactType
::isaSubType($profileType)) {
2000 $setSubtype = $profileType;
2001 $profileType = CRM_Contact_BAO_ContactType
::getBasicType($profileType);
2004 $subtypes = $profileType ? CRM_Contact_BAO_ContactType
::subTypePairs($profileType) : [];
2008 $subtypeList[$setSubtype] = $subtypes[$setSubtype];
2011 $subtypeList = $subtypes;
2014 $form->add('select', $name, $title, $subtypeList, $required, ['class' => 'crm-select2', 'multiple' => TRUE]);
2016 elseif (in_array($fieldName, CRM_Contact_BAO_Contact
::$_greetingTypes)) {
2017 // Get contact type for greeting selector
2018 $gId = $form->get('gid') ?
: CRM_Utils_Array
::value('group_id', $field);
2019 $profileType = CRM_Core_BAO_UFField
::getProfileType($gId, TRUE, FALSE, TRUE);
2021 if (!$profileType ||
in_array($profileType, ['Contact', 'Contribution', 'Participant', 'Membership'])) {
2022 $profileType = ($profileType == 'Contact' && $form->get('id')) ? CRM_Contact_BAO_Contact
::getContactType($form->get('id')) : 'Individual';
2024 if (CRM_Contact_BAO_ContactType
::isaSubType($profileType)) {
2025 $profileType = CRM_Contact_BAO_ContactType
::getBasicType($profileType);
2028 'contact_type' => $profileType,
2029 'greeting_type' => $fieldName,
2031 $form->add('select', $name, $title, ['' => ts('- select -')] + CRM_Core_PseudoConstant
::greeting($greeting), $required);
2032 // add custom greeting element
2033 $form->add('text', $fieldName . '_custom', ts('Custom %1', [1 => ucwords(str_replace('_', ' ', $fieldName))]),
2037 elseif ($fieldName === 'preferred_communication_method') {
2038 $communicationFields = CRM_Core_PseudoConstant
::get('CRM_Contact_DAO_Contact', 'preferred_communication_method');
2039 foreach ($communicationFields as $key => $var) {
2043 $communicationOptions[] = $form->createElement('checkbox', $key, NULL, $var);
2045 $form->addGroup($communicationOptions, $name, $title, '<br/>');
2047 elseif ($fieldName === 'preferred_mail_format') {
2048 $form->add('select', $name, $title, CRM_Core_SelectValues
::pmf());
2050 elseif ($fieldName === 'preferred_language') {
2051 $form->add('select', $name, $title, ['' => ts('- select -')] + CRM_Contact_BAO_Contact
::buildOptions('preferred_language'));
2053 elseif ($fieldName == 'external_identifier') {
2054 $form->add('text', $name, $title, $attributes, $required);
2055 $contID = $contactId;
2057 $contID = $form->get('id');
2059 $form->addRule($name,
2060 ts('External ID already exists in Database.'),
2062 ['CRM_Contact_DAO_Contact', $contID, 'external_identifier']
2065 elseif ($fieldName === 'group') {
2066 CRM_Contact_Form_Edit_TagsAndGroups
::buildQuickForm($form, $contactId,
2067 CRM_Contact_Form_Edit_TagsAndGroups
::GROUP
,
2072 elseif ($fieldName === 'tag') {
2073 CRM_Contact_Form_Edit_TagsAndGroups
::buildQuickForm($form, $contactId,
2074 CRM_Contact_Form_Edit_TagsAndGroups
::TAG
,
2079 elseif (substr($fieldName, 0, 4) === 'url-') {
2080 $form->add('text', $name, $title, CRM_Core_DAO
::getAttribute('CRM_Core_DAO_Website', 'url'), $required);
2081 $form->addRule($name, ts('Enter a valid web address beginning with \'http://\' or \'https://\'.'), 'url');
2083 // Note should be rendered as textarea
2084 elseif (substr($fieldName, -4) == 'note') {
2085 $form->add('textarea', $name, $title, $attributes, $required);
2087 elseif (substr($fieldName, 0, 6) === 'custom') {
2088 $customFieldID = CRM_Core_BAO_CustomField
::getKeyID($fieldName);
2089 if ($customFieldID) {
2090 CRM_Core_BAO_CustomField
::addQuickFormElement($form, $name, $customFieldID, $required, $search, $title);
2093 elseif (substr($fieldName, 0, 14) === 'address_custom') {
2094 list($fName, $locTypeId) = CRM_Utils_System
::explode('-', $fieldName, 2);
2095 $customFieldID = CRM_Core_BAO_CustomField
::getKeyID(substr($fName, 8));
2096 if ($customFieldID) {
2097 CRM_Core_BAO_CustomField
::addQuickFormElement($form, $name, $customFieldID, $required, $search, $title);
2100 elseif ($fieldName == 'send_receipt') {
2101 $form->addElement('checkbox', $name, $title);
2103 elseif ($fieldName == 'soft_credit') {
2104 $form->addEntityRef("soft_credit_contact_id[$rowNumber]", ts('Soft Credit To'), ['create' => TRUE]);
2105 $form->addMoney("soft_credit_amount[{$rowNumber}]", ts('Amount'), FALSE, NULL, FALSE);
2107 elseif ($fieldName === 'product_name') {
2108 list($products, $options) = CRM_Contribute_BAO_Premium
::getPremiumProductInfo();
2109 $sel = &$form->addElement('hierselect', $name, $title);
2110 $products = ['0' => ts('- select -')] +
$products;
2111 $sel->setOptions([$products, $options]);
2113 elseif ($fieldName === 'payment_instrument') {
2114 $form->add('select', $name, $title,
2115 ['' => ts('- select -')] + CRM_Contribute_PseudoConstant
::paymentInstrument(), $required);
2117 elseif ($fieldName === 'financial_type') {
2118 $form->add('select', $name, $title,
2120 '' => ts('- select -'),
2121 ] + CRM_Contribute_PseudoConstant
::financialType(), $required
2124 elseif ($fieldName === 'contribution_status_id') {
2125 $contributionStatuses = CRM_Contribute_PseudoConstant
::contributionStatus();
2126 $statusName = CRM_Contribute_PseudoConstant
::contributionStatus(NULL, 'name');
2127 foreach (['In Progress', 'Overdue', 'Refunded'] as $suppress) {
2128 unset($contributionStatuses[CRM_Utils_Array
::key($suppress, $statusName)]);
2131 $form->add('select', $name, $title,
2133 '' => ts('- select -'),
2134 ] +
$contributionStatuses, $required
2137 elseif ($fieldName === 'soft_credit_type') {
2138 $name = "soft_credit_type[$rowNumber]";
2139 $form->add('select', $name, $title,
2141 '' => ts('- select -'),
2142 ] + CRM_Core_OptionGroup
::values("soft_credit_type")
2144 //CRM-15350: choose SCT field default value as 'Gift' for membership use
2145 //else (for contribution), use configured SCT default value
2146 $SCTDefaultValue = CRM_Core_OptionGroup
::getDefaultValue("soft_credit_type");
2147 if ($field['field_type'] == 'Membership') {
2148 $SCTDefaultValue = CRM_Core_PseudoConstant
::getKey('CRM_Contribute_BAO_ContributionSoft', 'soft_credit_type_id', 'gift');
2150 $form->addElement('hidden', 'sct_default_id', $SCTDefaultValue, ['id' => 'sct_default_id']);
2152 elseif ($fieldName == 'contribution_soft_credit_pcp_id') {
2153 CRM_Contribute_Form_SoftCredit
::addPCPFields($form, "[$rowNumber]");
2155 elseif ($fieldName == 'currency') {
2156 $form->addCurrency($name, $title, $required, NULL, FALSE, FALSE);
2158 elseif ($fieldName == 'contribution_page_id') {
2159 $form->add('select', $name, $title,
2161 '' => ts('- select -'),
2162 ] + CRM_Contribute_PseudoConstant
::contributionPage(), $required, 'class="big"'
2165 elseif ($fieldName == 'activity_status_id') {
2166 $form->add('select', $name, $title,
2168 '' => ts('- select -'),
2169 ] + CRM_Core_PseudoConstant
::activityStatus(), $required
2172 elseif ($fieldName == 'activity_engagement_level') {
2173 $form->add('select', $name, $title,
2175 '' => ts('- select -'),
2176 ] + CRM_Campaign_PseudoConstant
::engagementLevel(), $required
2179 elseif ($fieldName == 'participant_status') {
2181 if ($online == TRUE) {
2182 $cond = 'visibility_id = 1';
2184 $form->add('select', $name, $title,
2186 '' => ts('- select -'),
2187 ] + CRM_Event_PseudoConstant
::participantStatus(NULL, $cond, 'label'), $required
2190 elseif ($fieldName == 'participant_role') {
2191 if (!empty($field['is_multiple'])) {
2192 $form->addCheckBox($name, $title, CRM_Event_PseudoConstant
::participantRole(), NULL, NULL, NULL, NULL, ' ', TRUE);
2195 $form->add('select', $name, $title,
2197 '' => ts('- select -'),
2198 ] + CRM_Event_PseudoConstant
::participantRole(), $required
2202 elseif ($fieldName == 'world_region') {
2203 $form->add('select', $name, $title, CRM_Core_PseudoConstant
::worldRegion(), $required, $selectAttributes);
2205 elseif ($fieldName == 'signature_html') {
2206 $form->add('wysiwyg', $name, $title, CRM_Core_DAO
::getAttribute('CRM_Core_DAO_Email', $fieldName));
2208 elseif ($fieldName == 'signature_text') {
2209 $form->add('textarea', $name, $title, CRM_Core_DAO
::getAttribute('CRM_Core_DAO_Email', $fieldName));
2211 elseif (substr($fieldName, -11) == 'campaign_id') {
2212 if (CRM_Campaign_BAO_Campaign
::isCampaignEnable()) {
2213 $campaigns = CRM_Campaign_BAO_Campaign
::getCampaigns(CRM_Utils_Array
::value($contactId,
2214 $form->_componentCampaigns
2216 $form->add('select', $name, $title,
2218 '' => ts('- select -'),
2219 ] +
$campaigns, $required, 'class="crm-select2 big"'
2223 elseif ($fieldName == 'activity_details') {
2224 $form->add('wysiwyg', $fieldName, $title, ['rows' => 4, 'cols' => 60], $required);
2226 elseif ($fieldName == 'activity_duration') {
2227 $form->add('text', $name, $title, $attributes, $required);
2228 $form->addRule($name, ts('Please enter the duration as number of minutes (integers only).'), 'positiveInteger');
2230 elseif ($fieldName == 'case_status') {
2231 $form->add('select', $name, $title,
2233 '' => ts('- select -'),
2234 ] + CRM_Case_BAO_Case
::buildOptions('case_status_id', 'create'),
2239 if (substr($fieldName, 0, 3) === 'is_' or substr($fieldName, 0, 7) === 'do_not_') {
2240 $form->add('advcheckbox', $name, $title, $attributes, $required);
2242 elseif (CRM_Utils_Array
::value('html_type', $field) === 'Select Date') {
2243 $extra = isset($field['datepicker']) ?
$field['datepicker']['extra'] : CRM_Utils_Date
::getDatePickerExtra($field);
2244 $attributes = isset($field['datepicker']) ?
$field['datepicker']['attributes'] : CRM_Utils_Date
::getDatePickerAttributes($field);
2245 $form->add('datepicker', $name, $title, $attributes, $required, $extra);
2248 $form->add('text', $name, $title, $attributes, $required);
2252 static $hiddenSubtype = FALSE;
2253 if (!$hiddenSubtype && CRM_Contact_BAO_ContactType
::isaSubType($field['field_type'])) {
2254 // In registration mode params are submitted via POST and we don't have any clue
2255 // about profile-id or the profile-type (which could be a subtype)
2256 // To generalize the behavior and simplify the process,
2257 // lets always add the hidden
2258 //subtype value if there is any, and we won't have to
2259 // compute it while processing.
2261 $form->addElement('hidden', $usedFor . '[contact_sub_type]', $field['field_type']);
2264 $form->addElement('hidden', 'contact_sub_type_hidden', $field['field_type']);
2266 $hiddenSubtype = TRUE;
2269 if (($view && $mode != CRM_Profile_Form
::MODE_SEARCH
) ||
$isShared) {
2270 $form->freeze($name);
2274 if (in_array($fieldName, [
2275 'non_deductible_amount',
2280 $form->addRule($name, ts('Please enter a valid amount.'), 'money');
2283 if (!($rule == 'email' && $mode == CRM_Profile_Form
::MODE_SEARCH
)) {
2284 $form->addRule($name, ts('Please enter a valid %1', [1 => $title]), $rule);
2290 * Set profile defaults.
2292 * @param int $contactId
2294 * @param array $fields
2295 * Associative array of fields.
2296 * @param array $defaults
2298 * @param bool $singleProfile
2299 * True for single profile else false(Update multiple items).
2300 * @param int $componentId
2301 * Id for specific components like contribute, event etc.
2302 * @param null $component
2304 public static function setProfileDefaults(
2305 $contactId, &$fields, &$defaults,
2306 $singleProfile = TRUE, $componentId = NULL, $component = NULL
2308 if (!$componentId) {
2309 //get the contact details
2310 list($contactDetails, $options) = CRM_Contact_BAO_Contact
::getHierContactDetails($contactId, $fields);
2311 $details = CRM_Utils_Array
::value($contactId, $contactDetails);
2312 $multipleFields = ['website' => 'url'];
2314 //start of code to set the default values
2315 foreach ($fields as $name => $field) {
2316 // skip pseudo fields
2317 if (substr($name, 0, 9) == 'phone_ext') {
2321 //set the field name depending upon the profile mode(single/multiple)
2322 if ($singleProfile) {
2326 $fldName = "field[$contactId][$name]";
2329 if ($name == 'group') {
2330 CRM_Contact_Form_Edit_TagsAndGroups
::setDefaults($contactId, $defaults, CRM_Contact_Form_Edit_TagsAndGroups
::GROUP
, $fldName);
2332 if ($name == 'tag') {
2333 CRM_Contact_Form_Edit_TagsAndGroups
::setDefaults($contactId, $defaults, CRM_Contact_Form_Edit_TagsAndGroups
::TAG
, $fldName);
2336 if (!empty($details[$name]) ||
isset($details[$name])) {
2337 //to handle custom data (checkbox) to be written
2338 // to handle birth/deceased date, greeting_type and few other fields
2339 if (in_array($name, CRM_Contact_BAO_Contact
::$_greetingTypes)) {
2340 $defaults[$fldName] = $details[$name . '_id'];
2341 $defaults[$name . '_custom'] = $details[$name . '_custom'];
2343 elseif ($name == 'preferred_communication_method') {
2344 $v = $details[$name];
2345 if (!is_array($details[$name])) {
2346 $v = explode(CRM_Core_DAO
::VALUE_SEPARATOR
, $v);
2348 foreach ($v as $item) {
2350 $defaults[$fldName . "[$item]"] = 1;
2354 elseif ($name == 'contact_sub_type') {
2355 $defaults[$fldName] = explode(CRM_Core_DAO
::VALUE_SEPARATOR
, trim($details[$name], CRM_Core_DAO
::VALUE_SEPARATOR
));
2357 elseif ($name == 'world_region') {
2358 $defaults[$fldName] = $details['worldregion_id'];
2360 elseif ($customFieldId = CRM_Core_BAO_CustomField
::getKeyID($name)) {
2361 // @todo retrieving the custom fields here seems obsolete - $field holds more data for the fields.
2362 $customFields = CRM_Core_BAO_CustomField
::getFields(CRM_Utils_Array
::value('contact_type', $details));
2364 // hack to add custom data for components
2365 $components = ['Contribution', 'Participant', 'Membership', 'Activity'];
2366 foreach ($components as $value) {
2367 $customFields = CRM_Utils_Array
::crmArrayMerge($customFields,
2368 CRM_Core_BAO_CustomField
::getFieldsForImport($value)
2372 switch ($customFields[$customFieldId]['html_type']) {
2373 case 'Multi-Select State/Province':
2374 case 'Multi-Select Country':
2375 case 'Multi-Select':
2376 $v = explode(CRM_Core_DAO
::VALUE_SEPARATOR
, $details[$name]);
2377 foreach ($v as $item) {
2379 $defaults[$fldName][$item] = $item;
2385 $v = explode(CRM_Core_DAO
::VALUE_SEPARATOR
, $details[$name]);
2386 foreach ($v as $item) {
2388 $defaults[$fldName][$item] = 1;
2389 // seems like we need this for QF style checkboxes in profile where its multiindexed
2391 $defaults["{$fldName}[{$item}]"] = 1;
2397 $defaults[$fldName] = $details[$name];
2402 $defaults[$fldName] = $details[$name];
2406 $blocks = ['email', 'phone', 'im', 'openid'];
2407 list($fieldName, $locTypeId, $phoneTypeId) = CRM_Utils_System
::explode('-', $name, 3);
2408 if (!in_array($fieldName, $multipleFields)) {
2409 if (is_array($details)) {
2410 foreach ($details as $key => $value) {
2411 // when we fixed CRM-5319 - get primary loc
2412 // type as per loc field and removed below code.
2413 $primaryLocationType = FALSE;
2414 if ($locTypeId == 'Primary') {
2415 if (is_array($value) && array_key_exists($fieldName, $value)) {
2416 $primaryLocationType = TRUE;
2417 if (in_array($fieldName, $blocks)) {
2418 $locTypeId = CRM_Contact_BAO_Contact
::getPrimaryLocationType($contactId, FALSE, $fieldName);
2421 $locTypeId = CRM_Contact_BAO_Contact
::getPrimaryLocationType($contactId, FALSE, 'address');
2426 // fixed for CRM-665
2427 if (is_numeric($locTypeId)) {
2428 if ($primaryLocationType ||
$locTypeId == CRM_Utils_Array
::value('location_type_id', $value)) {
2429 if (!empty($value[$fieldName])) {
2430 //to handle stateprovince and country
2431 if ($fieldName == 'state_province') {
2432 $defaults[$fldName] = $value['state_province_id'];
2434 elseif ($fieldName == 'county') {
2435 $defaults[$fldName] = $value['county_id'];
2437 elseif ($fieldName == 'country') {
2438 if (!isset($value['country_id']) ||
!$value['country_id']) {
2439 $config = CRM_Core_Config
::singleton();
2440 if ($config->defaultContactCountry
) {
2441 $defaults[$fldName] = $config->defaultContactCountry
;
2445 $defaults[$fldName] = $value['country_id'];
2448 elseif ($fieldName == 'phone') {
2450 if (isset($value['phone'][$phoneTypeId])) {
2451 $defaults[$fldName] = $value['phone'][$phoneTypeId];
2453 if (isset($value['phone_ext'][$phoneTypeId])) {
2454 $defaults[str_replace('phone', 'phone_ext', $fldName)] = $value['phone_ext'][$phoneTypeId];
2458 $phoneDefault = CRM_Utils_Array
::value('phone', $value);
2460 if (!is_array($phoneDefault)) {
2461 $defaults[$fldName] = $phoneDefault;
2465 elseif ($fieldName == 'email') {
2466 //adding the first email (currently we don't support multiple emails of same location type)
2467 $defaults[$fldName] = $value['email'];
2469 elseif ($fieldName == 'im') {
2470 //adding the first im (currently we don't support multiple ims of same location type)
2471 $defaults[$fldName] = $value['im'];
2472 $defaults[$fldName . '-provider_id'] = $value['im_provider_id'];
2475 $defaults[$fldName] = $value[$fieldName];
2478 elseif (substr($fieldName, 0, 14) === 'address_custom' &&
2479 CRM_Utils_Array
::value(substr($fieldName, 8), $value)
2481 $defaults[$fldName] = $value[substr($fieldName, 8)];
2489 if (is_array($details)) {
2490 if ($fieldName === 'url'
2491 && !empty($details['website'])
2492 && !empty($details['website'][$locTypeId])
2494 $defaults[$fldName] = CRM_Utils_Array
::value('url', $details['website'][$locTypeId]);
2502 // Handling Contribution Part of the batch profile
2503 if (CRM_Core_Permission
::access('CiviContribute') && $component == 'Contribute') {
2504 self
::setComponentDefaults($fields, $componentId, $component, $defaults);
2507 // Handling Event Participation Part of the batch profile
2508 if (CRM_Core_Permission
::access('CiviEvent') && $component == 'Event') {
2509 self
::setComponentDefaults($fields, $componentId, $component, $defaults);
2512 // Handling membership Part of the batch profile
2513 if (CRM_Core_Permission
::access('CiviMember') && $component == 'Membership') {
2514 self
::setComponentDefaults($fields, $componentId, $component, $defaults);
2517 // Handling Activity Part of the batch profile
2518 if ($component == 'Activity') {
2519 self
::setComponentDefaults($fields, $componentId, $component, $defaults);
2522 // Handling Case Part of the batch profile
2523 if (CRM_Core_Permission
::access('CiviCase') && $component == 'Case') {
2524 self
::setComponentDefaults($fields, $componentId, $component, $defaults);
2529 * Get profiles by type eg: pure Individual etc
2531 * @param array $types
2532 * Associative array of types eg: types('Individual').
2533 * @param bool $onlyPure
2534 * True if only pure profiles are required.
2537 * associative array of profiles
2539 public static function getProfiles($types, $onlyPure = FALSE) {
2541 $ufGroups = CRM_Core_PseudoConstant
::get('CRM_Core_DAO_UFField', 'uf_group_id');
2543 CRM_Utils_Hook
::aclGroup(CRM_Core_Permission
::ADMIN
, NULL, 'civicrm_uf_group', $ufGroups, $ufGroups);
2545 // Exclude Batch Data Entry profiles - CRM-10901
2546 $batchProfiles = CRM_Core_BAO_UFGroup
::getBatchProfiles();
2548 foreach ($ufGroups as $id => $title) {
2549 $ptype = CRM_Core_BAO_UFField
::getProfileType($id, FALSE, $onlyPure);
2550 if (in_array($ptype, $types) && !array_key_exists($id, $batchProfiles)) {
2551 $profiles[$id] = $title;
2558 * Check whether a profile is valid combination of
2559 * required and/or optional profile types
2561 * @param array $required
2562 * Array of types those are required.
2563 * @param array $optional
2564 * Array of types those are optional.
2567 * associative array of profiles
2569 public static function getValidProfiles($required, $optional = NULL) {
2570 if (!is_array($required) ||
empty($required)) {
2575 $ufGroups = CRM_Core_PseudoConstant
::get('CRM_Core_DAO_UFField', 'uf_group_id');
2577 CRM_Utils_Hook
::aclGroup(CRM_Core_Permission
::ADMIN
, NULL, 'civicrm_uf_group', $ufGroups, $ufGroups);
2579 foreach ($ufGroups as $id => $title) {
2580 $type = CRM_Core_BAO_UFField
::checkValidProfileType($id, $required, $optional);
2582 $profiles[$id] = $title;
2590 * Check whether a profile is valid combination of
2591 * required profile fields
2593 * @param array $ufId
2594 * Integer id of the profile.
2595 * @param array $required
2596 * Array of fields those are required in the profile.
2599 * associative array of profiles
2601 public static function checkValidProfile($ufId, $required = NULL) {
2602 $validProfile = FALSE;
2604 return $validProfile;
2607 if (!CRM_Core_DAO
::getFieldValue('CRM_Core_DAO_UFGroup', $ufId, 'is_active')) {
2608 return $validProfile;
2611 $profileFields = self
::getFields($ufId, FALSE, CRM_Core_Action
::VIEW
, NULL,
2612 NULL, FALSE, NULL, FALSE, NULL,
2613 CRM_Core_Permission
::CREATE
, NULL
2617 if (!empty($profileFields)) {
2618 $fields = array_keys($profileFields);
2619 foreach ($fields as $val) {
2620 foreach ($required as $key => $field) {
2621 if (strpos($val, $field) === 0) {
2622 unset($required[$key]);
2627 $validProfile = (empty($required)) ?
TRUE : FALSE;
2630 return $validProfile;
2634 * Get default value for Register.
2636 * @param array $fields
2637 * @param array $defaults
2641 public static function setRegisterDefaults(&$fields, &$defaults) {
2642 $config = CRM_Core_Config
::singleton();
2643 foreach ($fields as $name => $field) {
2644 if (substr($name, 0, 8) == 'country-') {
2645 if (!empty($config->defaultContactCountry
)) {
2646 $defaults[$name] = $config->defaultContactCountry
;
2649 elseif (substr($name, 0, 15) == 'state_province-') {
2650 if (!empty($config->defaultContactStateProvince
)) {
2651 $defaults[$name] = $config->defaultContactStateProvince
;
2659 * make a copy of a profile, including
2660 * all the fields in the profile
2663 * The profile id to copy.
2665 * @return \CRM_Core_DAO
2667 public static function copy($id) {
2668 $maxId = CRM_Core_DAO
::singleValueQuery("SELECT max(id) FROM civicrm_uf_group");
2670 $title = ts('[Copy id %1]', [1 => $maxId +
1]);
2673 'title' => ' ' . $title,
2674 'name' => '__Copy_id_' . ($maxId +
1) . '_',
2678 $copy = CRM_Core_DAO
::copyGeneric('CRM_Core_DAO_UFGroup',
2684 if ($pos = strrpos($copy->name
, "_{$id}")) {
2685 $copy->name
= substr_replace($copy->name
, '', $pos);
2687 $copy->name
= CRM_Utils_String
::munge($copy->name
, '_', 56) . "_{$copy->id}";
2690 $copyUFJoin = CRM_Core_DAO
::copyGeneric('CRM_Core_DAO_UFJoin',
2691 ['uf_group_id' => $id],
2692 ['uf_group_id' => $copy->id
],
2697 $copyUFField = CRM_Core_DAO
::copyGeneric('CRM_Core_BAO_UFField',
2698 ['uf_group_id' => $id],
2699 ['uf_group_id' => $copy->id
]
2702 $maxWeight = CRM_Utils_Weight
::getMax('CRM_Core_DAO_UFJoin', NULL, 'weight');
2706 UPDATE civicrm_uf_join
2708 WHERE uf_group_id = %2
2709 AND ( entity_id IS NULL OR entity_id <= 0 )
2712 1 => [$maxWeight +
1, 'Integer'],
2713 2 => [$copy->id
, 'Integer'],
2715 CRM_Core_DAO
::executeQuery($query, $p);
2716 if ($copy->is_reserved
) {
2717 $query = "UPDATE civicrm_uf_group SET is_reserved = 0 WHERE id = %1";
2718 $params = [1 => [$copy->id
, 'Integer']];
2719 CRM_Core_DAO
::executeQuery($query, $params);
2721 CRM_Utils_Hook
::copy('UFGroup', $copy);
2727 * Process that send notification e-mails
2729 * @param int $contactID
2731 * @param array $values
2732 * Associative array of name/value pair.
2734 public static function commonSendMail($contactID, &$values) {
2735 if (!$contactID ||
!$values) {
2739 $template = CRM_Core_Smarty
::singleton();
2741 $displayName = CRM_Core_DAO
::getFieldValue('CRM_Contact_DAO_Contact',
2746 self
::profileDisplay($values['id'], $values['values'], $template);
2747 $emailList = explode(',', $values['email']);
2749 $contactLink = CRM_Utils_System
::url('civicrm/contact/view',
2750 "reset=1&cid=$contactID",
2751 TRUE, NULL, FALSE, FALSE, TRUE
2754 //get the default domain email address.
2755 list($domainEmailName, $domainEmailAddress) = CRM_Core_BAO_Domain
::getNameAndEmail();
2757 if (!$domainEmailAddress ||
$domainEmailAddress == 'info@EXAMPLE.ORG') {
2758 $fixUrl = CRM_Utils_System
::url('civicrm/admin/domain', 'action=update&reset=1');
2759 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]));
2762 foreach ($emailList as $emailTo) {
2763 // FIXME: take the below out of the foreach loop
2764 CRM_Core_BAO_MessageTemplate
::sendTemplate(
2766 'groupName' => 'msg_tpl_workflow_uf',
2767 'valueName' => 'uf_notify',
2768 'contactId' => $contactID,
2770 'displayName' => $displayName,
2771 'currentDate' => date('r'),
2772 'contactLink' => $contactLink,
2774 'from' => "$domainEmailName <$domainEmailAddress>",
2775 'toEmail' => $emailTo,
2782 * Given a contact id and a group id, returns the field values from the db
2783 * for this group and notify email only if group's notify field is
2784 * set and field values are not empty
2790 * @param array $params
2791 * @param bool $skipCheck
2795 public function checkFieldsEmptyValues($gid, $cid, $params, $skipCheck = FALSE) {
2797 if (CRM_Core_BAO_UFGroup
::filterUFGroups($gid, $cid) ||
$skipCheck) {
2799 $fields = CRM_Core_BAO_UFGroup
::getFields($gid, FALSE, CRM_Core_Action
::VIEW
);
2800 CRM_Core_BAO_UFGroup
::getValues($cid, $fields, $values, FALSE, $params, TRUE);
2802 $email = CRM_Core_DAO
::getFieldValue('CRM_Core_DAO_UFGroup', $gid, 'notify');
2804 if (!empty($values) &&
2809 'values' => $values,
2820 * Assign uf fields to template.
2824 * @param array $values
2825 * @param CRM_Core_Smarty $template
2827 public static function profileDisplay($gid, $values, $template) {
2828 $groupTitle = CRM_Core_DAO
::getFieldValue('CRM_Core_DAO_UFGroup', $gid, 'title');
2829 $template->assign('grouptitle', $groupTitle);
2830 if (count($values)) {
2831 $template->assign('values', $values);
2836 * Format fields for dupe Contact Matching.
2838 * @param array $params
2840 * @param int $contactId
2843 * associated formatted array
2845 public static function formatFields($params, $contactId = NULL) {
2847 // get the primary location type id and email
2848 list($name, $primaryEmail, $primaryLocationType) = CRM_Contact_BAO_Contact_Location
::getEmailDetails($contactId);
2851 $defaultLocationType = CRM_Core_BAO_LocationType
::getDefault();
2852 $primaryLocationType = $defaultLocationType->id
;
2858 $primaryLocation = 0;
2859 foreach ($params as $key => $value) {
2860 list($fieldName, $locTypeId, $phoneTypeId) = explode('-', $key);
2862 if ($locTypeId == 'Primary') {
2863 $locTypeId = $primaryLocationType;
2866 if (is_numeric($locTypeId)) {
2867 if (!in_array($locTypeId, $locationType)) {
2868 $locationType[$count] = $locTypeId;
2871 $loc = CRM_Utils_Array
::key($locTypeId, $locationType);
2873 $data['location'][$loc]['location_type_id'] = $locTypeId;
2875 // if we are getting in a new primary email, dont overwrite the new one
2876 if ($locTypeId == $primaryLocationType) {
2877 if (!empty($params['email-' . $primaryLocationType])) {
2878 $data['location'][$loc]['email'][$loc]['email'] = $fields['email-' . $primaryLocationType];
2880 elseif (isset($primaryEmail)) {
2881 $data['location'][$loc]['email'][$loc]['email'] = $primaryEmail;
2887 $data['location'][$loc]['is_primary'] = 1;
2889 if ($fieldName == 'phone') {
2891 $data['location'][$loc]['phone'][$loc]['phone_type_id'] = $phoneTypeId;
2894 $data['location'][$loc]['phone'][$loc]['phone_type_id'] = '';
2896 $data['location'][$loc]['phone'][$loc]['phone'] = $value;
2898 elseif ($fieldName == 'email') {
2899 $data['location'][$loc]['email'][$loc]['email'] = $value;
2901 elseif ($fieldName == 'im') {
2902 $data['location'][$loc]['im'][$loc]['name'] = $value;
2905 if ($fieldName === 'state_province') {
2906 $data['location'][$loc]['address']['state_province_id'] = $value;
2908 elseif ($fieldName === 'country') {
2909 $data['location'][$loc]['address']['country_id'] = $value;
2912 $data['location'][$loc]['address'][$fieldName] = $value;
2917 // TODO: prefix, suffix and gender translation may no longer be necessary - check inputs
2918 if ($key === 'individual_suffix') {
2919 $data['suffix_id'] = $value;
2921 elseif ($key === 'individual_prefix') {
2922 $data['prefix_id'] = $value;
2924 elseif ($key === 'gender') {
2925 $data['gender_id'] = $value;
2927 elseif (substr($key, 0, 6) === 'custom') {
2928 if ($customFieldID = CRM_Core_BAO_CustomField
::getKeyID($key)) {
2930 if ($customFields[$customFieldID]['html_type'] == 'CheckBox') {
2931 $value = implode(CRM_Core_DAO
::VALUE_SEPARATOR
, array_keys($value));
2933 // fix the date field
2934 if ($customFields[$customFieldID]['data_type'] == 'Date') {
2935 $date = CRM_Utils_Date
::format($value);
2942 $data['custom'][$customFieldID] = [
2945 'extends' => $customFields[$customFieldID]['extends'],
2946 'type' => $customFields[$customFieldID]['data_type'],
2947 'custom_field_id' => $customFieldID,
2951 elseif ($key == 'edit') {
2955 $data[$key] = $value;
2960 if (!$primaryLocation) {
2962 $data['location'][$loc]['email'][$loc]['email'] = $primaryEmail;
2969 * Calculate the profile type 'group_type' as per profile fields.
2973 * @param bool $includeTypeValues
2974 * @param int $ignoreFieldId
2975 * Ignore particular profile field.
2978 * list of calculated group type
2980 public static function calculateGroupType($gId, $includeTypeValues = FALSE, $ignoreFieldId = NULL) {
2981 //get the profile fields.
2982 $ufFields = self
::getFields($gId, FALSE, NULL, NULL, NULL, TRUE, NULL, TRUE);
2983 return self
::_calculateGroupType($ufFields, $includeTypeValues, $ignoreFieldId);
2987 * Calculate the profile type 'group_type' as per profile fields.
2990 * @param bool $includeTypeValues
2991 * @param int $ignoreFieldId
2992 * Ignore perticular profile field.
2995 * list of calculated group type
2997 public static function _calculateGroupType($ufFields, $includeTypeValues = FALSE, $ignoreFieldId = NULL) {
2998 $groupType = $groupTypeValues = $customFieldIds = [];
2999 if (!empty($ufFields)) {
3000 foreach ($ufFields as $fieldName => $fieldValue) {
3001 //ignore field from group type when provided.
3002 //in case of update profile field.
3003 if ($ignoreFieldId && ($ignoreFieldId == $fieldValue['field_id'])) {
3006 if (!in_array($fieldValue['field_type'], $groupType)) {
3007 $groupType[$fieldValue['field_type']] = $fieldValue['field_type'];
3010 if ($includeTypeValues && ($fldId = CRM_Core_BAO_CustomField
::getKeyID($fieldName))) {
3011 $customFieldIds[$fldId] = $fldId;
3016 if (!empty($customFieldIds)) {
3017 $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) . ')';
3019 $customGroups = CRM_Core_DAO
::executeQuery($query);
3020 while ($customGroups->fetch()) {
3021 if (!$customGroups->extends_entity_column_value
) {
3025 $groupTypeName = "{$customGroups->extends}Type";
3026 if ($customGroups->extends == 'Participant' && $customGroups->extends_entity_column_id
) {
3027 $groupTypeName = CRM_Core_PseudoConstant
::getName('CRM_Core_DAO_CustomGroup', 'extends_entity_column_id', $customGroups->extends_entity_column_id
);
3030 foreach (explode(CRM_Core_DAO
::VALUE_SEPARATOR
, $customGroups->extends_entity_column_value
) as $val) {
3032 $groupTypeValues[$groupTypeName][$val] = $val;
3037 if (!empty($groupTypeValues)) {
3038 $groupType = array_merge($groupType, $groupTypeValues);
3046 * Update the profile type 'group_type' as per profile fields including group types and group subtype values.
3047 * Build and store string like: group_type1,group_type2[VALUE_SEPERATOR]group_type1Type:1:2:3,group_type2Type:1:2
3050 * BirthDate + Email Individual,Contact
3051 * BirthDate + Subject Individual,Activity
3052 * BirthDate + Subject + SurveyOnlyField Individual,Activity\0ActivityType:28
3053 * BirthDate + Subject + SurveyOnlyField + PhoneOnlyField (Not allowed)
3054 * BirthDate + SurveyOnlyField Individual,Activity\0ActivityType:28
3055 * BirthDate + Subject + SurveyOrPhoneField Individual,Activity\0ActivityType:2:28
3056 * BirthDate + SurveyOrPhoneField Individual,Activity\0ActivityType:2:28
3057 * BirthDate + SurveyOrPhoneField + SurveyOnlyField Individual,Activity\0ActivityType:2:28
3058 * BirthDate + StudentField + Subject + SurveyOnlyField Individual,Activity,Student\0ActivityType:28
3061 * @param array $groupTypes
3062 * With key having group type names.
3066 public static function updateGroupTypes($gId, $groupTypes = []) {
3067 if (!is_array($groupTypes) ||
!$gId) {
3071 // If empty group types set group_type as 'null'
3072 if (empty($groupTypes)) {
3073 return CRM_Core_DAO
::setFieldValue('CRM_Core_DAO_UFGroup', $gId, 'group_type', 'null');
3076 $componentGroupTypes = ['Contribution', 'Participant', 'Membership', 'Activity', 'Case'];
3077 $validGroupTypes = array_merge([
3082 ], $componentGroupTypes, CRM_Contact_BAO_ContactType
::subTypes());
3084 $gTypes = $gTypeValues = [];
3086 $participantExtends = ['ParticipantRole', 'ParticipantEventName', 'ParticipantEventType'];
3087 // Get valid group type and group subtypes
3088 foreach ($groupTypes as $groupType => $value) {
3089 if (in_array($groupType, $validGroupTypes) && !in_array($groupType, $gTypes)) {
3090 $gTypes[] = $groupType;
3095 if (in_array($groupType, $participantExtends)) {
3096 $subTypesOf = $groupType;
3098 elseif (strpos($groupType, 'Type') > 0) {
3099 $subTypesOf = substr($groupType, 0, strpos($groupType, 'Type'));
3105 if (!empty($value) &&
3106 (in_array($subTypesOf, $componentGroupTypes) ||
3107 in_array($subTypesOf, $participantExtends)
3110 $gTypeValues[$subTypesOf] = $groupType . ":" . implode(':', $value);
3114 if (empty($gTypes)) {
3118 // Build String to store group types and group subtypes
3119 $groupTypeString = implode(',', $gTypes);
3120 if (!empty($gTypeValues)) {
3121 $groupTypeString .= CRM_Core_DAO
::VALUE_SEPARATOR
. implode(',', $gTypeValues);
3124 return CRM_Core_DAO
::setFieldValue('CRM_Core_DAO_UFGroup', $gId, 'group_type', $groupTypeString);
3128 * Create a "group_type" string.
3130 * @param array $coreTypes
3131 * E.g. array('Individual','Contact','Student').
3132 * @param array $subTypes
3133 * E.g. array('ActivityType' => array(7, 11)).
3134 * @param string $delim
3137 * @throws CRM_Core_Exception
3139 public static function encodeGroupType($coreTypes, $subTypes, $delim = CRM_Core_DAO
::VALUE_SEPARATOR
) {
3140 $groupTypeExpr = '';
3142 $groupTypeExpr .= implode(',', $coreTypes);
3145 //CRM-15427 Allow Multiple subtype filtering
3146 //if (count($subTypes) > 1) {
3147 //throw new CRM_Core_Exception("Multiple subtype filtering is not currently supported by widget.");
3149 foreach ($subTypes as $subType => $subTypeIds) {
3150 $groupTypeExpr .= $delim . $subType . ':' . implode(':', $subTypeIds);
3153 return $groupTypeExpr;
3157 * setDefault componet specific profile fields.
3159 * @param array $fields
3161 * @param int $componentId
3163 * @param string $component
3165 * @param array $defaults
3166 * An array of default values.
3168 * @param bool $isStandalone
3170 public static function setComponentDefaults(&$fields, $componentId, $component, &$defaults, $isStandalone = FALSE) {
3171 if (!$componentId ||
3172 !in_array($component, ['Contribute', 'Membership', 'Event', 'Activity', 'Case'])
3177 $componentBAO = $componentSubType = NULL;
3178 switch ($component) {
3180 $componentBAO = 'CRM_Member_BAO_Membership';
3181 $componentBAOName = 'Membership';
3182 $componentSubType = ['membership_type_id'];
3186 $componentBAO = 'CRM_Contribute_BAO_Contribution';
3187 $componentBAOName = 'Contribution';
3188 $componentSubType = ['financial_type_id'];
3192 $componentBAO = 'CRM_Event_BAO_Participant';
3193 $componentBAOName = 'Participant';
3194 $componentSubType = ['role_id', 'event_id', 'event_type_id'];
3198 $componentBAO = 'CRM_Activity_BAO_Activity';
3199 $componentBAOName = 'Activity';
3200 $componentSubType = ['activity_type_id'];
3204 $componentBAO = 'CRM_Case_BAO_Case';
3205 $componentBAOName = 'Case';
3206 $componentSubType = ['case_type_id'];
3211 $params = ['id' => $componentId];
3213 //get the component values.
3214 CRM_Core_DAO
::commonRetrieve($componentBAO, $params, $values);
3215 if ($componentBAOName == 'Participant') {
3216 $values +
= ['event_type_id' => CRM_Core_DAO
::getFieldValue('CRM_Event_DAO_Event', $values['event_id'], 'event_type_id')];
3219 $formattedGroupTree = [];
3221 foreach ($fields as $name => $field) {
3222 $fldName = $isStandalone ?
$name : "field[$componentId][$name]";
3223 if (array_key_exists($name, $values)) {
3224 $defaults[$fldName] = $values[$name];
3226 elseif ($name == 'participant_note') {
3227 $noteDetails = CRM_Core_BAO_Note
::getNote($componentId, 'civicrm_participant');
3228 $defaults[$fldName] = array_pop($noteDetails);
3230 elseif (in_array($name, [
3232 'payment_instrument',
3233 'participant_status',
3236 $defaults[$fldName] = $values["{$name}_id"];
3238 elseif ($name == 'membership_type') {
3239 // since membership_type field is a hierselect -
3240 $defaults[$fldName][0]
3241 = CRM_Core_DAO
::getFieldValue('CRM_Member_DAO_MembershipType', $values['membership_type_id'], 'member_of_contact_id', 'id');
3242 $defaults[$fldName][1] = $values['membership_type_id'];
3244 elseif ($name == 'membership_status') {
3245 $defaults[$fldName] = $values['status_id'];
3247 elseif ($name == 'case_status') {
3248 $defaults[$fldName] = $values['case_status_id'];
3250 elseif (CRM_Core_BAO_CustomField
::getKeyID($name, TRUE) !== [NULL, NULL]) {
3251 if (empty($formattedGroupTree)) {
3252 //get the groupTree as per subTypes.
3254 foreach ($componentSubType as $subType) {
3255 $subTree = CRM_Core_BAO_CustomGroup
::getTree($componentBAOName, NULL,
3256 $componentId, 0, $values[$subType]
3258 $groupTree = CRM_Utils_Array
::crmArrayMerge($groupTree, $subTree);
3260 $formattedGroupTree = CRM_Core_BAO_CustomGroup
::formatGroupTree($groupTree, 1);
3261 CRM_Core_BAO_CustomGroup
::setDefaults($formattedGroupTree, $defaults);
3264 //FIX ME: We need to loop defaults, but once we move to custom_1_x convention this code can be simplified.
3265 foreach ($defaults as $customKey => $customValue) {
3266 if ($customFieldDetails = CRM_Core_BAO_CustomField
::getKeyID($customKey, TRUE)) {
3267 if ($name == 'custom_' . $customFieldDetails[0]) {
3269 //hack to set default for checkbox
3270 //basically this is for weired field name like field[33][custom_19]
3271 //we are converting this field name to array structure and assign value.
3274 foreach ($formattedGroupTree as $tree) {
3275 if (!empty($tree['fields'][$customFieldDetails[0]])) {
3276 if ('CheckBox' == CRM_Utils_Array
::value('html_type', $tree['fields'][$customFieldDetails[0]])) {
3278 $defaults['field'][$componentId][$name] = $customValue;
3281 elseif (CRM_Utils_Array
::value('data_type', $tree['fields'][$customFieldDetails[0]]) == 'Date') {
3284 // CRM-6681, $default contains formatted date, time values.
3285 $defaults[$fldName] = $customValue;
3286 if (!empty($defaults[$customKey . '_time'])) {
3287 $defaults['field'][$componentId][$name . '_time'] = $defaults[$customKey . '_time'];
3293 if (!$skipValue ||
$isStandalone) {
3294 $defaults[$fldName] = $customValue;
3296 unset($defaults[$customKey]);
3302 elseif (isset($values[$fldName])) {
3303 $defaults[$fldName] = $values[$fldName];
3309 * Retrieve groups of profiles.
3311 * @param int $profileID
3312 * Id of the profile.
3317 public static function profileGroups($profileID) {
3319 $profileTypes = CRM_Core_DAO
::getFieldValue('CRM_Core_DAO_UFGroup', $profileID, 'group_type');
3320 if ($profileTypes) {
3321 $groupTypeParts = explode(CRM_Core_DAO
::VALUE_SEPARATOR
, $profileTypes);
3322 $groupTypes = explode(',', $groupTypeParts[0]);
3328 * Alter contact params by filtering existing subscribed groups and returns
3329 * unsubscribed groups array for subscription.
3331 * @param array $params
3333 * @param int $contactId
3337 * This contains array of groups for subscription
3339 public static function getDoubleOptInGroupIds(&$params, $contactId = NULL) {
3340 $config = CRM_Core_Config
::singleton();
3341 $subscribeGroupIds = [];
3343 // process further only if profileDoubleOptIn enabled and if groups exist
3344 if (!array_key_exists('group', $params) ||
3345 !self
::isProfileDoubleOptin() ||
3346 CRM_Utils_System
::isNull($params['group'])
3348 return $subscribeGroupIds;
3351 //check if contact email exist.
3353 foreach ($params as $name => $value) {
3354 if (strpos($name, 'email-') !== FALSE) {
3360 //Proceed furthur only if email present
3362 return $subscribeGroupIds;
3365 //do check for already subscriptions.
3366 $contactGroups = [];
3370 FROM civicrm_group_contact
3371 WHERE status = 'Added'
3372 AND contact_id = %1";
3374 $dao = CRM_Core_DAO
::executeQuery($query, [1 => [$contactId, 'Integer']]);
3375 while ($dao->fetch()) {
3376 $contactGroups[$dao->group_id
] = $dao->group_id
;
3380 //since we don't have names, compare w/ label.
3381 $mailingListGroupType = array_search('Mailing List', CRM_Core_OptionGroup
::values('group_type'));
3383 //actual processing start.
3384 foreach ($params['group'] as $groupId => $isSelected) {
3385 //unset group those are not selected.
3387 unset($params['group'][$groupId]);
3391 $groupTypes = explode(CRM_Core_DAO
::VALUE_SEPARATOR
,
3392 CRM_Core_DAO
::getFieldValue('CRM_Contact_DAO_Group', $groupId, 'group_type', 'id')
3394 //get only mailing type group and unset it from params
3395 if (in_array($mailingListGroupType, $groupTypes) && !in_array($groupId, $contactGroups)) {
3396 $subscribeGroupIds[$groupId] = $groupId;
3397 unset($params['group'][$groupId]);
3401 return $subscribeGroupIds;
3405 * Check if we are rendering mixed profiles.
3407 * @param array $profileIds
3408 * Associated array of profile ids.
3411 * true if profile is mixed
3413 public static function checkForMixProfiles($profileIds) {
3414 $mixProfile = FALSE;
3416 $contactTypes = ['Individual', 'Household', 'Organization'];
3417 $subTypes = CRM_Contact_BAO_ContactType
::subTypes();
3419 $components = ['Contribution', 'Participant', 'Membership', 'Activity'];
3421 $typeCount = ['ctype' => [], 'subtype' => []];
3422 foreach ($profileIds as $gid) {
3423 $profileType = CRM_Core_BAO_UFField
::getProfileType($gid);
3424 // ignore profile of type Contact
3425 if ($profileType == 'Contact') {
3428 if (in_array($profileType, $contactTypes)) {
3429 if (!isset($typeCount['ctype'][$profileType])) {
3430 $typeCount['ctype'][$profileType] = 1;
3433 // check if we are rendering profile of different contact types
3434 if (count($typeCount['ctype']) == 2) {
3439 elseif (in_array($profileType, $components)) {
3444 if (!isset($typeCount['subtype'][$profileType])) {
3445 $typeCount['subtype'][$profileType] = 1;
3447 // check if we are rendering profile of different contact sub types
3448 if (count($typeCount['subtype']) == 2) {
3458 * Determine of we show overlay profile or not.
3461 * true if profile should be shown else false
3463 public static function showOverlayProfile() {
3464 $showOverlay = TRUE;
3466 // get the id of overlay profile
3467 $overlayProfileId = CRM_Core_DAO
::getFieldValue('CRM_Core_DAO_UFGroup', 'summary_overlay', 'id', 'name');
3468 $query = "SELECT count(id) FROM civicrm_uf_field WHERE uf_group_id = {$overlayProfileId} AND visibility IN ('Public Pages', 'Public Pages and Listings') ";
3470 $count = CRM_Core_DAO
::singleValueQuery($query);
3472 //check if there are no public fields and use is anonymous
3473 $session = CRM_Core_Session
::singleton();
3474 if (!$count && !$session->get('userID')) {
3475 $showOverlay = FALSE;
3478 return $showOverlay;
3482 * Get group type values of the profile.
3484 * @param int $profileId
3485 * @param string $groupType
3490 public static function groupTypeValues($profileId, $groupType = NULL) {
3491 $groupTypeValue = [];
3492 $groupTypes = CRM_Core_DAO
::getFieldValue('CRM_Core_DAO_UFGroup', $profileId, 'group_type');
3494 $groupTypeParts = explode(CRM_Core_DAO
::VALUE_SEPARATOR
, $groupTypes);
3495 if (empty($groupTypeParts[1])) {
3496 return $groupTypeValue;
3498 $participantExtends = ['ParticipantRole', 'ParticipantEventName', 'ParticipantEventType'];
3500 foreach (explode(',', $groupTypeParts[1]) as $groupTypeValues) {
3502 $valueParts = explode(':', $groupTypeValues);
3504 ($valueParts[0] != "{$groupType}Type" ||
3505 ($groupType == 'Participant' &&
3506 !in_array($valueParts[0], $participantExtends)
3512 foreach ($valueParts as $val) {
3513 if (CRM_Utils_Rule
::integer($val)) {
3514 $values[$val] = $val;
3517 if (!empty($values)) {
3518 $typeName = substr($valueParts[0], 0, -4);
3519 if (in_array($valueParts[0], $participantExtends)) {
3520 $typeName = $valueParts[0];
3522 $groupTypeValue[$typeName] = $values;
3526 return $groupTypeValue;
3530 * @return bool|object
3532 public static function isProfileDoubleOptin() {
3533 // check for double optin
3534 $config = CRM_Core_Config
::singleton();
3535 if (in_array('CiviMail', $config->enableComponents
)) {
3536 return Civi
::settings()->get('profile_double_optin');
3542 * @return bool|object
3544 public static function isProfileAddToGroupDoubleOptin() {
3545 // check for add to group double optin
3546 $config = CRM_Core_Config
::singleton();
3547 if (in_array('CiviMail', $config->enableComponents
)) {
3548 return Civi
::settings()->get('profile_add_to_group_double_optin');
3554 * Get profiles used for batch entry.
3557 * profileIds profile ids
3559 public static function getBatchProfiles() {
3561 FROM civicrm_uf_group
3562 WHERE name IN ('contribution_batch_entry', 'membership_batch_entry')";
3563 $dao = CRM_Core_DAO
::executeQuery($query);
3565 while ($dao->fetch()) {
3566 $profileIds[$dao->id
] = $dao->id
;
3573 * @param $destination
3574 * @param bool $returnMultiSummaryFields
3576 * @return array|null
3577 * @todo what do I do?
3579 public static function shiftMultiRecordFields(&$source, &$destination, $returnMultiSummaryFields = FALSE) {
3580 $multiSummaryFields = $returnMultiSummaryFields ?
[] : NULL;
3581 foreach ($source as $field => $properties) {
3582 if (!CRM_Core_BAO_CustomField
::getKeyID($field)) {
3585 if (CRM_Core_BAO_CustomField
::isMultiRecordField($field)) {
3586 $destination[$field] = $properties;
3587 if ($returnMultiSummaryFields) {
3588 if ($properties['is_multi_summary']) {
3589 $multiSummaryFields[$field] = $properties;
3592 unset($source[$field]);
3595 return $multiSummaryFields;
3599 * This is function is used to format pseudo fields.
3601 * @param array $fields
3602 * Associated array of profile fields.
3605 public static function reformatProfileFields(&$fields) {
3606 //reformat fields array
3607 foreach ($fields as $name => $field) {
3608 //reformat phone and extension field
3609 if (substr($field['name'], 0, 13) == 'phone_and_ext') {
3610 $fieldSuffix = str_replace('phone_and_ext-', '', $field['name']);
3612 // retain existing element properties and just update and replace key
3613 CRM_Utils_Array
::crmReplaceKey($fields, $name, "phone-{$fieldSuffix}");
3614 $fields["phone-{$fieldSuffix}"]['name'] = "phone-{$fieldSuffix}";
3615 $fields["phone-{$fieldSuffix}"]['where'] = 'civicrm_phone.phone';
3617 // add additional phone extension field
3618 $fields["phone_ext-{$fieldSuffix}"] = $field;
3619 $fields["phone_ext-{$fieldSuffix}"]['title'] = $field['title'] . ' - ' . ts('Ext.');
3620 $fields["phone_ext-{$fieldSuffix}"]['name'] = "phone_ext-{$fieldSuffix}";
3621 $fields["phone_ext-{$fieldSuffix}"]['where'] = 'civicrm_phone.phone_ext';
3622 $fields["phone_ext-{$fieldSuffix}"]['skipDisplay'] = 1;
3623 //ignore required for extension field
3624 $fields["phone_ext-{$fieldSuffix}"]['is_required'] = 0;