[REF] Refactor to use the standard CRM_Core_Form::addRadio function for a number...
[civicrm-core.git] / CRM / Core / BAO / UFGroup.php
CommitLineData
6a488035
TO
1<?php
2/*
3 +--------------------------------------------------------------------+
bc77d7c0 4 | Copyright CiviCRM LLC. All rights reserved. |
6a488035 5 | |
bc77d7c0
TO
6 | This work is published under the GNU AGPLv3 license with some |
7 | permitted exceptions and without any warranty. For full license |
8 | and copyright information, see https://civicrm.org/licensing |
6a488035 9 +--------------------------------------------------------------------+
d25dd0ee 10 */
6a488035
TO
11
12/**
13 *
14 * @package CRM
ca5cec67 15 * @copyright CiviCRM LLC https://civicrm.org/licensing
6a488035
TO
16 */
17
18/**
8eedd10a 19 * UF group BAO class.
6a488035
TO
20 */
21class CRM_Core_BAO_UFGroup extends CRM_Core_DAO_UFGroup {
a6a0cdb7 22
7da04cde 23 const PUBLIC_VISIBILITY = 1,
6a488035
TO
24 ADMIN_VISIBILITY = 2,
25 LISTINGS_VISIBILITY = 4;
26
27 /**
fe482240 28 * Cache the match clause used in this transaction.
6a488035
TO
29 *
30 * @var string
31 */
518fa0ee 32 public static $_matchFields = NULL;
6a488035
TO
33
34 /**
fe482240 35 * Fetch object based on array of properties.
6a488035 36 *
6a0b768e
TO
37 * @param array $params
38 * (reference) an assoc array of name/value pairs.
39 * @param array $defaults
40 * (reference) an assoc array to hold the flattened values.
6a488035 41 *
a6c01b45
CW
42 * @return object
43 * CRM_Core_DAO_UFGroup object
6a488035 44 */
00be9182 45 public static function retrieve(&$params, &$defaults) {
6a488035
TO
46 return CRM_Core_DAO::commonRetrieve('CRM_Core_DAO_UFGroup', $params, $defaults);
47 }
48
49 /**
50 * Retrieve the first non-generic contact type
51 *
6a0b768e
TO
52 * @param int $id
53 * Id of uf_group.
6a488035 54 *
a6c01b45
CW
55 * @return string
56 * contact type
6a488035 57 */
00be9182 58 public static function getContactType($id) {
6a488035
TO
59
60 $validTypes = array_filter(array_keys(CRM_Core_SelectValues::contactType()));
61 $validSubTypes = CRM_Contact_BAO_ContactType::subTypeInfo();
62
63 $typesParts = explode(CRM_Core_DAO::VALUE_SEPARATOR, CRM_Core_DAO::getFieldValue('CRM_Core_DAO_UFGroup', $id, 'group_type'));
64 $types = explode(',', $typesParts[0]);
65
66 $cType = NULL;
67 foreach ($types as $type) {
68 if (in_array($type, $validTypes)) {
69 $cType = $type;
70 }
71 elseif (array_key_exists($type, $validSubTypes)) {
9c1bc317 72 $cType = $validSubTypes[$type]['parent'] ?? NULL;
6a488035 73 }
2aa397bc 74 if ($cType) {
5d6ac993 75 break;
2aa397bc 76 }
6a488035
TO
77 }
78
79 return $cType;
80 }
81
82 /**
83 * Get the form title.
84 *
6a0b768e
TO
85 * @param int $id
86 * Id of uf_form.
6a488035 87 *
a6c01b45
CW
88 * @return string
89 * title
6a488035 90 *
6a488035
TO
91 */
92 public static function getTitle($id) {
93 return CRM_Core_DAO::getFieldValue('CRM_Core_DAO_UFGroup', $id, 'title');
94 }
95
96 /**
fe482240 97 * Update the is_active flag in the db.
6a488035 98 *
6a0b768e
TO
99 * @param int $id
100 * Id of the database record.
101 * @param bool $is_active
102 * Value we want to set the is_active field.
6a488035 103 *
8a4fede3 104 * @return bool
105 * true if we found and updated the object, else false
6a488035 106 */
00be9182 107 public static function setIsActive($id, $is_active) {
6a488035
TO
108 return CRM_Core_DAO::setFieldValue('CRM_Core_DAO_UFGroup', $id, 'is_active', $is_active);
109 }
110
111 /**
fe482240 112 * Get all the registration fields.
6a488035 113 *
6a0b768e
TO
114 * @param int $action
115 * What action are we doing.
116 * @param int $mode
117 * Mode.
da6b46f4 118 *
a6a0cdb7 119 * @param string $ctype
6a488035 120 *
a6c01b45
CW
121 * @return array
122 * the fields that are needed for registration
a6a0cdb7 123 *
124 * @throws \Exception
6a488035 125 */
00be9182 126 public static function getRegistrationFields($action, $mode, $ctype = NULL) {
6a488035
TO
127 if ($mode & CRM_Profile_Form::MODE_REGISTER) {
128 $ufGroups = CRM_Core_BAO_UFGroup::getModuleUFGroup('User Registration');
129 }
130 else {
131 $ufGroups = CRM_Core_BAO_UFGroup::getModuleUFGroup('Profile');
132 }
133
134 if (!is_array($ufGroups)) {
135 return FALSE;
136 }
137
a6a0cdb7 138 $fields = [];
6a488035
TO
139
140 foreach ($ufGroups as $id => $title) {
141 if ($ctype) {
142 $fieldType = CRM_Core_BAO_UFField::getProfileType($id);
143 if (($fieldType != 'Contact') &&
144 ($fieldType != $ctype) &&
145 !CRM_Contact_BAO_ContactType::isExtendsContactType($fieldType, $ctype)
146 ) {
147 continue;
148 }
149 if (CRM_Contact_BAO_ContactType::isaSubType($fieldType)) {
150 $profileSubType = $fieldType;
151 }
152 }
153
154 $subset = self::getFields($id, TRUE, $action,
155 NULL, NULL, FALSE, NULL, TRUE, $ctype
156 );
157
158 // we do not allow duplicates. the first field is the winner
159 foreach ($subset as $name => $field) {
a7488080 160 if (empty($fields[$name])) {
6a488035
TO
161 $fields[$name] = $field;
162 }
163 }
164 }
165
166 return $fields;
167 }
168
169 /**
fe482240 170 * Get all the listing fields.
6a488035 171 *
6a0b768e
TO
172 * @param int $action
173 * What action are we doing.
174 * @param int $visibility
175 * Visibility of fields we are interested in.
176 * @param bool $considerSelector
177 * Whether to consider the in_selector parameter.
da6b46f4 178 * @param array $ufGroupIds
6a0b768e 179 * @param bool $searchable
6a488035 180 *
da6b46f4
EM
181 * @param null $restrict
182 * @param bool $skipPermission
183 * @param int $permissionType
a6a0cdb7 184 *
a6c01b45
CW
185 * @return array
186 * the fields that are listings related
a6a0cdb7 187 *
188 * @throws \Exception
6a488035 189 */
e7483cbe 190 public static function getListingFields(
6a488035
TO
191 $action,
192 $visibility,
193 $considerSelector = FALSE,
5d6ac993
TO
194 $ufGroupIds = NULL,
195 $searchable = NULL,
196 $restrict = NULL,
197 $skipPermission = FALSE,
198 $permissionType = CRM_Core_Permission::SEARCH
6a488035
TO
199 ) {
200 if ($ufGroupIds) {
201 $subset = self::getFields($ufGroupIds, FALSE, $action,
202 $visibility, $searchable,
203 FALSE, $restrict,
204 $skipPermission,
205 NULL,
206 $permissionType
207 );
208 if ($considerSelector) {
209 // drop the fields not meant for the selector
210 foreach ($subset as $name => $field) {
211 if (!$field['in_selector']) {
212 unset($subset[$name]);
213 }
214 }
215 }
216 $fields = $subset;
217 }
218 else {
ff4f7744 219 $ufGroups = CRM_Core_PseudoConstant::get('CRM_Core_DAO_UFField', 'uf_group_id');
6a488035 220
a6a0cdb7 221 $fields = [];
6a488035
TO
222 foreach ($ufGroups as $id => $title) {
223 $subset = self::getFields($id, FALSE, $action,
224 $visibility, $searchable,
225 FALSE, $restrict,
226 $skipPermission,
227 NULL,
228 $permissionType
229 );
230 if ($considerSelector) {
231 // drop the fields not meant for the selector
232 foreach ($subset as $name => $field) {
4f99ca55
TO
233 if (!$field['in_selector']) {
234 unset($subset[$name]);
2aa397bc 235 }
6a488035
TO
236 }
237 }
238 $fields = array_merge($fields, $subset);
239 }
240 }
241 return $fields;
242 }
243
244 /**
245 * Get all the fields that belong to the group with the name title,
246 * and format for use with buildProfile. This is the SQL analog of
247 * formatUFFields().
248 *
6a0b768e
TO
249 * @param mix $id
250 * The id of the UF group or ids of ufgroup.
fd31fa4c 251 * @param bool|int $register are we interested in registration fields
6a0b768e
TO
252 * @param int $action
253 * What action are we doing.
254 * @param int $visibility
255 * Visibility of fields we are interested in.
256 * @param $searchable
fd31fa4c 257 * @param bool $showAll
6a0b768e
TO
258 * @param string $restrict
259 * Should we restrict based on a specified profile type.
fd31fa4c
EM
260 * @param bool $skipPermission
261 * @param null $ctype
262 * @param int $permissionType
263 * @param string $orderBy
264 * @param null $orderProfiles
265 *
54957108 266 * @param bool $eventProfile
267 *
a6c01b45 268 * @return array
54957108 269 * The fields that belong to this ufgroup(s)
301906ab 270 *
271 * @throws \CRM_Core_Exception
6a488035 272 */
e7483cbe 273 public static function getFields(
6a488035
TO
274 $id,
275 $register = FALSE,
276 $action = NULL,
5d6ac993 277 $visibility = NULL,
6a488035 278 $searchable = NULL,
5d6ac993 279 $showAll = FALSE,
6a488035
TO
280 $restrict = NULL,
281 $skipPermission = FALSE,
5d6ac993 282 $ctype = NULL,
6a488035 283 $permissionType = CRM_Core_Permission::CREATE,
5d6ac993 284 $orderBy = 'field_name',
44792363 285 $orderProfiles = NULL,
286 $eventProfile = FALSE
6a488035
TO
287 ) {
288 if (!is_array($id)) {
289 $id = CRM_Utils_Type::escape($id, 'Positive');
a6a0cdb7 290 $profileIds = [$id];
6a488035
TO
291 }
292 else {
293 $profileIds = $id;
294 }
295
296 $gids = implode(',', $profileIds);
a6a0cdb7 297 $params = [];
6a488035 298 if ($restrict) {
f9d8a5d1 299 $query = "SELECT g.* from civicrm_uf_group g
300 LEFT JOIN civicrm_uf_join j ON (j.uf_group_id = g.id)
6a488035 301 WHERE g.id IN ( {$gids} )
f9d8a5d1 302 AND ((j.uf_group_id IN ( {$gids} ) AND j.module = %1) OR g.is_reserved = 1 )
6a488035 303 ";
a6a0cdb7 304 $params = [1 => [$restrict, 'String']];
6a488035
TO
305 }
306 else {
307 $query = "SELECT g.* from civicrm_uf_group g WHERE g.id IN ( {$gids} ) ";
308 }
309
310 if (!$showAll) {
311 $query .= " AND g.is_active = 1";
312 }
313
a6a0cdb7 314 $checkPermission = [
315 [
44792363 316 'administer CiviCRM',
317 'manage event profiles',
a6a0cdb7 318 ],
319 ];
44792363 320 if ($eventProfile && CRM_Core_Permission::check($checkPermission)) {
321 $skipPermission = TRUE;
322 }
323
6a488035
TO
324 // add permissioning for profiles only if not registration
325 if (!$skipPermission) {
326 $permissionClause = CRM_Core_Permission::ufGroupClause($permissionType, 'g.');
327 $query .= " AND $permissionClause ";
328 }
329
518fa0ee 330 if ($orderProfiles and count($profileIds) > 1) {
6a488035
TO
331 $query .= " ORDER BY FIELD( g.id, {$gids} )";
332 }
5d6ac993 333 $group = CRM_Core_DAO::executeQuery($query, $params);
a6a0cdb7 334 $fields = [];
6a488035
TO
335 $validGroup = FALSE;
336
337 while ($group->fetch()) {
338 $validGroup = TRUE;
339 $query = self::createUFFieldQuery($group->id, $searchable, $showAll, $visibility, $orderBy);
340 $field = CRM_Core_DAO::executeQuery($query);
341
fc040dd2 342 $importableFields = self::getProfileFieldMetadata($showAll);
6a488035
TO
343 list($customFields, $addressCustomFields) = self::getCustomFields($ctype);
344
345 while ($field->fetch()) {
346 list($name, $formattedField) = self::formatUFField($group, $field, $customFields, $addressCustomFields, $importableFields, $permissionType);
347 if ($formattedField !== NULL) {
348 $fields[$name] = $formattedField;
349 }
350 }
6a488035
TO
351 }
352
353 if (empty($fields) && !$validGroup) {
301906ab 354 throw new CRM_Core_Exception(ts('The requested Profile (gid=%1) is disabled OR it is not configured to be used for \'Profile\' listings in its Settings OR there is no Profile with that ID OR you do not have permission to access this profile. Please contact the site administrator if you need assistance.',
a6a0cdb7 355 [1 => implode(',', $profileIds)]
5d6ac993 356 ));
6a488035
TO
357 }
358 else {
359 self::reformatProfileFields($fields);
360 }
361
362 return $fields;
363 }
364
365 /**
366 * Format a list of UFFields for use with buildProfile. This is the in-memory analog
367 * of getFields().
368 *
6a0b768e
TO
369 * @param array $groupArr
370 * (mimic CRM_UF_DAO_UFGroup).
371 * @param array $fieldArrs
372 * List of fields (each mimics CRM_UF_DAO_UFField).
373 * @param bool $visibility
374 * Visibility of fields we are interested in.
6a488035 375 * @param bool $searchable
77b97be7
EM
376 * @param bool $showAll
377 * @param null $ctype
378 * @param int $permissionType
379 *
6a488035 380 * @return array
c490a46a 381 * @see self::getFields
6a488035
TO
382 */
383 public static function formatUFFields(
384 $groupArr,
385 $fieldArrs,
386 $visibility = NULL,
387 $searchable = NULL,
388 $showAll = FALSE,
389 $ctype = NULL,
390 $permissionType = CRM_Core_Permission::CREATE
391 ) {
392 // $group = new CRM_Core_DAO_UFGroup();
393 // $group->copyValues($groupArr); // no... converts string('') to string('null')
394 $group = (object) $groupArr;
395
396 // Refactoring note: The $fieldArrs here may be slightly different than the $ufFields
397 // used by calculateGroupType, but I don't think the missing fields matter, and -- if
398 // they did -- the obvious fix would produce mutual recursion.
399 $ufGroupType = self::_calculateGroupType($fieldArrs);
5d6ac993
TO
400 $profileType = CRM_Core_BAO_UFField::calculateProfileType(implode(',', $ufGroupType));
401 $contactActivityProfile = CRM_Core_BAO_UFField::checkContactActivityProfileTypeByGroupType(implode(',', $ufGroupType));
6a488035
TO
402 $importableFields = self::getImportableFields($showAll, $profileType, $contactActivityProfile);
403 list($customFields, $addressCustomFields) = self::getCustomFields($ctype);
404
a6a0cdb7 405 $formattedFields = [];
6a488035 406 foreach ($fieldArrs as $fieldArr) {
6a488035
TO
407 $field = (object) $fieldArr;
408 if (!self::filterUFField($field, $searchable, $showAll, $visibility)) {
409 continue;
410 }
411
412 list($name, $formattedField) = self::formatUFField($group, $field, $customFields, $addressCustomFields, $importableFields, $permissionType);
413 if ($formattedField !== NULL) {
414 $formattedFields[$name] = $formattedField;
415 }
416 }
417 return $formattedFields;
418 }
419
420 /**
421 * Prepare a field for rendering with CRM_Core_BAO_UFGroup::buildProfile.
422 *
423 * @param CRM_Core_DAO_UFGroup|CRM_Core_DAO $group
424 * @param CRM_Core_DAO_UFField|CRM_Core_DAO $field
e7483cbe 425 * @param array $customFields
6a488035
TO
426 * @param array $addressCustomFields
427 * @param array $importableFields
6a0b768e
TO
428 * @param int $permissionType
429 * Eg CRM_Core_Permission::CREATE.
a6a0cdb7 430 *
6a488035
TO
431 * @return array
432 */
433 protected static function formatUFField(
434 $group,
435 $field,
436 $customFields,
437 $addressCustomFields,
438 $importableFields,
439 $permissionType = CRM_Core_Permission::CREATE
440 ) {
441 $name = $field->field_name;
442 $title = $field->label;
443
444 $addressCustom = FALSE;
a6a0cdb7 445 if (in_array($permissionType, [CRM_Core_Permission::CREATE, CRM_Core_Permission::EDIT]) &&
6a488035
TO
446 in_array($field->field_name, array_keys($addressCustomFields))
447 ) {
448 $addressCustom = TRUE;
449 $name = "address_{$name}";
450 }
887e764d
PN
451 if ($field->field_name == 'url') {
452 $name .= "-{$field->website_type_id}";
453 }
454 elseif (!empty($field->location_type_id)) {
6a488035
TO
455 $name .= "-{$field->location_type_id}";
456 }
457 else {
458 $locationFields = self::getLocationFields();
459 if (in_array($field->field_name, $locationFields) || $addressCustom) {
460 $name .= '-Primary';
461 }
462 }
463
464 if (isset($field->phone_type_id)) {
465 $name .= "-{$field->phone_type_id}";
466 }
2e1f50d6 467 $fieldMetaData = CRM_Utils_Array::value($name, $importableFields, ($importableFields[$field->field_name] ?? []));
6a488035
TO
468
469 // No lie: this is bizarre; why do we need to mix so many UFGroup properties into UFFields?
470 // I guess to make field self sufficient with all the required data and avoid additional calls
a6a0cdb7 471 $formattedField = [
6a488035
TO
472 'name' => $name,
473 'groupTitle' => $group->title,
5d6ac993 474 'groupName' => $group->name,
ce1a9db4 475 'groupDisplayTitle' => (!empty($group->frontend_title)) ? $group->frontend_title : $group->title,
6a488035
TO
476 'groupHelpPre' => empty($group->help_pre) ? '' : $group->help_pre,
477 'groupHelpPost' => empty($group->help_post) ? '' : $group->help_post,
478 'title' => $title,
479 'where' => CRM_Utils_Array::value('where', CRM_Utils_Array::value($field->field_name, $importableFields)),
480 'attributes' => CRM_Core_DAO::makeAttribute(CRM_Utils_Array::value($field->field_name, $importableFields)),
481 'is_required' => $field->is_required,
482 'is_view' => $field->is_view,
483 'help_pre' => $field->help_pre,
484 'help_post' => $field->help_post,
485 'visibility' => $field->visibility,
486 'in_selector' => $field->in_selector,
487 'rule' => CRM_Utils_Array::value('rule', CRM_Utils_Array::value($field->field_name, $importableFields)),
2e1f50d6
CW
488 'location_type_id' => $field->location_type_id ?? NULL,
489 'website_type_id' => $field->website_type_id ?? NULL,
490 'phone_type_id' => $field->phone_type_id ?? NULL,
6a488035 491 'group_id' => $group->id,
2e1f50d6
CW
492 'add_to_group_id' => $group->add_to_group_id ?? NULL,
493 'add_captcha' => $group->add_captcha ?? NULL,
6a488035
TO
494 'field_type' => $field->field_type,
495 'field_id' => $field->id,
0c145cc0
DL
496 'pseudoconstant' => CRM_Utils_Array::value(
497 'pseudoconstant',
498 CRM_Utils_Array::value($field->field_name, $importableFields)
499 ),
500 // obsolete this when we remove the name / dbName discrepancy with gender/suffix/prefix
501 'dbName' => CRM_Utils_Array::value(
502 'dbName',
503 CRM_Utils_Array::value($field->field_name, $importableFields)
504 ),
6a488035 505 'skipDisplay' => 0,
d86e674f 506 'data_type' => CRM_Utils_Type::getDataTypeFromFieldMetadata($fieldMetaData),
6b409353 507 'bao' => $fieldMetaData['bao'] ?? NULL,
a6a0cdb7 508 ];
6a488035 509
d86e674f 510 $formattedField = CRM_Utils_Date::addDateMetadataToField($fieldMetaData, $formattedField);
511
6a488035
TO
512 //adding custom field property
513 if (substr($field->field_name, 0, 6) == 'custom' ||
514 substr($field->field_name, 0, 14) === 'address_custom'
515 ) {
516 // if field is not present in customFields, that means the user
517 // DOES NOT HAVE permission to access that field
518 if (array_key_exists($field->field_name, $customFields)) {
e1d699d7 519 $formattedField['serialize'] = !empty($customFields[$field->field_name]['serialize']);
6a488035
TO
520 $formattedField['is_search_range'] = $customFields[$field->field_name]['is_search_range'];
521 // fix for CRM-1994
522 $formattedField['options_per_line'] = $customFields[$field->field_name]['options_per_line'];
6a488035
TO
523 $formattedField['html_type'] = $customFields[$field->field_name]['html_type'];
524
525 if (CRM_Utils_Array::value('html_type', $formattedField) == 'Select Date') {
526 $formattedField['date_format'] = $customFields[$field->field_name]['date_format'];
527 $formattedField['time_format'] = $customFields[$field->field_name]['time_format'];
d86e674f 528 $formattedField['is_datetime_field'] = TRUE;
2732685b 529 $formattedField['smarty_view_format'] = CRM_Utils_Date::getDateFieldViewFormat($formattedField['date_format']);
6a488035
TO
530 }
531
532 $formattedField['is_multi_summary'] = $field->is_multi_summary;
a6a0cdb7 533 return [$name, $formattedField];
6a488035
TO
534 }
535 else {
536 $formattedField = NULL;
a6a0cdb7 537 return [$name, $formattedField];
6a488035
TO
538 }
539 }
a6a0cdb7 540 return [$name, $formattedField];
6a488035
TO
541 }
542
543 /**
fe482240 544 * Create a query to find all visible UFFields in a UFGroup.
6a488035
TO
545 *
546 * This is the SQL-variant of checkUFFieldDisplayable().
547 *
548 * @param int $groupId
549 * @param bool $searchable
550 * @param bool $showAll
551 * @param int $visibility
6a0b768e
TO
552 * @param string $orderBy
553 * Comma-delimited list of SQL columns.
a6a0cdb7 554 *
6a488035
TO
555 * @return string
556 */
557 protected static function createUFFieldQuery($groupId, $searchable, $showAll, $visibility, $orderBy) {
558 $where = " WHERE uf_group_id = {$groupId}";
559
560 if ($searchable) {
561 $where .= " AND is_searchable = 1";
562 }
563
564 if (!$showAll) {
565 $where .= " AND is_active = 1";
566 }
567
568 if ($visibility) {
a6a0cdb7 569 $clause = [];
6a488035
TO
570 if ($visibility & self::PUBLIC_VISIBILITY) {
571 $clause[] = 'visibility = "Public Pages"';
572 }
573 if ($visibility & self::ADMIN_VISIBILITY) {
574 $clause[] = 'visibility = "User and User Admin Only"';
575 }
576 if ($visibility & self::LISTINGS_VISIBILITY) {
577 $clause[] = 'visibility = "Public Pages and Listings"';
578 }
579 if (!empty($clause)) {
580 $where .= ' AND ( ' . implode(' OR ', $clause) . ' ) ';
581 }
582 }
583
584 $query = "SELECT * FROM civicrm_uf_field $where ORDER BY weight";
585 if ($orderBy) {
586 $query .= ", " . $orderBy;
587 return $query;
588 }
589 return $query;
590 }
591
592 /**
fe482240 593 * Create a query to find all visible UFFields in a UFGroup.
6a488035
TO
594 *
595 * This is the PHP in-memory variant of createUFFieldQuery().
596 *
597 * @param CRM_Core_DAO_UFField|CRM_Core_DAO $field
598 * @param bool $searchable
599 * @param bool $showAll
600 * @param int $visibility
a6a0cdb7 601 *
a6c01b45
CW
602 * @return bool
603 * TRUE if field is displayable
6a488035
TO
604 */
605 protected static function filterUFField($field, $searchable, $showAll, $visibility) {
606 if ($searchable && $field->is_searchable != 1) {
607 return FALSE;
608 }
609
610 if (!$showAll && $field->is_active != 1) {
611 return FALSE;
612 }
613
614 if ($visibility) {
a6a0cdb7 615 $allowedVisibilities = [];
6a488035
TO
616 if ($visibility & self::PUBLIC_VISIBILITY) {
617 $allowedVisibilities[] = 'Public Pages';
618 }
619 if ($visibility & self::ADMIN_VISIBILITY) {
620 $allowedVisibilities[] = 'User and User Admin Only';
621 }
622 if ($visibility & self::LISTINGS_VISIBILITY) {
623 $allowedVisibilities[] = 'Public Pages and Listings';
624 }
625 // !empty($allowedVisibilities) seems silly to me, but it is equivalent to the pre-existing SQL
626 if (!empty($allowedVisibilities) && !in_array($field->visibility, $allowedVisibilities)) {
627 return FALSE;
628 }
629 }
630
631 return TRUE;
632 }
633
b5c2afd0 634 /**
fc040dd2 635 * Get a list of filtered field metadata.
636 *
b5c2afd0
EM
637 * @param $showAll
638 * @param $profileType
639 * @param $contactActivityProfile
fc040dd2 640 * @param bool $filterMode
641 * Filter mode means you are using importable fields for filtering rather than just getting metadata.
642 * With filter mode = FALSE BOTH activity fields and component fields are returned.
643 * I can't see why you would ever want to use this function in filter mode as the component fields are
644 * still unfiltered. However, I feel scared enough to leave it as it is. I have marked this function as
645 * deprecated and am recommending the wrapper 'getProfileFieldMetadata' in order to try to
646 * send this confusion to history.
b5c2afd0
EM
647 *
648 * @return array
a6a0cdb7 649 * @deprecated use getProfileFieldMetadata
650 *
b5c2afd0 651 */
fc040dd2 652 protected static function getImportableFields($showAll, $profileType, $contactActivityProfile, $filterMode = TRUE) {
6a488035
TO
653 if (!$showAll) {
654 $importableFields = CRM_Contact_BAO_Contact::importableFields('All', FALSE, FALSE, FALSE, TRUE, TRUE);
655 }
656 else {
657 $importableFields = CRM_Contact_BAO_Contact::importableFields('All', FALSE, TRUE, FALSE, TRUE, TRUE);
658 }
659
fc040dd2 660 $activityFields = CRM_Activity_BAO_Activity::getProfileFields();
661 $componentFields = CRM_Core_Component::getQueryFields();
662 if ($filterMode == TRUE) {
663 if ($profileType == 'Activity' || $contactActivityProfile) {
664 $importableFields = array_merge($importableFields, $activityFields);
665 }
666 else {
667 $importableFields = array_merge($importableFields, $componentFields);
668 }
6a488035
TO
669 }
670 else {
fc040dd2 671 $importableFields = array_merge($importableFields, $activityFields, $componentFields);
6a488035
TO
672 }
673
6a488035
TO
674 $importableFields['group']['title'] = ts('Group(s)');
675 $importableFields['group']['where'] = NULL;
676 $importableFields['tag']['title'] = ts('Tag(s)');
677 $importableFields['tag']['where'] = NULL;
678 return $importableFields;
679 }
680
fc040dd2 681 /**
682 * Get the metadata for all potential profile fields.
683 *
684 * @param bool $isIncludeInactive
685 * Should disabled fields be included.
686 *
687 * @return array
688 * Field metadata for all fields that might potentially be in a profile.
689 */
690 protected static function getProfileFieldMetadata($isIncludeInactive) {
691 return self::getImportableFields($isIncludeInactive, NULL, NULL, NULL, TRUE);
692 }
693
bc854509 694 /**
695 * Get the fields relating to locations.
696 *
697 * @return array
698 */
6a488035 699 public static function getLocationFields() {
a6a0cdb7 700 static $locationFields = [
6a488035
TO
701 'street_address',
702 'supplemental_address_1',
703 'supplemental_address_2',
207f62c6 704 'supplemental_address_3',
6a488035
TO
705 'city',
706 'postal_code',
707 'postal_code_suffix',
708 'geo_code_1',
709 'geo_code_2',
710 'state_province',
711 'country',
712 'county',
713 'phone',
714 'phone_and_ext',
715 'email',
716 'im',
717 'address_name',
718 'phone_ext',
a6a0cdb7 719 ];
6a488035
TO
720 return $locationFields;
721 }
722
b5c2afd0
EM
723 /**
724 * @param $ctype
725 *
726 * @return mixed
727 */
6a488035 728 protected static function getCustomFields($ctype) {
58159c3b 729 $cacheKey = 'uf_group_custom_fields_' . $ctype;
730 if (!Civi::cache('metadata')->has($cacheKey)) {
6a488035
TO
731 $customFields = CRM_Core_BAO_CustomField::getFieldsForImport($ctype, FALSE, FALSE, FALSE, TRUE, TRUE);
732
733 // hack to add custom data for components
a6a0cdb7 734 $components = ['Contribution', 'Participant', 'Membership', 'Activity', 'Case'];
6a488035
TO
735 foreach ($components as $value) {
736 $customFields = array_merge($customFields, CRM_Core_BAO_CustomField::getFieldsForImport($value));
737 }
738 $addressCustomFields = CRM_Core_BAO_CustomField::getFieldsForImport('Address');
739 $customFields = array_merge($customFields, $addressCustomFields);
58159c3b 740 Civi::cache('metadata')->set($cacheKey, [$customFields, $addressCustomFields]);
6a488035 741 }
58159c3b 742 return Civi::cache('metadata')->get($cacheKey);
6a488035
TO
743 }
744
745 /**
fe482240 746 * Check the data validity.
6a488035 747 *
6a0b768e
TO
748 * @param int $userID
749 * The user id that we are actually editing.
b247a732 750 * @param string $name
751 * The machine-name of the group we are interested in.
2a6da8d7 752 * @param bool $register
6a0b768e
TO
753 * @param int $action
754 * The action of the form.
6a488035 755 *
2a6da8d7 756 * @pram boolean $register is this the registrtion form
e7483cbe 757 * @return bool
a6c01b45 758 * true if form is valid
6a488035 759 */
b247a732 760 public static function isValid($userID, $name, $register = FALSE, $action = NULL) {
6a488035
TO
761 if ($register) {
762 $controller = new CRM_Core_Controller_Simple('CRM_Profile_Form_Dynamic',
763 ts('Dynamic Form Creator'),
764 $action
765 );
766 $controller->set('id', $userID);
767 $controller->set('register', 1);
768 $controller->process();
769 return $controller->validate();
770 }
771 else {
772 // make sure we have a valid group
773 $group = new CRM_Core_DAO_UFGroup();
774
b247a732 775 $group->name = $name;
6a488035
TO
776
777 if ($group->find(TRUE) && $userID) {
778 $controller = new CRM_Core_Controller_Simple('CRM_Profile_Form_Dynamic', ts('Dynamic Form Creator'), $action);
779 $controller->set('gid', $group->id);
780 $controller->set('id', $userID);
781 $controller->set('register', 0);
782 $controller->process();
783 return $controller->validate();
784 }
785 return TRUE;
786 }
787 }
788
789 /**
fe482240 790 * Get the html for the form that represents this particular group.
6a488035 791 *
6a0b768e
TO
792 * @param int $userID
793 * The user id that we are actually editing.
794 * @param string $title
795 * The title of the group we are interested in.
796 * @param int $action
797 * The action of the form.
798 * @param bool $register
799 * Is this the registration form.
800 * @param bool $reset
801 * Should we reset the form?.
802 * @param int $profileID
803 * Do we have the profile ID?.
2a6da8d7
EM
804 *
805 * @param bool $doNotProcess
806 * @param null $ctype
6a488035 807 *
a6c01b45
CW
808 * @return string
809 * the html for the form on success, otherwise empty string
6a488035 810 */
e7483cbe 811 public static function getEditHTML(
5d6ac993 812 $userID,
6a488035 813 $title,
5d6ac993
TO
814 $action = NULL,
815 $register = FALSE,
816 $reset = FALSE,
817 $profileID = NULL,
6a488035 818 $doNotProcess = FALSE,
5d6ac993 819 $ctype = NULL
6a488035
TO
820 ) {
821
822 if ($register) {
823 $controller = new CRM_Core_Controller_Simple('CRM_Profile_Form_Dynamic',
824 ts('Dynamic Form Creator'),
825 $action
826 );
827 if ($reset || $doNotProcess) {
828 // hack to make sure we do not process this form
829 $oldQFDefault = CRM_Utils_Array::value('_qf_default',
830 $_POST
831 );
832 unset($_POST['_qf_default']);
833 unset($_REQUEST['_qf_default']);
834 if ($reset) {
835 $controller->reset();
836 }
837 }
838
839 $controller->set('id', $userID);
840 $controller->set('register', 1);
841 $controller->set('skipPermission', 1);
842 $controller->set('ctype', $ctype);
843 $controller->process();
844 if ($doNotProcess || !empty($_POST)) {
845 $controller->validate();
846 }
847 $controller->setEmbedded(TRUE);
848
849 //CRM-5839 - though we want to process form, get the control back.
91768280 850 $controller->setSkipRedirection(!$doNotProcess);
6a488035
TO
851
852 $controller->run();
853
854 // we are done processing so restore the POST/REQUEST vars
855 if (($reset || $doNotProcess) && $oldQFDefault) {
856 $_POST['_qf_default'] = $_REQUEST['_qf_default'] = $oldQFDefault;
857 }
858
859 $template = CRM_Core_Smarty::singleton();
860
861 // Hide CRM error messages if they are displayed using drupal form_set_error.
862 if (!empty($_POST)) {
863 $template->assign('suppressForm', TRUE);
864 }
865
866 return trim($template->fetch('CRM/Profile/Form/Dynamic.tpl'));
867 }
868 else {
869 if (!$profileID) {
870 // make sure we have a valid group
871 $group = new CRM_Core_DAO_UFGroup();
872
873 $group->title = $title;
874
875 if ($group->find(TRUE)) {
876 $profileID = $group->id;
877 }
878 }
879
880 if ($profileID) {
881 // make sure profileID and ctype match if ctype exists
882 if ($ctype) {
883 $profileType = CRM_Core_BAO_UFField::getProfileType($profileID);
884 if (CRM_Contact_BAO_ContactType::isaSubType($profileType)) {
885 $profileType = CRM_Contact_BAO_ContactType::getBasicType($profileType);
886 }
887
888 if (($profileType != 'Contact') && ($profileType != $ctype)) {
889 return NULL;
890 }
891 }
892
893 $controller = new CRM_Core_Controller_Simple('CRM_Profile_Form_Dynamic',
894 ts('Dynamic Form Creator'),
895 $action
896 );
897 if ($reset) {
898 $controller->reset();
899 }
900 $controller->set('gid', $profileID);
901 $controller->set('id', $userID);
902 $controller->set('register', 0);
903 $controller->set('skipPermission', 1);
904 if ($ctype) {
905 $controller->set('ctype', $ctype);
906 }
907 $controller->process();
908 $controller->setEmbedded(TRUE);
909
910 //CRM-5846 - give the control back to drupal.
91768280 911 $controller->setSkipRedirection(!$doNotProcess);
6a488035
TO
912 $controller->run();
913
914 $template = CRM_Core_Smarty::singleton();
915
916 // Hide CRM error messages if they are displayed using drupal form_set_error.
917 if (!empty($_POST) && CRM_Core_Config::singleton()->userFramework == 'Drupal') {
918 if (arg(0) == 'user' || (arg(0) == 'admin' && arg(1) == 'people')) {
919 $template->assign('suppressForm', TRUE);
920 }
921 }
922
923 $templateFile = "CRM/Profile/Form/{$profileID}/Dynamic.tpl";
924 if (!$template->template_exists($templateFile)) {
925 $templateFile = 'CRM/Profile/Form/Dynamic.tpl';
926 }
927 return trim($template->fetch($templateFile));
928 }
929 else {
930 $userEmail = CRM_Contact_BAO_Contact_Location::getEmailDetails($userID);
931
932 // if post not empty then only proceed
933 if (!empty($_POST)) {
934 // get the new email
935 $config = CRM_Core_Config::singleton();
9c1bc317 936 $email = $_POST['mail'] ?? NULL;
6a488035
TO
937
938 if (CRM_Utils_Rule::email($email) && ($email != $userEmail[1])) {
939 CRM_Core_BAO_UFMatch::updateContactEmail($userID, $email);
940 }
941 }
942 }
943 }
944 return '';
945 }
946
6a488035 947 /**
f3f00653 948 * Given a contact id and a field set, return the values from the db.
6a488035 949 *
100fef9d 950 * @param int $cid
6a0b768e
TO
951 * @param array $fields
952 * The profile fields of interest.
953 * @param array $values
954 * The values for the above fields.
955 * @param bool $searchable
956 * Searchable or not.
957 * @param array $componentWhere
958 * Component condition.
959 * @param bool $absolute
960 * Return urls in absolute form (useful when sending an email).
2a6da8d7 961 * @param null $additionalWhereClause
f3f00653 962 *
963 * @return null|array
6a488035 964 */
5d6ac993
TO
965 public static function getValues(
966 $cid, &$fields, &$values,
6a488035
TO
967 $searchable = TRUE, $componentWhere = NULL,
968 $absolute = FALSE, $additionalWhereClause = NULL
969 ) {
970 if (empty($cid) && empty($componentWhere)) {
971 return NULL;
972 }
973
974 // get the contact details (hier)
975 $returnProperties = CRM_Contact_BAO_Contact::makeHierReturnProperties($fields);
a6a0cdb7 976 $params = $cid ? [['contact_id', '=', $cid, 0, 0]] : [];
6a488035
TO
977
978 // add conditions specified by components. eg partcipant_id etc
979 if (!empty($componentWhere)) {
980 $params = array_merge($params, $componentWhere);
981 }
982
983 $query = new CRM_Contact_BAO_Query($params, $returnProperties, $fields);
6a488035 984
5d6ac993 985 $details = $query->searchQuery(0, 0, NULL, FALSE, FALSE,
6a488035 986 FALSE, FALSE, FALSE, $additionalWhereClause);
6511fc14 987 while ($details->fetch()) {
c4deda45
BS
988 if (!$details) {
989 return;
990 }
6a488035 991 }
d9ab802d 992 $query->convertToPseudoNames($details);
6a488035 993
4961a325
JP
994 $locationTypes = CRM_Core_BAO_Address::buildOptions('location_type_id', 'validate');
995 $imProviders = CRM_Core_DAO_IM::buildOptions('provider_id');
996 $websiteTypes = CRM_Core_DAO_Website::buildOptions('website_type_id');
6a488035 997
a6a0cdb7 998 $multipleFields = ['url'];
6a488035
TO
999
1000 //start of code to set the default values
1001 foreach ($fields as $name => $field) {
1002 // fix for CRM-3962
1003 if ($name == 'id') {
1004 $name = 'contact_id';
1005 }
1006
1007 // skip fields that should not be displayed separately
a7488080 1008 if (!empty($field['skipDisplay'])) {
6a488035
TO
1009 continue;
1010 }
1011
50bf705c 1012 // Create a unique, non-empty index for each field.
6a488035 1013 $index = $field['title'];
f9f40af3
TO
1014 if ($index === '') {
1015 $index = ' ';
2aa397bc 1016 }
5d6ac993 1017 while (array_key_exists($index, $values)) {
50bf705c 1018 $index .= ' ';
5d6ac993 1019 }
6a488035 1020
6a488035
TO
1021 $params[$index] = $values[$index] = '';
1022 $customFieldName = NULL;
1023 // hack for CRM-665
1024 if (isset($details->$name) || $name == 'group' || $name == 'tag') {
1025 // to handle gender / suffix / prefix
a6a0cdb7 1026 if (in_array(substr($name, 0, -3), ['gender', 'prefix', 'suffix'])) {
04ffef8d 1027 $params[$index] = $details->$name;
46796b19 1028 $values[$index] = $details->$name;
6a488035
TO
1029 }
1030 elseif (in_array($name, CRM_Contact_BAO_Contact::$_greetingTypes)) {
5d6ac993 1031 $dname = $name . '_display';
6a488035 1032 $values[$index] = $details->$dname;
5d6ac993 1033 $name = $name . '_id';
6a488035
TO
1034 $params[$index] = $details->$name;
1035 }
a6a0cdb7 1036 elseif (in_array($name, [
5d6ac993
TO
1037 'state_province',
1038 'country',
21dfd5f5 1039 'county',
a6a0cdb7 1040 ])) {
6a488035 1041 $values[$index] = $details->$name;
5d6ac993 1042 $idx = $name . '_id';
6a488035
TO
1043 $params[$index] = $details->$idx;
1044 }
6a488035 1045 elseif ($name === 'preferred_language') {
6a488035 1046 $params[$index] = $details->$name;
a8c23526 1047 $values[$index] = CRM_Core_PseudoConstant::getLabel('CRM_Contact_DAO_Contact', 'preferred_language', $details->$name);
6a488035
TO
1048 }
1049 elseif ($name == 'group') {
1050 $groups = CRM_Contact_BAO_GroupContact::getContactGroup($cid, 'Added', NULL, FALSE, TRUE);
a6a0cdb7 1051 $title = $ids = [];
6a488035
TO
1052
1053 foreach ($groups as $g) {
1054 // CRM-8362: User and User Admin visibility groups should be included in display if user has
1055 // VIEW permission on that group
69953588 1056 $groupPerm = CRM_Contact_BAO_Group::checkPermission($g['group_id'], TRUE);
6a488035
TO
1057
1058 if ($g['visibility'] != 'User and User Admin Only' ||
1059 CRM_Utils_Array::key(CRM_Core_Permission::VIEW, $groupPerm)
1060 ) {
1061 $title[] = $g['title'];
1062 if ($g['visibility'] == 'Public Pages') {
1063 $ids[] = $g['group_id'];
1064 }
1065 }
1066 }
1067 $values[$index] = implode(', ', $title);
1068 $params[$index] = implode(',', $ids);
1069 }
1070 elseif ($name == 'tag') {
1071 $entityTags = CRM_Core_BAO_EntityTag::getTag($cid);
a6a0cdb7 1072 $allTags = CRM_Core_PseudoConstant::get('CRM_Core_DAO_EntityTag', 'tag_id', ['onlyActive' => FALSE]);
1073 $title = [];
6a488035
TO
1074 foreach ($entityTags as $tagId) {
1075 $title[] = $allTags[$tagId];
1076 }
1077 $values[$index] = implode(', ', $title);
1078 $params[$index] = implode(',', $entityTags);
1079 }
1080 elseif ($name == 'activity_status_id') {
1081 $activityStatus = CRM_Core_PseudoConstant::activityStatus();
1082 $values[$index] = $activityStatus[$details->$name];
1083 $params[$index] = $details->$name;
1084 }
1085 elseif ($name == 'activity_date_time') {
1086 $values[$index] = CRM_Utils_Date::customFormat($details->$name);
1087 $params[$index] = $details->$name;
1088 }
1089 elseif ($name == 'contact_sub_type') {
1090 $contactSubTypeNames = explode(CRM_Core_DAO::VALUE_SEPARATOR, $details->$name);
1091 if (!empty($contactSubTypeNames)) {
a6a0cdb7 1092 $contactSubTypeLabels = [];
6a488035
TO
1093 // get all contact subtypes
1094 $allContactSubTypes = CRM_Contact_BAO_ContactType::subTypeInfo();
1095 // build contact subtype labels array
5d6ac993 1096 foreach ($contactSubTypeNames as $cstName) {
6a488035
TO
1097 if ($cstName) {
1098 $contactSubTypeLabels[] = $allContactSubTypes[$cstName]['label'];
1099 }
1100 }
1101 $values[$index] = implode(',', $contactSubTypeLabels);
1102 }
1103
1104 $params[$index] = $details->$name;
1105 }
1106 else {
1107 if (substr($name, 0, 7) === 'do_not_' || substr($name, 0, 3) === 'is_') {
1108 if ($details->$name) {
1109 $values[$index] = '[ x ]';
1110 }
1111 }
1112 else {
1113 if ($cfID = CRM_Core_BAO_CustomField::getKeyID($name)) {
1114 $htmlType = $field['html_type'];
1115
1116 // field_type is only set when we are retrieving profile values
1117 // when sending email, we call the same function to get custom field
1118 // values etc, i.e. emulating a profile
9c1bc317 1119 $fieldType = $field['field_type'] ?? NULL;
6a488035
TO
1120
1121 if ($htmlType == 'File') {
1122 $entityId = $cid;
1123 if (!$cid &&
5d6ac993
TO
1124 $fieldType == 'Activity' && !empty($componentWhere[0][2])
1125 ) {
6a488035
TO
1126 $entityId = $componentWhere[0][2];
1127 }
1128
1129 $fileURL = CRM_Core_BAO_CustomField::getFileURL($entityId,
1130 $cfID,
1131 NULL,
b42d84aa 1132 $absolute,
1133 $additionalWhereClause
6a488035
TO
1134 );
1135 $params[$index] = $values[$index] = $fileURL['file_url'];
1136 }
1137 else {
1138 $customVal = NULL;
1139 if (isset($dao) && property_exists($dao, 'data_type') &&
1140 ($dao->data_type == 'Int' ||
1141 $dao->data_type == 'Boolean'
1142 )
1143 ) {
5d6ac993 1144 $customVal = (int ) ($details->{$name});
6a488035
TO
1145 }
1146 elseif (isset($dao) && property_exists($dao, 'data_type')
1147 && $dao->data_type == 'Float'
1148 ) {
5d6ac993 1149 $customVal = (float ) ($details->{$name});
6a488035
TO
1150 }
1151 elseif (!CRM_Utils_System::isNull(explode(CRM_Core_DAO::VALUE_SEPARATOR,
5d6ac993
TO
1152 $details->{$name}
1153 ))
1154 ) {
6a488035
TO
1155 $customVal = $details->{$name};
1156 }
1157
1158 //CRM-4582
1159 if (CRM_Utils_System::isNull($customVal)) {
1160 continue;
1161 }
1162
1163 $params[$index] = $customVal;
8cee0c70 1164 $values[$index] = CRM_Core_BAO_CustomField::displayValue($customVal, $cfID);
1b4d9e39 1165 if ($field['data_type'] == 'ContactReference') {
6a488035
TO
1166 $params[$index] = $values[$index];
1167 }
1168 if (CRM_Core_DAO::getFieldValue('CRM_Core_DAO_CustomField',
5d6ac993
TO
1169 $cfID, 'is_search_range'
1170 )
1171 ) {
6a488035
TO
1172 $customFieldName = "{$name}_from";
1173 }
1174 }
1175 }
1176 elseif ($name == 'image_URL') {
77d45291 1177 list($width, $height) = getimagesize(CRM_Utils_String::unstupifyUrl($details->$name));
6a488035
TO
1178 list($thumbWidth, $thumbHeight) = CRM_Contact_BAO_Contact::getThumbSize($width, $height);
1179
1180 $image_URL = '<img src="' . $details->$name . '" height= ' . $thumbHeight . ' width= ' . $thumbWidth . ' />';
1181 $values[$index] = "<a href='#' onclick='contactImagePopUp(\"{$details->$name}\", {$width}, {$height});'>{$image_URL}</a>";
1182 }
a6a0cdb7 1183 elseif (in_array($name, [
5d6ac993
TO
1184 'birth_date',
1185 'deceased_date',
a6a0cdb7 1186 ])) {
363544d7 1187 // @todo this set should be determined from metadata, not hard-coded.
6a488035
TO
1188 $values[$index] = CRM_Utils_Date::customFormat($details->$name);
1189 $params[$index] = CRM_Utils_Date::isoToMysql($details->$name);
1190 }
1191 else {
1192 $dao = '';
1193 if ($index == 'Campaign') {
1194 $dao = 'CRM_Campaign_DAO_Campaign';
1195 }
1196 elseif ($index == 'Contribution Page') {
1197 $dao = 'CRM_Contribute_DAO_ContributionPage';
1198 }
1199 if ($dao) {
1200 $value = CRM_Core_DAO::getFieldValue($dao, $details->$name, 'title');
1201 }
1202 else {
1203 $value = $details->$name;
1204 }
1205 $values[$index] = $value;
1206 }
1207 }
1208 }
1209 }
1210 elseif (strpos($name, '-') !== FALSE) {
1211 list($fieldName, $id, $type) = CRM_Utils_System::explode('-', $name, 3);
1212
1213 if (!in_array($fieldName, $multipleFields)) {
1214 if ($id == 'Primary') {
1215 // fix for CRM-1543
1216 // not sure why we'd every use Primary location type id
1217 // we need to fix the source if we are using it
1218 // $locationTypeName = CRM_Contact_BAO_Contact::getPrimaryLocationType( $cid );
1219 $locationTypeName = 1;
1220 }
1221 else {
9c1bc317 1222 $locationTypeName = $locationTypes[$id] ?? NULL;
6a488035
TO
1223 }
1224
1225 if (!$locationTypeName) {
1226 continue;
1227 }
1228
1229 $detailName = "{$locationTypeName}-{$fieldName}";
1230 $detailName = str_replace(' ', '_', $detailName);
1231
a6a0cdb7 1232 if (in_array($fieldName, [
5d6ac993
TO
1233 'phone',
1234 'im',
1235 'email',
21dfd5f5 1236 'openid',
a6a0cdb7 1237 ])) {
6a488035
TO
1238 if ($type) {
1239 $detailName .= "-{$type}";
1240 }
1241 }
1242
a6a0cdb7 1243 if (in_array($fieldName, [
5d6ac993
TO
1244 'state_province',
1245 'country',
21dfd5f5 1246 'county',
a6a0cdb7 1247 ])) {
6a488035 1248 $values[$index] = $details->$detailName;
5d6ac993 1249 $idx = $detailName . '_id';
6a488035
TO
1250 $params[$index] = $details->$idx;
1251 }
1252 elseif ($fieldName == 'im') {
1253 $providerId = $detailName . '-provider_id';
38913d36
TO
1254 if (isset($imProviders[$details->$providerId])) {
1255 $values[$index] = $details->$detailName . " (" . $imProviders[$details->$providerId] . ")";
6a488035
TO
1256 }
1257 else {
1258 $values[$index] = $details->$detailName;
1259 }
1260 $params[$index] = $details->$detailName;
1261 }
1262 elseif ($fieldName == 'phone') {
1263 $phoneExtField = str_replace('phone', 'phone_ext', $detailName);
1264 if (isset($details->$phoneExtField)) {
1265 $values[$index] = $details->$detailName . " (" . $details->$phoneExtField . ")";
1266 }
1267 else {
1268 $values[$index] = $details->$detailName;
1269 }
1270 $params[$index] = $details->$detailName;
1271 }
1272 else {
1273 $values[$index] = $params[$index] = $details->$detailName;
1274 }
1275 }
1276 else {
1277 $detailName = "website-{$id}-{$fieldName}";
1278 $url = CRM_Utils_System::fixURL($details->$detailName);
1279 if ($details->$detailName) {
5d6ac993
TO
1280 $websiteTypeId = "website-{$id}-website_type_id";
1281 $websiteType = $websiteTypes[$details->$websiteTypeId];
6a488035
TO
1282 $values[$index] = "<a href=\"$url\">{$details->$detailName} ( {$websiteType} )</a>";
1283 }
1284 else {
1285 $values[$index] = '';
1286 }
1287 }
1288 }
1289
1290 if ((CRM_Utils_Array::value('visibility', $field) == 'Public Pages and Listings') &&
1291 CRM_Core_Permission::check('profile listings and forms')
1292 ) {
1293
1294 if (CRM_Utils_System::isNull($params[$index])) {
1295 $params[$index] = $values[$index];
1296 }
1297 if (!isset($params[$index])) {
1298 continue;
1299 }
1300 if (!$customFieldName) {
1301 $fieldName = $field['name'];
1302 }
1303 else {
1304 $fieldName = $customFieldName;
1305 }
1306
1307 $url = NULL;
1308 if (CRM_Core_BAO_CustomField::getKeyID($field['name'])) {
1309 $htmlType = $field['html_type'];
1310 if ($htmlType == 'Link') {
1311 $url = $params[$index];
1312 }
a6a0cdb7 1313 elseif (in_array($htmlType, [
5d6ac993
TO
1314 'CheckBox',
1315 'Multi-Select',
5d6ac993
TO
1316 'Multi-Select State/Province',
1317 'Multi-Select Country',
a6a0cdb7 1318 ])) {
6a488035
TO
1319 $valSeperator = CRM_Core_DAO::VALUE_SEPARATOR;
1320 $selectedOptions = explode($valSeperator, $params[$index]);
1321
1322 foreach ($selectedOptions as $key => $multiOption) {
1323 if ($multiOption) {
1324 $url[] = CRM_Utils_System::url('civicrm/profile',
1325 'reset=1&force=1&gid=' . $field['group_id'] . '&' .
1326 urlencode($fieldName) .
1327 '=' .
1328 urlencode($multiOption)
1329 );
1330 }
1331 }
1332 }
1333 else {
1334 $url = CRM_Utils_System::url('civicrm/profile',
1335 'reset=1&force=1&gid=' . $field['group_id'] . '&' .
1336 urlencode($fieldName) .
1337 '=' .
1338 urlencode($params[$index])
1339 );
1340 }
1341 }
1342 else {
1343 $url = CRM_Utils_System::url('civicrm/profile',
1344 'reset=1&force=1&gid=' . $field['group_id'] . '&' .
1345 urlencode($fieldName) .
1346 '=' .
1347 urlencode($params[$index])
1348 );
1349 }
1350
1351 if ($url &&
1352 !empty($values[$index]) &&
1353 $searchable
1354 ) {
1355
1356 if (is_array($url) && !empty($url)) {
a6a0cdb7 1357 $links = [];
6a488035
TO
1358 $eachMultiValue = explode(', ', $values[$index]);
1359 foreach ($eachMultiValue as $key => $valueLabel) {
1360 $links[] = '<a href="' . $url[$key] . '">' . $valueLabel . '</a>';
1361 }
1362 $values[$index] = implode(', ', $links);
1363 }
1364 else {
1365 $values[$index] = '<a href="' . $url . '">' . $values[$index] . '</a>';
1366 }
1367 }
1368 }
1369 }
1370 }
1371
1372 /**
1373 * Check if profile Group used by any module.
1374 *
6a0b768e
TO
1375 * @param int $id
1376 * Profile Id.
6a488035 1377 *
e7483cbe 1378 * @return bool
6a488035 1379 *
6a488035
TO
1380 */
1381 public static function usedByModule($id) {
1382 //check whether this group is used by any module(check uf join records)
1383 $sql = "SELECT id
1384 FROM civicrm_uf_join
1385 WHERE civicrm_uf_join.uf_group_id=$id";
1386
1387 $dao = new CRM_Core_DAO();
1388 $dao->query($sql);
1389 if ($dao->fetch()) {
1390 return TRUE;
1391 }
1392 else {
1393 return FALSE;
1394 }
1395 }
1396
1397 /**
1398 * Delete the profile Group.
1399 *
6a0b768e
TO
1400 * @param int $id
1401 * Profile Id.
6a488035 1402 *
e7483cbe 1403 * @return bool
6a488035 1404 *
6a488035
TO
1405 */
1406 public static function del($id) {
1407 //check whether this group contains any profile fields
1408 $profileField = new CRM_Core_DAO_UFField();
1409 $profileField->uf_group_id = $id;
1410 $profileField->find();
1411 while ($profileField->fetch()) {
1412 CRM_Core_BAO_UFField::del($profileField->id);
1413 }
1414
1415 //delete records from uf join table
1416 $ufJoin = new CRM_Core_DAO_UFJoin();
1417 $ufJoin->uf_group_id = $id;
1418 $ufJoin->delete();
1419
1420 //delete profile group
1421 $group = new CRM_Core_DAO_UFGroup();
1422 $group->id = $id;
1423 $group->delete();
1424 return 1;
1425 }
1426
1427 /**
fe482240 1428 * Add the UF Group.
6a488035 1429 *
6a0b768e
TO
1430 * @param array $params
1431 * Reference array contains the values submitted by the form.
1432 * @param array $ids
1433 * Reference array contains the id.
6a488035 1434 *
6a488035
TO
1435 *
1436 * @return object
1437 */
a6a0cdb7 1438 public static function add(&$params, $ids = []) {
1439 $fields = [
5d6ac993
TO
1440 'is_active',
1441 'add_captcha',
1442 'is_map',
1443 'is_update_dupe',
1444 'is_edit_link',
1445 'is_uf_link',
21dfd5f5 1446 'is_cms_user',
a6a0cdb7 1447 ];
6a488035
TO
1448 foreach ($fields as $field) {
1449 $params[$field] = CRM_Utils_Array::value($field, $params, FALSE);
1450 }
1451
9c1bc317
CW
1452 $params['limit_listings_group_id'] = $params['group'] ?? NULL;
1453 $params['add_to_group_id'] = $params['add_contact_to_group'] ?? NULL;
6a488035 1454
f80ef0e2 1455 //CRM-15427
1456 if (!empty($params['group_type']) && is_array($params['group_type'])) {
1457 $params['group_type'] = implode(',', $params['group_type']);
1458 }
6a488035
TO
1459 $ufGroup = new CRM_Core_DAO_UFGroup();
1460 $ufGroup->copyValues($params);
1461
6a73ef3f 1462 $ufGroupID = CRM_Utils_Array::value('ufgroup', $ids, CRM_Utils_Array::value('id', $params));
25973039 1463 if (!$ufGroupID && empty($params['name'])) {
6a488035
TO
1464 $ufGroup->name = CRM_Utils_String::munge($ufGroup->title, '_', 56);
1465 }
1466 $ufGroup->id = $ufGroupID;
1467
1468 $ufGroup->save();
1469
25973039 1470 if (!$ufGroupID && empty($params['name'])) {
6a488035
TO
1471 $ufGroup->name = $ufGroup->name . "_{$ufGroup->id}";
1472 $ufGroup->save();
1473 }
1474
1475 return $ufGroup;
1476 }
1477
1478 /**
fe482240 1479 * Make uf join entries for an uf group.
6a488035 1480 *
259ab031 1481 * @param int $weight
1482 * @param array $groupTypes
1483 * An assoc array of name/value pairs.
6a0b768e
TO
1484 * @param int $ufGroupId
1485 * Ufgroup id.
6a488035 1486 */
259ab031 1487 public static function createUFJoin($weight, $groupTypes, $ufGroupId) {
6a488035
TO
1488
1489 // get ufjoin records for uf group
1490 $ufGroupRecord = CRM_Core_BAO_UFGroup::getUFJoinRecord($ufGroupId);
1491
1492 // get the list of all ufgroup types
1493 $allUFGroupType = CRM_Core_SelectValues::ufGroupTypes();
1494
1495 // this fix is done to prevent warning generated by array_key_exits incase of empty array is given as input
1496 if (!is_array($groupTypes)) {
a6a0cdb7 1497 $groupTypes = [];
6a488035
TO
1498 }
1499
1500 // this fix is done to prevent warning generated by array_key_exits incase of empty array is given as input
1501 if (!is_array($ufGroupRecord)) {
a6a0cdb7 1502 $ufGroupRecord = [];
6a488035
TO
1503 }
1504
1505 // check which values has to be inserted/deleted for contact
1506 $menuRebuild = FALSE;
1507 foreach ($allUFGroupType as $key => $value) {
a6a0cdb7 1508 $joinParams = [];
6a488035
TO
1509 $joinParams['uf_group_id'] = $ufGroupId;
1510 $joinParams['module'] = $key;
259ab031 1511 if ($key === 'User Account') {
6a488035
TO
1512 $menuRebuild = TRUE;
1513 }
1514 if (array_key_exists($key, $groupTypes) && !in_array($key, $ufGroupRecord)) {
1515 // insert a new record
1516 CRM_Core_BAO_UFGroup::addUFJoin($joinParams);
1517 }
1518 elseif (!array_key_exists($key, $groupTypes) && in_array($key, $ufGroupRecord)) {
1519 // delete a record for existing ufgroup
1520 CRM_Core_BAO_UFGroup::delUFJoin($joinParams);
1521 }
1522 }
1523
1524 //update the weight
259ab031 1525 $query = '
6a488035
TO
1526UPDATE civicrm_uf_join
1527SET weight = %1
1528WHERE uf_group_id = %2
1529AND ( entity_id IS NULL OR entity_id <= 0 )
259ab031 1530';
a6a0cdb7 1531 $p = [
259ab031 1532 1 => [$weight, 'Integer'],
a6a0cdb7 1533 2 => [$ufGroupId, 'Integer'],
1534 ];
6a488035
TO
1535 CRM_Core_DAO::executeQuery($query, $p);
1536
4d16a7e1
DS
1537 // Do a menu rebuild, so it gets all the new menu entries for user account
1538 if ($menuRebuild) {
1539 $config = CRM_Core_Config::singleton();
1540 $config->userSystem->updateCategories();
6a488035
TO
1541 }
1542 }
1543
1544 /**
fe482240 1545 * Get the UF Join records for an ufgroup id.
6a488035 1546 *
6a0b768e
TO
1547 * @param int $ufGroupId
1548 * Uf group id.
1549 * @param int $displayName
1550 * If set return display name in array.
1551 * @param int $status
1552 * If set return module other than default modules (User Account/User registration/Profile).
77b97be7 1553 *
a6c01b45 1554 * @return array
6a488035 1555 *
6a488035
TO
1556 */
1557 public static function getUFJoinRecord($ufGroupId = NULL, $displayName = NULL, $status = NULL) {
1558 if ($displayName) {
a6a0cdb7 1559 $UFGroupType = [];
6a488035
TO
1560 $UFGroupType = CRM_Core_SelectValues::ufGroupTypes();
1561 }
1562
a6a0cdb7 1563 $ufJoin = [];
6a488035
TO
1564 $dao = new CRM_Core_DAO_UFJoin();
1565
1566 if ($ufGroupId) {
1567 $dao->uf_group_id = $ufGroupId;
1568 }
1569
1570 $dao->find();
a6a0cdb7 1571 $ufJoin = [];
6a488035
TO
1572
1573 while ($dao->fetch()) {
1574 if (!$displayName) {
1575 $ufJoin[$dao->id] = $dao->module;
1576 }
1577 else {
1578 if (isset($UFGroupType[$dao->module])) {
1579 // skip the default modules
1580 if (!$status) {
1581 $ufJoin[$dao->id] = $UFGroupType[$dao->module];
1582 }
1583 // added for CRM-1475
1584 }
1585 elseif (!CRM_Utils_Array::key($dao->module, $ufJoin)) {
1586 $ufJoin[$dao->id] = $dao->module;
1587 }
1588 }
1589 }
1590 return $ufJoin;
1591 }
1592
1593 /**
fe482240 1594 * Function takes an associative array and creates a ufjoin record for ufgroup.
6a488035 1595 *
6a0b768e
TO
1596 * @param array $params
1597 * (reference) an assoc array of name/value pairs.
6a488035 1598 *
16b10e64 1599 * @return CRM_Core_BAO_UFJoin
6a488035 1600 */
00be9182 1601 public static function addUFJoin(&$params) {
6a488035
TO
1602 $ufJoin = new CRM_Core_DAO_UFJoin();
1603 $ufJoin->copyValues($params);
1604 $ufJoin->save();
1605 return $ufJoin;
1606 }
1607
1608 /**
fe482240 1609 * Delete the uf join record for an uf group.
6a488035 1610 *
6a0b768e
TO
1611 * @param array $params
1612 * (reference) an assoc array of name/value pairs.
6a488035 1613 */
00be9182 1614 public static function delUFJoin(&$params) {
6a488035
TO
1615 $ufJoin = new CRM_Core_DAO_UFJoin();
1616 $ufJoin->copyValues($params);
1617 $ufJoin->delete();
1618 }
1619
1620 /**
fe482240 1621 * Get the weight for ufjoin record.
6a488035 1622 *
6a0b768e
TO
1623 * @param int $ufGroupId
1624 * If $ufGroupId get update weight or add weight.
6a488035 1625 *
a6c01b45
CW
1626 * @return int
1627 * weight of the UFGroup
6a488035 1628 */
00be9182 1629 public static function getWeight($ufGroupId = NULL) {
6a488035 1630 //calculate the weight
a6a0cdb7 1631 $p = [];
6a488035
TO
1632 if (!$ufGroupId) {
1633 $queryString = "SELECT ( MAX(civicrm_uf_join.weight)+1) as new_weight
1634 FROM civicrm_uf_join
1635 WHERE module = 'User Registration' OR module = 'User Account' OR module = 'Profile'";
1636 }
1637 else {
1638 $queryString = "SELECT MAX(civicrm_uf_join.weight) as new_weight
1639 FROM civicrm_uf_join
1640 WHERE civicrm_uf_join.uf_group_id = %1
1641 AND ( entity_id IS NULL OR entity_id <= 0 )";
a6a0cdb7 1642 $p[1] = [$ufGroupId, 'Integer'];
6a488035
TO
1643 }
1644
1645 $dao = CRM_Core_DAO::executeQuery($queryString, $p);
1646 $dao->fetch();
1647 return ($dao->new_weight) ? $dao->new_weight : 1;
1648 }
1649
1650 /**
fe482240 1651 * Get the uf group for a module.
6a488035 1652 *
6a0b768e
TO
1653 * @param string $moduleName
1654 * Module name.
1655 * @param int $count
1656 * No to increment the weight.
77b97be7 1657 * @param bool $skipPermission
6a0b768e
TO
1658 * @param int $op
1659 * Which operation (view, edit, create, etc) to check permission for.
2141efbf 1660 * @param array|NULL $returnFields list of UFGroup fields to return; NULL for default
6a488035 1661 *
a6c01b45
CW
1662 * @return array
1663 * array of ufgroups for a module
6a488035 1664 */
2141efbf 1665 public static function getModuleUFGroup($moduleName = NULL, $count = 0, $skipPermission = TRUE, $op = CRM_Core_Permission::VIEW, $returnFields = NULL) {
c4baa1da 1666 $selectFields = ['id', 'title', 'created_id', 'is_active', 'is_reserved', 'group_type', 'description'];
290d4ccc 1667
eed7e803 1668 if (CRM_Core_BAO_SchemaHandler::checkIfFieldExists('civicrm_uf_group', 'frontend_title')) {
ce1a9db4 1669 $selectFields[] = 'frontend_title';
290d4ccc 1670 }
7ba38389 1671
1672 if (!empty($returnFields)) {
1673 $selectFields = array_merge($returnFields, array_diff($selectFields, $returnFields));
2141efbf 1674 }
7ba38389 1675
1676 $queryString = 'SELECT civicrm_uf_group.' . implode(', civicrm_uf_group.', $selectFields) . '
6a488035
TO
1677 FROM civicrm_uf_group
1678 LEFT JOIN civicrm_uf_join ON (civicrm_uf_group.id = uf_group_id)';
a6a0cdb7 1679 $p = [];
6a488035
TO
1680 if ($moduleName) {
1681 $queryString .= ' AND civicrm_uf_group.is_active = 1
1682 WHERE civicrm_uf_join.module = %2';
a6a0cdb7 1683 $p[2] = [$moduleName, 'String'];
6a488035
TO
1684 }
1685
6a488035
TO
1686 // add permissioning for profiles only if not registration
1687 if (!$skipPermission) {
1688 $permissionClause = CRM_Core_Permission::ufGroupClause($op, 'civicrm_uf_group.');
1689 if (strpos($queryString, 'WHERE') !== FALSE) {
1690 $queryString .= " AND $permissionClause ";
1691 }
1692 else {
1693 $queryString .= " $permissionClause ";
1694 }
1695 }
1696
1697 $queryString .= ' ORDER BY civicrm_uf_join.weight, civicrm_uf_group.title';
1698 $dao = CRM_Core_DAO::executeQuery($queryString, $p);
1699
a6a0cdb7 1700 $ufGroups = [];
6a488035
TO
1701 while ($dao->fetch()) {
1702 //skip mix profiles in user Registration / User Account
a6a0cdb7 1703 if (($moduleName === 'User Registration' || $moduleName === 'User Account') &&
6a488035
TO
1704 CRM_Core_BAO_UFField::checkProfileType($dao->id)
1705 ) {
1706 continue;
1707 }
7ba38389 1708 foreach ($selectFields as $key => $field) {
a6a0cdb7 1709 if ($field === 'id') {
7ba38389 1710 continue;
1711 }
7ba38389 1712 $ufGroups[$dao->id][$field] = $dao->$field;
1713 }
6a488035
TO
1714 }
1715
1716 // Allow other modules to alter/override the UFGroups.
1717 CRM_Utils_Hook::buildUFGroupsForModule($moduleName, $ufGroups);
1718
1719 return $ufGroups;
1720 }
1721
1722 /**
fe482240 1723 * Filter ufgroups based on logged in user contact type.
6a488035 1724 *
6a0b768e
TO
1725 * @param int $ufGroupId
1726 * Uf group id (profile id).
c490a46a 1727 * @param int $contactID
77b97be7 1728 *
e7483cbe 1729 * @return bool
a6c01b45 1730 * true or false
6a488035 1731 */
00be9182 1732 public static function filterUFGroups($ufGroupId, $contactID = NULL) {
6a488035
TO
1733 if (!$contactID) {
1734 $session = CRM_Core_Session::singleton();
1735 $contactID = $session->get('userID');
1736 }
1737
1738 if ($contactID) {
1739 //get the contact type
1740 $contactType = CRM_Contact_BAO_Contact::getContactType($contactID);
1741
1742 //match if exixting contact type is same as profile contact type
1743 $profileType = CRM_Core_BAO_UFField::getProfileType($ufGroupId);
1744
1745 if (CRM_Contact_BAO_ContactType::isaSubType($profileType)) {
1746 $profileType = CRM_Contact_BAO_ContactType::getBasicType($profileType);
34daab76
M
1747
1748 //in some cases getBasicType() returns a cached array instead of string. Example: array ('sponsor' => 'organization')
1749 if (is_array($profileType)) {
1750 $profileType = array_shift($profileType);
1751 }
6a488035
TO
1752 }
1753
1754 //allow special mix profiles for Contribution and Participant
a6a0cdb7 1755 $specialProfiles = ['Contribution', 'Participant', 'Membership'];
6a488035
TO
1756
1757 if (in_array($profileType, $specialProfiles)) {
1758 return TRUE;
1759 }
1760
1761 if (($contactType == $profileType) || $profileType == 'Contact') {
1762 return TRUE;
1763 }
1764 }
1765
1766 return FALSE;
1767 }
1768
1769 /**
fe482240 1770 * Add profile field to a form.
6a488035 1771 *
c927c151 1772 * @param CRM_Core_Form $form
6a0b768e
TO
1773 * @param array $field
1774 * Properties.
1775 * @param int $mode
1776 * Profile mode.
1f177c6b 1777 * @param int $contactId
77b97be7 1778 * @param bool $online
6a0b768e
TO
1779 * @param string $usedFor
1780 * For building up prefixed fieldname for special cases (e.g. onBehalf, Honor).
1f177c6b 1781 * @param int $rowNumber
77b97be7
EM
1782 * @param string $prefix
1783 *
6a488035 1784 * @return null
6a488035 1785 */
e7483cbe 1786 public static function buildProfile(
6a488035
TO
1787 &$form,
1788 &$field,
1789 $mode,
1790 $contactId = NULL,
1791 $online = FALSE,
133e2c99 1792 $usedFor = NULL,
5d6ac993 1793 $rowNumber = NULL,
6a488035
TO
1794 $prefix = ''
1795 ) {
a6a0cdb7 1796 $defaultValues = [];
1f177c6b
CW
1797 $fieldName = $field['name'];
1798 $title = $field['title'];
1799 $attributes = $field['attributes'];
1800 $rule = $field['rule'];
1801 $view = $field['is_view'];
1802 $required = ($mode == CRM_Profile_Form::MODE_SEARCH) ? FALSE : $field['is_required'];
63d76404 1803 $search = $mode == CRM_Profile_Form::MODE_SEARCH;
1f177c6b 1804 $isShared = CRM_Utils_Array::value('is_shared', $field, 0);
6a488035
TO
1805
1806 // do not display view fields in drupal registration form
1807 // CRM-4632
1808 if ($view && $mode == CRM_Profile_Form::MODE_REGISTER) {
e7483cbe 1809 return NULL;
6a488035
TO
1810 }
1811
133e2c99 1812 if ($usedFor == 'onbehalf') {
6a488035
TO
1813 $name = "onbehalf[$fieldName]";
1814 }
133e2c99 1815 elseif ($usedFor == 'honor') {
1816 $name = "honor[$fieldName]";
1817 }
6a488035
TO
1818 elseif ($contactId && !$online) {
1819 $name = "field[$contactId][$fieldName]";
1820 }
1821 elseif ($rowNumber) {
1822 $name = "field[$rowNumber][$fieldName]";
1823 }
1824 elseif (!empty($prefix)) {
5d6ac993 1825 $name = $prefix . "[$fieldName]";
6a488035
TO
1826 }
1827 else {
1828 $name = $fieldName;
1829 }
9e1854a1 1830
a6a0cdb7 1831 $selectAttributes = ['class' => 'crm-select2', 'placeholder' => TRUE];
6a488035
TO
1832
1833 if ($fieldName == 'image_URL' && $mode == CRM_Profile_Form::MODE_EDIT) {
e8fb9449 1834 $deleteExtra = json_encode(ts('Are you sure you want to delete contact image.'));
a6a0cdb7 1835 $deleteURL = [
1836 CRM_Core_Action::DELETE => [
e7483cbe
J
1837 'name' => ts('Delete Contact Image'),
1838 'url' => 'civicrm/contact/image',
1839 'qs' => 'reset=1&id=%%id%%&gid=%%gid%%&action=delete',
e8fb9449 1840 'extra' => 'onclick = "' . htmlspecialchars("if (confirm($deleteExtra)) this.href+='&confirmed=1'; else return false;") . '"',
a6a0cdb7 1841 ],
1842 ];
6a488035
TO
1843 $deleteURL = CRM_Core_Action::formLink($deleteURL,
1844 CRM_Core_Action::DELETE,
a6a0cdb7 1845 [
5d6ac993 1846 'id' => $form->get('id'),
6a488035 1847 'gid' => $form->get('gid'),
a6a0cdb7 1848 ],
87dab4a4
AH
1849 ts('more'),
1850 FALSE,
1851 'contact.profileimage.delete',
1852 'Contact',
1853 $form->get('id')
6a488035
TO
1854 );
1855 $form->assign('deleteURL', $deleteURL);
1856 }
1857 $addressOptions = CRM_Core_BAO_Setting::valueOptions(CRM_Core_BAO_Setting::SYSTEM_PREFERENCES_NAME,
1858 'address_options', TRUE, NULL, TRUE
1859 );
1860
1861 if (substr($fieldName, 0, 14) === 'state_province') {
a6a0cdb7 1862 $form->addChainSelect($name, ['label' => $title, 'required' => $required]);
6a488035 1863 $config = CRM_Core_Config::singleton();
a6a0cdb7 1864 if (!in_array($mode, [CRM_Profile_Form::MODE_EDIT, CRM_Profile_Form::MODE_SEARCH]) &&
6a488035
TO
1865 $config->defaultContactStateProvince
1866 ) {
1867 $defaultValues[$name] = $config->defaultContactStateProvince;
1868 $form->setDefaults($defaultValues);
1869 }
1870 }
1871 elseif (substr($fieldName, 0, 7) === 'country') {
a6a0cdb7 1872 $form->add('select', $name, $title, ['' => ts('- select -')] + CRM_Core_PseudoConstant::country(), $required, $selectAttributes);
6a488035 1873 $config = CRM_Core_Config::singleton();
a6a0cdb7 1874 if (!in_array($mode, [CRM_Profile_Form::MODE_EDIT, CRM_Profile_Form::MODE_SEARCH]) &&
6a488035
TO
1875 $config->defaultContactCountry
1876 ) {
1877 $defaultValues[$name] = $config->defaultContactCountry;
1878 $form->setDefaults($defaultValues);
1879 }
1880 }
1881 elseif (substr($fieldName, 0, 6) === 'county') {
1882 if ($addressOptions['county']) {
a6a0cdb7 1883 $form->addChainSelect($name, ['label' => $title, 'required' => $required]);
6a488035
TO
1884 }
1885 }
1886 elseif (substr($fieldName, 0, 9) === 'image_URL') {
1887 $form->add('file', $name, $title, $attributes, $required);
1888 $form->addUploadElement($name);
1889 }
1890 elseif (substr($fieldName, 0, 2) === 'im') {
1891 $form->add('text', $name, $title, $attributes, $required);
1892 if (!$contactId) {
133e2c99 1893 if ($usedFor) {
a6a0cdb7 1894 if (substr($name, -1) === ']') {
6a488035
TO
1895 $providerName = substr($name, 0, -1) . '-provider_id]';
1896 }
1897 $form->add('select', $providerName, NULL,
a6a0cdb7 1898 [
21dfd5f5 1899 '' => ts('- select -'),
a6a0cdb7 1900 ] + CRM_Core_PseudoConstant::get('CRM_Core_DAO_IM', 'provider_id'), $required
6a488035
TO
1901 );
1902 }
1903 else {
1904 $form->add('select', $name . '-provider_id', $title,
a6a0cdb7 1905 [
21dfd5f5 1906 '' => ts('- select -'),
a6a0cdb7 1907 ] + CRM_Core_PseudoConstant::get('CRM_Core_DAO_IM', 'provider_id'), $required
6a488035
TO
1908 );
1909 }
1910
1911 if ($view && $mode != CRM_Profile_Form::MODE_SEARCH) {
1912 $form->freeze($name . '-provider_id');
1913 }
1914 }
1915 }
5d6ac993 1916 elseif (CRM_Utils_Array::value('name', $field) == 'membership_type') {
6a488035
TO
1917 list($orgInfo, $types) = CRM_Member_BAO_MembershipType::getMembershipTypeInfo();
1918 $sel = &$form->addElement('hierselect', $name, $title);
a6a0cdb7 1919 $select = ['' => ts('- select -')];
5d6ac993 1920 if (count($orgInfo) == 1 && $field['is_required']) {
53cfc93c 1921 // we only have one org - so we should default to it. Not sure about defaulting to first type
1922 // as it could be missed - so adding a select
1923 // however, possibly that is more similar to the membership form
5d6ac993 1924 if (count($types[1]) > 1) {
53cfc93c 1925 $types[1] = $select + $types[1];
1926 }
1927 }
1928 else {
1929 $orgInfo = $select + $orgInfo;
1930 }
a6a0cdb7 1931 $sel->setOptions([$orgInfo, $types]);
6a488035 1932 }
5d6ac993 1933 elseif (CRM_Utils_Array::value('name', $field) == 'membership_status') {
6a488035 1934 $form->add('select', $name, $title,
a6a0cdb7 1935 [
21dfd5f5 1936 '' => ts('- select -'),
a6a0cdb7 1937 ] + CRM_Member_PseudoConstant::membershipStatus(NULL, NULL, 'label'), $required
6a488035
TO
1938 );
1939 }
a6a0cdb7 1940 elseif (in_array($fieldName, ['gender_id', 'communication_style_id'])) {
1941 $options = [];
ee015de4 1942 $pseudoValues = CRM_Core_PseudoConstant::get('CRM_Contact_DAO_Contact', $fieldName);
39405208 1943 $form->addRadio($name, ts('%1', [1 => $title]), $pseudoValues, ['allowClear' => !$required], NULL, $required);
6a488035 1944 }
f45334bd 1945 elseif ($fieldName === 'prefix_id' || $fieldName === 'suffix_id') {
a6a0cdb7 1946 $form->addSelect($name, [
1f177c6b
CW
1947 'label' => $title,
1948 'entity' => 'contact',
1949 'field' => $fieldName,
1950 'class' => 'six',
1951 'placeholder' => '',
a6a0cdb7 1952 ], $required);
6a488035
TO
1953 }
1954 elseif ($fieldName === 'contact_sub_type') {
1955 $gId = $form->get('gid') ? $form->get('gid') : CRM_Utils_Array::value('group_id', $field);
133e2c99 1956 if ($usedFor == 'onbehalf') {
6a488035
TO
1957 $profileType = 'Organization';
1958 }
133e2c99 1959 elseif ($usedFor == 'honor') {
1960 $profileType = CRM_Core_BAO_UFField::getProfileType($form->_params['honoree_profile_id']);
1961 }
6a488035
TO
1962 else {
1963 $profileType = $gId ? CRM_Core_BAO_UFField::getProfileType($gId) : NULL;
1964 if ($profileType == 'Contact') {
1965 $profileType = 'Individual';
1966 }
1967 }
1968
1969 $setSubtype = FALSE;
1970 if (CRM_Contact_BAO_ContactType::isaSubType($profileType)) {
1971 $setSubtype = $profileType;
1972 $profileType = CRM_Contact_BAO_ContactType::getBasicType($profileType);
1973 }
1974
a6a0cdb7 1975 $subtypes = $profileType ? CRM_Contact_BAO_ContactType::subTypePairs($profileType) : [];
6a488035
TO
1976
1977 if ($setSubtype) {
a6a0cdb7 1978 $subtypeList = [];
6a488035
TO
1979 $subtypeList[$setSubtype] = $subtypes[$setSubtype];
1980 }
1981 else {
1982 $subtypeList = $subtypes;
1983 }
1984
a6a0cdb7 1985 $form->add('select', $name, $title, $subtypeList, $required, ['class' => 'crm-select2', 'multiple' => TRUE]);
6a488035
TO
1986 }
1987 elseif (in_array($fieldName, CRM_Contact_BAO_Contact::$_greetingTypes)) {
d43d0639
CW
1988 // Get contact type for greeting selector
1989 $gId = $form->get('gid') ?: CRM_Utils_Array::value('group_id', $field);
6a488035
TO
1990 $profileType = CRM_Core_BAO_UFField::getProfileType($gId, TRUE, FALSE, TRUE);
1991
d43d0639
CW
1992 if (!$profileType || in_array($profileType, ['Contact', 'Contribution', 'Participant', 'Membership'])) {
1993 $profileType = ($profileType == 'Contact' && $form->get('id')) ? CRM_Contact_BAO_Contact::getContactType($form->get('id')) : 'Individual';
6a488035
TO
1994 }
1995 if (CRM_Contact_BAO_ContactType::isaSubType($profileType)) {
1996 $profileType = CRM_Contact_BAO_ContactType::getBasicType($profileType);
1997 }
d43d0639 1998 $greeting = [
6a488035
TO
1999 'contact_type' => $profileType,
2000 'greeting_type' => $fieldName,
d43d0639
CW
2001 ];
2002 $form->add('select', $name, $title, ['' => ts('- select -')] + CRM_Core_PseudoConstant::greeting($greeting), $required);
6a488035 2003 // add custom greeting element
a6a0cdb7 2004 $form->add('text', $fieldName . '_custom', ts('Custom %1', [1 => ucwords(str_replace('_', ' ', $fieldName))]),
6a488035
TO
2005 NULL, FALSE
2006 );
2007 }
2008 elseif ($fieldName === 'preferred_communication_method') {
e7e657f0 2009 $communicationFields = CRM_Core_PseudoConstant::get('CRM_Contact_DAO_Contact', 'preferred_communication_method');
6a488035
TO
2010 foreach ($communicationFields as $key => $var) {
2011 if ($key == '') {
2012 continue;
2013 }
2014 $communicationOptions[] = $form->createElement('checkbox', $key, NULL, $var);
2015 }
2016 $form->addGroup($communicationOptions, $name, $title, '<br/>');
2017 }
2018 elseif ($fieldName === 'preferred_mail_format') {
2019 $form->add('select', $name, $title, CRM_Core_SelectValues::pmf());
2020 }
2021 elseif ($fieldName === 'preferred_language') {
a6a0cdb7 2022 $form->add('select', $name, $title, ['' => ts('- select -')] + CRM_Contact_BAO_Contact::buildOptions('preferred_language'));
6a488035
TO
2023 }
2024 elseif ($fieldName == 'external_identifier') {
2025 $form->add('text', $name, $title, $attributes, $required);
2026 $contID = $contactId;
2027 if (!$contID) {
2028 $contID = $form->get('id');
2029 }
2030 $form->addRule($name,
2031 ts('External ID already exists in Database.'),
2032 'objectExists',
a6a0cdb7 2033 ['CRM_Contact_DAO_Contact', $contID, 'external_identifier']
6a488035
TO
2034 );
2035 }
2036 elseif ($fieldName === 'group') {
2037 CRM_Contact_Form_Edit_TagsAndGroups::buildQuickForm($form, $contactId,
2038 CRM_Contact_Form_Edit_TagsAndGroups::GROUP,
2039 TRUE, $required,
2040 $title, NULL, $name
2041 );
2042 }
2043 elseif ($fieldName === 'tag') {
2044 CRM_Contact_Form_Edit_TagsAndGroups::buildQuickForm($form, $contactId,
2045 CRM_Contact_Form_Edit_TagsAndGroups::TAG,
2046 FALSE, $required,
2047 NULL, $title, $name
2048 );
2049 }
2050 elseif (substr($fieldName, 0, 4) === 'url-') {
eef9a6da
J
2051 $form->add('text', $name, $title, CRM_Core_DAO::getAttribute('CRM_Core_DAO_Website', 'url'), $required);
2052 $form->addRule($name, ts('Enter a valid web address beginning with \'http://\' or \'https://\'.'), 'url');
6a488035
TO
2053 }
2054 // Note should be rendered as textarea
2055 elseif (substr($fieldName, -4) == 'note') {
2056 $form->add('textarea', $name, $title, $attributes, $required);
2057 }
2058 elseif (substr($fieldName, 0, 6) === 'custom') {
2059 $customFieldID = CRM_Core_BAO_CustomField::getKeyID($fieldName);
2060 if ($customFieldID) {
3a7773be 2061 CRM_Core_BAO_CustomField::addQuickFormElement($form, $name, $customFieldID, $required, $search, $title);
6a488035
TO
2062 }
2063 }
2064 elseif (substr($fieldName, 0, 14) === 'address_custom') {
2065 list($fName, $locTypeId) = CRM_Utils_System::explode('-', $fieldName, 2);
2066 $customFieldID = CRM_Core_BAO_CustomField::getKeyID(substr($fName, 8));
2067 if ($customFieldID) {
3a7773be 2068 CRM_Core_BAO_CustomField::addQuickFormElement($form, $name, $customFieldID, $required, $search, $title);
6a488035
TO
2069 }
2070 }
6a488035
TO
2071 elseif ($fieldName == 'send_receipt') {
2072 $form->addElement('checkbox', $name, $title);
2073 }
2074 elseif ($fieldName == 'soft_credit') {
a6a0cdb7 2075 $form->addEntityRef("soft_credit_contact_id[$rowNumber]", ts('Soft Credit To'), ['create' => TRUE]);
5ee60152 2076 $form->addMoney("soft_credit_amount[{$rowNumber}]", ts('Amount'), FALSE, NULL, FALSE);
6a488035 2077 }
a6a0cdb7 2078 elseif ($fieldName === 'product_name') {
6a488035
TO
2079 list($products, $options) = CRM_Contribute_BAO_Premium::getPremiumProductInfo();
2080 $sel = &$form->addElement('hierselect', $name, $title);
a6a0cdb7 2081 $products = ['0' => ts('- select -')] + $products;
2082 $sel->setOptions([$products, $options]);
6a488035 2083 }
a6a0cdb7 2084 elseif ($fieldName === 'payment_instrument') {
6a488035 2085 $form->add('select', $name, $title,
a6a0cdb7 2086 ['' => ts('- select -')] + CRM_Contribute_PseudoConstant::paymentInstrument(), $required);
6a488035 2087 }
a6a0cdb7 2088 elseif ($fieldName === 'financial_type') {
6a488035 2089 $form->add('select', $name, $title,
a6a0cdb7 2090 [
21dfd5f5 2091 '' => ts('- select -'),
a6a0cdb7 2092 ] + CRM_Contribute_PseudoConstant::financialType(), $required
6a488035
TO
2093 );
2094 }
a6a0cdb7 2095 elseif ($fieldName === 'contribution_status_id') {
9805da76 2096 $contributionStatuses = CRM_Contribute_BAO_Contribution_Utils::getContributionStatuses();
6a73ef3f 2097
6a488035 2098 $form->add('select', $name, $title,
a6a0cdb7 2099 [
21dfd5f5 2100 '' => ts('- select -'),
a6a0cdb7 2101 ] + $contributionStatuses, $required
6a488035
TO
2102 );
2103 }
a6a0cdb7 2104 elseif ($fieldName === 'soft_credit_type') {
9e1854a1 2105 $name = "soft_credit_type[$rowNumber]";
51fa20cb 2106 $form->add('select', $name, $title,
a6a0cdb7 2107 [
21dfd5f5 2108 '' => ts('- select -'),
a6a0cdb7 2109 ] + CRM_Core_OptionGroup::values("soft_credit_type")
51fa20cb 2110 );
9e1854a1 2111 //CRM-15350: choose SCT field default value as 'Gift' for membership use
2112 //else (for contribution), use configured SCT default value
2113 $SCTDefaultValue = CRM_Core_OptionGroup::getDefaultValue("soft_credit_type");
2114 if ($field['field_type'] == 'Membership') {
233319bf 2115 $SCTDefaultValue = CRM_Core_PseudoConstant::getKey('CRM_Contribute_BAO_ContributionSoft', 'soft_credit_type_id', 'gift');
9e1854a1 2116 }
a6a0cdb7 2117 $form->addElement('hidden', 'sct_default_id', $SCTDefaultValue, ['id' => 'sct_default_id']);
51fa20cb 2118 }
a4a361c9 2119 elseif ($fieldName == 'contribution_soft_credit_pcp_id') {
03ad81ae 2120 CRM_Contribute_Form_SoftCredit::addPCPFields($form, "[$rowNumber]");
51fa20cb 2121 }
6a488035 2122 elseif ($fieldName == 'currency') {
483a53a8 2123 $form->addCurrency($name, $title, $required, NULL, FALSE, FALSE);
6a488035
TO
2124 }
2125 elseif ($fieldName == 'contribution_page_id') {
2126 $form->add('select', $name, $title,
a6a0cdb7 2127 [
21dfd5f5 2128 '' => ts('- select -'),
a6a0cdb7 2129 ] + CRM_Contribute_PseudoConstant::contributionPage(), $required, 'class="big"'
6a488035
TO
2130 );
2131 }
6a488035
TO
2132 elseif ($fieldName == 'activity_status_id') {
2133 $form->add('select', $name, $title,
a6a0cdb7 2134 [
21dfd5f5 2135 '' => ts('- select -'),
a6a0cdb7 2136 ] + CRM_Core_PseudoConstant::activityStatus(), $required
6a488035
TO
2137 );
2138 }
2139 elseif ($fieldName == 'activity_engagement_level') {
2140 $form->add('select', $name, $title,
a6a0cdb7 2141 [
21dfd5f5 2142 '' => ts('- select -'),
a6a0cdb7 2143 ] + CRM_Campaign_PseudoConstant::engagementLevel(), $required
6a488035
TO
2144 );
2145 }
6a488035
TO
2146 elseif ($fieldName == 'participant_status') {
2147 $cond = NULL;
2148 if ($online == TRUE) {
2149 $cond = 'visibility_id = 1';
2150 }
2151 $form->add('select', $name, $title,
a6a0cdb7 2152 [
21dfd5f5 2153 '' => ts('- select -'),
a6a0cdb7 2154 ] + CRM_Event_PseudoConstant::participantStatus(NULL, $cond, 'label'), $required
6a488035
TO
2155 );
2156 }
2157 elseif ($fieldName == 'participant_role') {
a7488080 2158 if (!empty($field['is_multiple'])) {
6a488035
TO
2159 $form->addCheckBox($name, $title, CRM_Event_PseudoConstant::participantRole(), NULL, NULL, NULL, NULL, '&nbsp', TRUE);
2160 }
2161 else {
2162 $form->add('select', $name, $title,
a6a0cdb7 2163 [
21dfd5f5 2164 '' => ts('- select -'),
a6a0cdb7 2165 ] + CRM_Event_PseudoConstant::participantRole(), $required
6a488035
TO
2166 );
2167 }
2168 }
2169 elseif ($fieldName == 'world_region') {
1f177c6b 2170 $form->add('select', $name, $title, CRM_Core_PseudoConstant::worldRegion(), $required, $selectAttributes);
6a488035
TO
2171 }
2172 elseif ($fieldName == 'signature_html') {
5d51a2f9 2173 $form->add('wysiwyg', $name, $title, CRM_Core_DAO::getAttribute('CRM_Core_DAO_Email', $fieldName));
6a488035
TO
2174 }
2175 elseif ($fieldName == 'signature_text') {
2176 $form->add('textarea', $name, $title, CRM_Core_DAO::getAttribute('CRM_Core_DAO_Email', $fieldName));
2177 }
2178 elseif (substr($fieldName, -11) == 'campaign_id') {
2179 if (CRM_Campaign_BAO_Campaign::isCampaignEnable()) {
2180 $campaigns = CRM_Campaign_BAO_Campaign::getCampaigns(CRM_Utils_Array::value($contactId,
2181 $form->_componentCampaigns
2182 ));
2183 $form->add('select', $name, $title,
a6a0cdb7 2184 [
21dfd5f5 2185 '' => ts('- select -'),
a6a0cdb7 2186 ] + $campaigns, $required, 'class="crm-select2 big"'
6a488035
TO
2187 );
2188 }
2189 }
2190 elseif ($fieldName == 'activity_details') {
a6a0cdb7 2191 $form->add('wysiwyg', $fieldName, $title, ['rows' => 4, 'cols' => 60], $required);
6a488035
TO
2192 }
2193 elseif ($fieldName == 'activity_duration') {
2194 $form->add('text', $name, $title, $attributes, $required);
2195 $form->addRule($name, ts('Please enter the duration as number of minutes (integers only).'), 'positiveInteger');
2196 }
888da08c
MW
2197 elseif ($fieldName == 'case_status') {
2198 $form->add('select', $name, $title,
a6a0cdb7 2199 [
888da08c 2200 '' => ts('- select -'),
a6a0cdb7 2201 ] + CRM_Case_BAO_Case::buildOptions('case_status_id', 'create'),
888da08c
MW
2202 $required
2203 );
2204 }
6a488035
TO
2205 else {
2206 if (substr($fieldName, 0, 3) === 'is_' or substr($fieldName, 0, 7) === 'do_not_') {
2207 $form->add('advcheckbox', $name, $title, $attributes, $required);
2208 }
2732685b 2209 elseif (CRM_Utils_Array::value('html_type', $field) === 'Select Date') {
2210 $extra = isset($field['datepicker']) ? $field['datepicker']['extra'] : CRM_Utils_Date::getDatePickerExtra($field);
2211 $attributes = isset($field['datepicker']) ? $field['datepicker']['attributes'] : CRM_Utils_Date::getDatePickerAttributes($field);
2212 $form->add('datepicker', $name, $title, $attributes, $required, $extra);
2213 }
6a488035
TO
2214 else {
2215 $form->add('text', $name, $title, $attributes, $required);
2216 }
2217 }
2218
2219 static $hiddenSubtype = FALSE;
2220 if (!$hiddenSubtype && CRM_Contact_BAO_ContactType::isaSubType($field['field_type'])) {
2221 // In registration mode params are submitted via POST and we don't have any clue
2222 // about profile-id or the profile-type (which could be a subtype)
2223 // To generalize the behavior and simplify the process,
2224 // lets always add the hidden
2225 //subtype value if there is any, and we won't have to
2226 // compute it while processing.
133e2c99 2227 if ($usedFor) {
2228 $form->addElement('hidden', $usedFor . '[contact_sub_type]', $field['field_type']);
6a488035
TO
2229 }
2230 else {
2231 $form->addElement('hidden', 'contact_sub_type_hidden', $field['field_type']);
2232 }
2233 $hiddenSubtype = TRUE;
2234 }
2235
2236 if (($view && $mode != CRM_Profile_Form::MODE_SEARCH) || $isShared) {
2237 $form->freeze($name);
2238 }
2239
2240 //add the rules
a6a0cdb7 2241 if (in_array($fieldName, [
5d6ac993
TO
2242 'non_deductible_amount',
2243 'total_amount',
2244 'fee_amount',
21dfd5f5 2245 'net_amount',
a6a0cdb7 2246 ])) {
6a488035
TO
2247 $form->addRule($name, ts('Please enter a valid amount.'), 'money');
2248 }
6a488035
TO
2249 if ($rule) {
2250 if (!($rule == 'email' && $mode == CRM_Profile_Form::MODE_SEARCH)) {
a6a0cdb7 2251 $form->addRule($name, ts('Please enter a valid %1', [1 => $title]), $rule);
6a488035
TO
2252 }
2253 }
2254 }
2255
2256 /**
fe482240 2257 * Set profile defaults.
6a488035 2258 *
6a0b768e
TO
2259 * @param int $contactId
2260 * Contact id.
2261 * @param array $fields
2262 * Associative array of fields.
2263 * @param array $defaults
2264 * Defaults array.
2265 * @param bool $singleProfile
b581842f 2266 * True for single profile else false(Update multiple items).
6a0b768e
TO
2267 * @param int $componentId
2268 * Id for specific components like contribute, event etc.
2269 * @param null $component
6a488035 2270 */
e7483cbe 2271 public static function setProfileDefaults(
f9f40af3
TO
2272 $contactId, &$fields, &$defaults,
2273 $singleProfile = TRUE, $componentId = NULL, $component = NULL
6a488035
TO
2274 ) {
2275 if (!$componentId) {
2276 //get the contact details
00bb741c 2277 $contactDetails = CRM_Contact_BAO_Contact::getHierContactDetails($contactId, $fields);
9c1bc317 2278 $details = $contactDetails[$contactId] ?? NULL;
a6a0cdb7 2279 $multipleFields = ['website' => 'url'];
6a488035
TO
2280
2281 //start of code to set the default values
2282 foreach ($fields as $name => $field) {
2283 // skip pseudo fields
2284 if (substr($name, 0, 9) == 'phone_ext') {
2285 continue;
2286 }
2287
b581842f 2288 //set the field name depending upon the profile mode(single/multiple)
6a488035
TO
2289 if ($singleProfile) {
2290 $fldName = $name;
2291 }
2292 else {
2293 $fldName = "field[$contactId][$name]";
2294 }
2295
2296 if ($name == 'group') {
2297 CRM_Contact_Form_Edit_TagsAndGroups::setDefaults($contactId, $defaults, CRM_Contact_Form_Edit_TagsAndGroups::GROUP, $fldName);
2298 }
2299 if ($name == 'tag') {
2300 CRM_Contact_Form_Edit_TagsAndGroups::setDefaults($contactId, $defaults, CRM_Contact_Form_Edit_TagsAndGroups::TAG, $fldName);
2301 }
2302
a7488080 2303 if (!empty($details[$name]) || isset($details[$name])) {
6a488035 2304 //to handle custom data (checkbox) to be written
58f00377 2305 // to handle birth/deceased date, greeting_type and few other fields
2732685b 2306 if (in_array($name, CRM_Contact_BAO_Contact::$_greetingTypes)) {
6a488035
TO
2307 $defaults[$fldName] = $details[$name . '_id'];
2308 $defaults[$name . '_custom'] = $details[$name . '_custom'];
2309 }
2310 elseif ($name == 'preferred_communication_method') {
d5a9068c
PN
2311 $v = $details[$name];
2312 if (!is_array($details[$name])) {
2313 $v = explode(CRM_Core_DAO::VALUE_SEPARATOR, $v);
2314 }
6a488035
TO
2315 foreach ($v as $item) {
2316 if ($item) {
2317 $defaults[$fldName . "[$item]"] = 1;
2318 }
2319 }
2320 }
8aefc657
RK
2321 elseif ($name == 'contact_sub_type') {
2322 $defaults[$fldName] = explode(CRM_Core_DAO::VALUE_SEPARATOR, trim($details[$name], CRM_Core_DAO::VALUE_SEPARATOR));
2323 }
6a488035
TO
2324 elseif ($name == 'world_region') {
2325 $defaults[$fldName] = $details['worldregion_id'];
2326 }
d4502c25
CW
2327 elseif (CRM_Core_BAO_CustomField::getKeyID($name)) {
2328 $defaults[$fldName] = self::formatCustomValue($field, $details[$name]);
6a488035
TO
2329 }
2330 else {
2331 $defaults[$fldName] = $details[$name];
2332 }
2333 }
2334 else {
a6a0cdb7 2335 $blocks = ['email', 'phone', 'im', 'openid'];
6a488035
TO
2336 list($fieldName, $locTypeId, $phoneTypeId) = CRM_Utils_System::explode('-', $name, 3);
2337 if (!in_array($fieldName, $multipleFields)) {
2338 if (is_array($details)) {
2339 foreach ($details as $key => $value) {
2340 // when we fixed CRM-5319 - get primary loc
2341 // type as per loc field and removed below code.
2342 $primaryLocationType = FALSE;
2343 if ($locTypeId == 'Primary') {
5d6ac993 2344 if (is_array($value) && array_key_exists($fieldName, $value)) {
6a488035 2345 $primaryLocationType = TRUE;
5d6ac993 2346 if (in_array($fieldName, $blocks)) {
6a488035
TO
2347 $locTypeId = CRM_Contact_BAO_Contact::getPrimaryLocationType($contactId, FALSE, $fieldName);
2348 }
5d6ac993 2349 else {
6a488035
TO
2350 $locTypeId = CRM_Contact_BAO_Contact::getPrimaryLocationType($contactId, FALSE, 'address');
2351 }
2352 }
2353 }
2354
2355 // fixed for CRM-665
2356 if (is_numeric($locTypeId)) {
2357 if ($primaryLocationType || $locTypeId == CRM_Utils_Array::value('location_type_id', $value)) {
a7488080 2358 if (!empty($value[$fieldName])) {
6a488035
TO
2359 //to handle stateprovince and country
2360 if ($fieldName == 'state_province') {
2361 $defaults[$fldName] = $value['state_province_id'];
2362 }
2363 elseif ($fieldName == 'county') {
2364 $defaults[$fldName] = $value['county_id'];
2365 }
2366 elseif ($fieldName == 'country') {
6a488035
TO
2367 if (!isset($value['country_id']) || !$value['country_id']) {
2368 $config = CRM_Core_Config::singleton();
2369 if ($config->defaultContactCountry) {
2370 $defaults[$fldName] = $config->defaultContactCountry;
2371 }
2372 }
b3071092
DL
2373 else {
2374 $defaults[$fldName] = $value['country_id'];
2375 }
6a488035
TO
2376 }
2377 elseif ($fieldName == 'phone') {
2378 if ($phoneTypeId) {
2379 if (isset($value['phone'][$phoneTypeId])) {
2380 $defaults[$fldName] = $value['phone'][$phoneTypeId];
2381 }
2382 if (isset($value['phone_ext'][$phoneTypeId])) {
2383 $defaults[str_replace('phone', 'phone_ext', $fldName)] = $value['phone_ext'][$phoneTypeId];
2384 }
2385 }
2386 else {
9c1bc317 2387 $phoneDefault = $value['phone'] ?? NULL;
6a488035
TO
2388 // CRM-9216
2389 if (!is_array($phoneDefault)) {
2390 $defaults[$fldName] = $phoneDefault;
2391 }
2392 }
2393 }
2394 elseif ($fieldName == 'email') {
2395 //adding the first email (currently we don't support multiple emails of same location type)
2396 $defaults[$fldName] = $value['email'];
2397 }
2398 elseif ($fieldName == 'im') {
2399 //adding the first im (currently we don't support multiple ims of same location type)
2400 $defaults[$fldName] = $value['im'];
2401 $defaults[$fldName . '-provider_id'] = $value['im_provider_id'];
2402 }
2403 else {
2404 $defaults[$fldName] = $value[$fieldName];
2405 }
2406 }
d4502c25
CW
2407 elseif (strpos($fieldName, 'address_custom') === 0 && !empty($value[substr($fieldName, 8)])) {
2408 $defaults[$fldName] = self::formatCustomValue($field, $value[substr($fieldName, 8)]);
6a488035
TO
2409 }
2410 }
2411 }
d4502c25
CW
2412 elseif (strpos($fieldName, 'address_custom') === 0 && !empty($value[substr($fieldName, 8)])) {
2413 $defaults[$fldName] = self::formatCustomValue($field, $value[substr($fieldName, 8)]);
2076c0d2 2414 }
6a488035
TO
2415 }
2416 }
2417 }
2418 else {
2419 if (is_array($details)) {
1fd63589
EM
2420 if ($fieldName === 'url'
2421 && !empty($details['website'])
5d6ac993
TO
2422 && !empty($details['website'][$locTypeId])
2423 ) {
9c1bc317 2424 $defaults[$fldName] = $details['website'][$locTypeId]['url'] ?? NULL;
6a488035
TO
2425 }
2426 }
2427 }
2428 }
2429 }
2430 }
2431
888da08c 2432 // Handling Contribution Part of the batch profile
6a488035
TO
2433 if (CRM_Core_Permission::access('CiviContribute') && $component == 'Contribute') {
2434 self::setComponentDefaults($fields, $componentId, $component, $defaults);
2435 }
2436
888da08c 2437 // Handling Event Participation Part of the batch profile
6a488035
TO
2438 if (CRM_Core_Permission::access('CiviEvent') && $component == 'Event') {
2439 self::setComponentDefaults($fields, $componentId, $component, $defaults);
2440 }
2441
888da08c 2442 // Handling membership Part of the batch profile
6a488035
TO
2443 if (CRM_Core_Permission::access('CiviMember') && $component == 'Membership') {
2444 self::setComponentDefaults($fields, $componentId, $component, $defaults);
2445 }
2446
888da08c 2447 // Handling Activity Part of the batch profile
6a488035
TO
2448 if ($component == 'Activity') {
2449 self::setComponentDefaults($fields, $componentId, $component, $defaults);
2450 }
888da08c
MW
2451
2452 // Handling Case Part of the batch profile
2453 if (CRM_Core_Permission::access('CiviCase') && $component == 'Case') {
2454 self::setComponentDefaults($fields, $componentId, $component, $defaults);
2455 }
6a488035
TO
2456 }
2457
2458 /**
100fef9d 2459 * Get profiles by type eg: pure Individual etc
6a488035 2460 *
6a0b768e
TO
2461 * @param array $types
2462 * Associative array of types eg: types('Individual').
2463 * @param bool $onlyPure
2464 * True if only pure profiles are required.
6a488035 2465 *
a6c01b45
CW
2466 * @return array
2467 * associative array of profiles
6a488035 2468 */
00be9182 2469 public static function getProfiles($types, $onlyPure = FALSE) {
a6a0cdb7 2470 $profiles = [];
ff4f7744 2471 $ufGroups = CRM_Core_PseudoConstant::get('CRM_Core_DAO_UFField', 'uf_group_id');
6a488035
TO
2472
2473 CRM_Utils_Hook::aclGroup(CRM_Core_Permission::ADMIN, NULL, 'civicrm_uf_group', $ufGroups, $ufGroups);
2474
2475 // Exclude Batch Data Entry profiles - CRM-10901
2476 $batchProfiles = CRM_Core_BAO_UFGroup::getBatchProfiles();
2477
2478 foreach ($ufGroups as $id => $title) {
2479 $ptype = CRM_Core_BAO_UFField::getProfileType($id, FALSE, $onlyPure);
2480 if (in_array($ptype, $types) && !array_key_exists($id, $batchProfiles)) {
2481 $profiles[$id] = $title;
2482 }
2483 }
2484 return $profiles;
2485 }
2486
2487 /**
100fef9d 2488 * Check whether a profile is valid combination of
6a488035
TO
2489 * required and/or optional profile types
2490 *
6a0b768e
TO
2491 * @param array $required
2492 * Array of types those are required.
2493 * @param array $optional
2494 * Array of types those are optional.
6a488035 2495 *
a6c01b45
CW
2496 * @return array
2497 * associative array of profiles
6a488035 2498 */
00be9182 2499 public static function getValidProfiles($required, $optional = NULL) {
6a488035 2500 if (!is_array($required) || empty($required)) {
e7483cbe 2501 return NULL;
6a488035
TO
2502 }
2503
a6a0cdb7 2504 $profiles = [];
ff4f7744 2505 $ufGroups = CRM_Core_PseudoConstant::get('CRM_Core_DAO_UFField', 'uf_group_id');
6a488035
TO
2506
2507 CRM_Utils_Hook::aclGroup(CRM_Core_Permission::ADMIN, NULL, 'civicrm_uf_group', $ufGroups, $ufGroups);
2508
2509 foreach ($ufGroups as $id => $title) {
2510 $type = CRM_Core_BAO_UFField::checkValidProfileType($id, $required, $optional);
2511 if ($type) {
2512 $profiles[$id] = $title;
2513 }
2514 }
2515
2516 return $profiles;
2517 }
2518
2519 /**
100fef9d 2520 * Check whether a profile is valid combination of
6a488035
TO
2521 * required profile fields
2522 *
6a0b768e
TO
2523 * @param array $ufId
2524 * Integer id of the profile.
2525 * @param array $required
2526 * Array of fields those are required in the profile.
6a488035 2527 *
a6c01b45
CW
2528 * @return array
2529 * associative array of profiles
6a488035 2530 */
00be9182 2531 public static function checkValidProfile($ufId, $required = NULL) {
6a488035
TO
2532 $validProfile = FALSE;
2533 if (!$ufId) {
2534 return $validProfile;
2535 }
2536
2537 if (!CRM_Core_DAO::getFieldValue('CRM_Core_DAO_UFGroup', $ufId, 'is_active')) {
2538 return $validProfile;
2539 }
2540
2541 $profileFields = self::getFields($ufId, FALSE, CRM_Core_Action::VIEW, NULL,
2542 NULL, FALSE, NULL, FALSE, NULL,
2543 CRM_Core_Permission::CREATE, NULL
2544 );
2545
a6a0cdb7 2546 $validProfile = [];
6a488035
TO
2547 if (!empty($profileFields)) {
2548 $fields = array_keys($profileFields);
2549 foreach ($fields as $val) {
2550 foreach ($required as $key => $field) {
2551 if (strpos($val, $field) === 0) {
2552 unset($required[$key]);
2553 }
2554 }
2555 }
2556
63d76404 2557 $validProfile = (empty($required));
6a488035
TO
2558 }
2559
2560 return $validProfile;
2561 }
2562
2563 /**
100fef9d 2564 * Get default value for Register.
6a488035 2565 *
72b3a70c
CW
2566 * @param array $fields
2567 * @param array $defaults
77b97be7 2568 *
72b3a70c 2569 * @return array
6a488035 2570 */
00be9182 2571 public static function setRegisterDefaults(&$fields, &$defaults) {
b525f1cc 2572 $config = CRM_Core_Config::singleton();
6a488035
TO
2573 foreach ($fields as $name => $field) {
2574 if (substr($name, 0, 8) == 'country-') {
b525f1cc 2575 if (!empty($config->defaultContactCountry)) {
6a488035
TO
2576 $defaults[$name] = $config->defaultContactCountry;
2577 }
2578 }
2579 elseif (substr($name, 0, 15) == 'state_province-') {
b525f1cc 2580 if (!empty($config->defaultContactStateProvince)) {
6a488035
TO
2581 $defaults[$name] = $config->defaultContactStateProvince;
2582 }
2583 }
2584 }
2585 return $defaults;
2586 }
2587
2588 /**
dc195289 2589 * make a copy of a profile, including
6a488035
TO
2590 * all the fields in the profile
2591 *
6a0b768e
TO
2592 * @param int $id
2593 * The profile id to copy.
6a488035 2594 *
8eedd10a 2595 * @return \CRM_Core_DAO
6a488035 2596 */
00be9182 2597 public static function copy($id) {
9739890f 2598 $maxId = CRM_Core_DAO::singleValueQuery("SELECT max(id) FROM civicrm_uf_group");
2599
a6a0cdb7 2600 $title = ts('[Copy id %1]', [1 => $maxId + 1]);
2601 $fieldsFix = [
2602 'suffix' => [
9739890f 2603 'title' => ' ' . $title,
2604 'name' => '__Copy_id_' . ($maxId + 1) . '_',
a6a0cdb7 2605 ],
2606 ];
9739890f 2607
3fec1adc 2608 $copy = CRM_Core_DAO::copyGeneric('CRM_Core_DAO_UFGroup',
a6a0cdb7 2609 ['id' => $id],
6a488035
TO
2610 NULL,
2611 $fieldsFix
2612 );
2613
2614 if ($pos = strrpos($copy->name, "_{$id}")) {
2615 $copy->name = substr_replace($copy->name, '', $pos);
2616 }
2617 $copy->name = CRM_Utils_String::munge($copy->name, '_', 56) . "_{$copy->id}";
2618 $copy->save();
2619
3fec1adc 2620 $copyUFJoin = CRM_Core_DAO::copyGeneric('CRM_Core_DAO_UFJoin',
a6a0cdb7 2621 ['uf_group_id' => $id],
2622 ['uf_group_id' => $copy->id],
6a488035
TO
2623 NULL,
2624 'entity_table'
2625 );
2626
3fec1adc 2627 $copyUFField = CRM_Core_DAO::copyGeneric('CRM_Core_BAO_UFField',
a6a0cdb7 2628 ['uf_group_id' => $id],
2629 ['uf_group_id' => $copy->id]
6a488035
TO
2630 );
2631
2632 $maxWeight = CRM_Utils_Weight::getMax('CRM_Core_DAO_UFJoin', NULL, 'weight');
2633
2634 //update the weight
2635 $query = "
2636UPDATE civicrm_uf_join
2637SET weight = %1
2638WHERE uf_group_id = %2
2639AND ( entity_id IS NULL OR entity_id <= 0 )
2640";
a6a0cdb7 2641 $p = [
2642 1 => [$maxWeight + 1, 'Integer'],
2643 2 => [$copy->id, 'Integer'],
2644 ];
6a488035
TO
2645 CRM_Core_DAO::executeQuery($query, $p);
2646 if ($copy->is_reserved) {
2647 $query = "UPDATE civicrm_uf_group SET is_reserved = 0 WHERE id = %1";
a6a0cdb7 2648 $params = [1 => [$copy->id, 'Integer']];
6a488035
TO
2649 CRM_Core_DAO::executeQuery($query, $params);
2650 }
2651 CRM_Utils_Hook::copy('UFGroup', $copy);
2652
2653 return $copy;
2654 }
2655
2656 /**
2657 * Process that send notification e-mails
2658 *
6a0b768e
TO
2659 * @param int $contactID
2660 * Contact id.
2661 * @param array $values
2662 * Associative array of name/value pair.
6a488035 2663 */
00be9182 2664 public static function commonSendMail($contactID, &$values) {
6a488035
TO
2665 if (!$contactID || !$values) {
2666 return;
2667
2668 }
2669 $template = CRM_Core_Smarty::singleton();
2670
2671 $displayName = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact',
2672 $contactID,
2673 'display_name'
2674 );
2675
2676 self::profileDisplay($values['id'], $values['values'], $template);
2677 $emailList = explode(',', $values['email']);
2678
2679 $contactLink = CRM_Utils_System::url('civicrm/contact/view',
2680 "reset=1&cid=$contactID",
5d6ac993 2681 TRUE, NULL, FALSE, FALSE, TRUE
6a488035
TO
2682 );
2683
2684 //get the default domain email address.
2685 list($domainEmailName, $domainEmailAddress) = CRM_Core_BAO_Domain::getNameAndEmail();
2686
2687 if (!$domainEmailAddress || $domainEmailAddress == 'info@EXAMPLE.ORG') {
2688 $fixUrl = CRM_Utils_System::url('civicrm/admin/domain', 'action=update&reset=1');
ac15829d 2689 CRM_Core_Error::statusBounce(ts('The site administrator needs to enter a valid \'FROM Email Address\' in <a href="%1">Administer CiviCRM &raquo; Communications &raquo; FROM Email Addresses</a>. The email address used may need to be a valid mail account with your email service provider.', [1 => $fixUrl]));
6a488035
TO
2690 }
2691
2692 foreach ($emailList as $emailTo) {
2693 // FIXME: take the below out of the foreach loop
c6327d7d 2694 CRM_Core_BAO_MessageTemplate::sendTemplate(
a6a0cdb7 2695 [
6a488035
TO
2696 'groupName' => 'msg_tpl_workflow_uf',
2697 'valueName' => 'uf_notify',
2698 'contactId' => $contactID,
a6a0cdb7 2699 'tplParams' => [
6a488035
TO
2700 'displayName' => $displayName,
2701 'currentDate' => date('r'),
2702 'contactLink' => $contactLink,
a6a0cdb7 2703 ],
6a488035
TO
2704 'from' => "$domainEmailName <$domainEmailAddress>",
2705 'toEmail' => $emailTo,
a6a0cdb7 2706 ]
6a488035
TO
2707 );
2708 }
2709 }
2710
2711 /**
2712 * Given a contact id and a group id, returns the field values from the db
2713 * for this group and notify email only if group's notify field is
2714 * set and field values are not empty
2715 *
6a0b768e
TO
2716 * @param int $gid
2717 * Group id.
2718 * @param int $cid
2719 * Contact id.
c490a46a 2720 * @param array $params
1fd63589
EM
2721 * @param bool $skipCheck
2722 *
6a488035 2723 * @return array
6a488035 2724 */
00be9182 2725 public function checkFieldsEmptyValues($gid, $cid, $params, $skipCheck = FALSE) {
6a488035
TO
2726 if ($gid) {
2727 if (CRM_Core_BAO_UFGroup::filterUFGroups($gid, $cid) || $skipCheck) {
a6a0cdb7 2728 $values = [];
6a488035
TO
2729 $fields = CRM_Core_BAO_UFGroup::getFields($gid, FALSE, CRM_Core_Action::VIEW);
2730 CRM_Core_BAO_UFGroup::getValues($cid, $fields, $values, FALSE, $params, TRUE);
2731
2732 $email = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_UFGroup', $gid, 'notify');
2733
2734 if (!empty($values) &&
2735 !empty($email)
2736 ) {
a6a0cdb7 2737 $val = [
6a488035
TO
2738 'id' => $gid,
2739 'values' => $values,
2740 'email' => $email,
a6a0cdb7 2741 ];
6a488035
TO
2742 return $val;
2743 }
2744 }
2745 }
2746 return NULL;
2747 }
2748
2749 /**
fe482240 2750 * Assign uf fields to template.
6a488035 2751 *
6a0b768e
TO
2752 * @param int $gid
2753 * Group id.
c490a46a
CW
2754 * @param array $values
2755 * @param CRM_Core_Smarty $template
6a488035 2756 */
518fa0ee 2757 public static function profileDisplay($gid, $values, $template) {
6a488035
TO
2758 $groupTitle = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_UFGroup', $gid, 'title');
2759 $template->assign('grouptitle', $groupTitle);
2760 if (count($values)) {
2761 $template->assign('values', $values);
2762 }
2763 }
2764
2765 /**
fe482240 2766 * Format fields for dupe Contact Matching.
6a488035 2767 *
6a0b768e 2768 * @param array $params
6a488035 2769 *
100fef9d 2770 * @param int $contactId
1fd63589 2771 *
a6c01b45 2772 * @return array
b44e3f84 2773 * associated formatted array
6a488035 2774 */
00be9182 2775 public static function formatFields($params, $contactId = NULL) {
6a488035
TO
2776 if ($contactId) {
2777 // get the primary location type id and email
2778 list($name, $primaryEmail, $primaryLocationType) = CRM_Contact_BAO_Contact_Location::getEmailDetails($contactId);
2779 }
2780 else {
2781 $defaultLocationType = CRM_Core_BAO_LocationType::getDefault();
2782 $primaryLocationType = $defaultLocationType->id;
2783 }
2784
a6a0cdb7 2785 $data = [];
2786 $locationType = [];
5d6ac993 2787 $count = 1;
6a488035
TO
2788 $primaryLocation = 0;
2789 foreach ($params as $key => $value) {
2790 list($fieldName, $locTypeId, $phoneTypeId) = explode('-', $key);
2791
2792 if ($locTypeId == 'Primary') {
2793 $locTypeId = $primaryLocationType;
2794 }
2795
2796 if (is_numeric($locTypeId)) {
2797 if (!in_array($locTypeId, $locationType)) {
2798 $locationType[$count] = $locTypeId;
2799 $count++;
2800 }
2801 $loc = CRM_Utils_Array::key($locTypeId, $locationType);
2802
2803 $data['location'][$loc]['location_type_id'] = $locTypeId;
2804
2805 // if we are getting in a new primary email, dont overwrite the new one
2806 if ($locTypeId == $primaryLocationType) {
a7488080 2807 if (!empty($params['email-' . $primaryLocationType])) {
6a488035
TO
2808 $data['location'][$loc]['email'][$loc]['email'] = $fields['email-' . $primaryLocationType];
2809 }
2810 elseif (isset($primaryEmail)) {
2811 $data['location'][$loc]['email'][$loc]['email'] = $primaryEmail;
2812 }
2813 $primaryLocation++;
2814 }
2815
2816 if ($loc == 1) {
2817 $data['location'][$loc]['is_primary'] = 1;
2818 }
2819 if ($fieldName == 'phone') {
2820 if ($phoneTypeId) {
2821 $data['location'][$loc]['phone'][$loc]['phone_type_id'] = $phoneTypeId;
2822 }
2823 else {
2824 $data['location'][$loc]['phone'][$loc]['phone_type_id'] = '';
2825 }
2826 $data['location'][$loc]['phone'][$loc]['phone'] = $value;
2827 }
2828 elseif ($fieldName == 'email') {
2829 $data['location'][$loc]['email'][$loc]['email'] = $value;
2830 }
2831 elseif ($fieldName == 'im') {
2832 $data['location'][$loc]['im'][$loc]['name'] = $value;
2833 }
2834 else {
2835 if ($fieldName === 'state_province') {
2836 $data['location'][$loc]['address']['state_province_id'] = $value;
2837 }
2838 elseif ($fieldName === 'country') {
2839 $data['location'][$loc]['address']['country_id'] = $value;
2840 }
2841 else {
2842 $data['location'][$loc]['address'][$fieldName] = $value;
2843 }
2844 }
2845 }
2846 else {
67744c4e 2847 // TODO: prefix, suffix and gender translation may no longer be necessary - check inputs
6a488035
TO
2848 if ($key === 'individual_suffix') {
2849 $data['suffix_id'] = $value;
2850 }
2851 elseif ($key === 'individual_prefix') {
2852 $data['prefix_id'] = $value;
2853 }
2854 elseif ($key === 'gender') {
2855 $data['gender_id'] = $value;
2856 }
2857 elseif (substr($key, 0, 6) === 'custom') {
2858 if ($customFieldID = CRM_Core_BAO_CustomField::getKeyID($key)) {
2859 //fix checkbox
2860 if ($customFields[$customFieldID]['html_type'] == 'CheckBox') {
2861 $value = implode(CRM_Core_DAO::VALUE_SEPARATOR, array_keys($value));
2862 }
2863 // fix the date field
2864 if ($customFields[$customFieldID]['data_type'] == 'Date') {
2865 $date = CRM_Utils_Date::format($value);
2866 if (!$date) {
2867 $date = '';
2868 }
2869 $value = $date;
2870 }
2871
a6a0cdb7 2872 $data['custom'][$customFieldID] = [
6a488035
TO
2873 'id' => $id,
2874 'value' => $value,
2875 'extends' => $customFields[$customFieldID]['extends'],
2876 'type' => $customFields[$customFieldID]['data_type'],
2877 'custom_field_id' => $customFieldID,
a6a0cdb7 2878 ];
6a488035
TO
2879 }
2880 }
2881 elseif ($key == 'edit') {
2882 continue;
2883 }
2884 else {
2885 $data[$key] = $value;
2886 }
2887 }
2888 }
2889
2890 if (!$primaryLocation) {
2891 $loc++;
2892 $data['location'][$loc]['email'][$loc]['email'] = $primaryEmail;
2893 }
2894
6a488035
TO
2895 return $data;
2896 }
2897
2898 /**
100fef9d 2899 * Calculate the profile type 'group_type' as per profile fields.
6a488035 2900 *
6a0b768e
TO
2901 * @param int $gId
2902 * Profile id.
1fd63589 2903 * @param bool $includeTypeValues
6a0b768e
TO
2904 * @param int $ignoreFieldId
2905 * Ignore particular profile field.
6a488035 2906 *
a6c01b45
CW
2907 * @return array
2908 * list of calculated group type
6a488035 2909 */
00be9182 2910 public static function calculateGroupType($gId, $includeTypeValues = FALSE, $ignoreFieldId = NULL) {
6a488035
TO
2911 //get the profile fields.
2912 $ufFields = self::getFields($gId, FALSE, NULL, NULL, NULL, TRUE, NULL, TRUE);
2913 return self::_calculateGroupType($ufFields, $includeTypeValues, $ignoreFieldId);
2914 }
2915
2916 /**
100fef9d 2917 * Calculate the profile type 'group_type' as per profile fields.
6a488035 2918 *
1fd63589
EM
2919 * @param $ufFields
2920 * @param bool $includeTypeValues
6a0b768e
TO
2921 * @param int $ignoreFieldId
2922 * Ignore perticular profile field.
6a488035 2923 *
a6c01b45
CW
2924 * @return array
2925 * list of calculated group type
6a488035 2926 */
00be9182 2927 public static function _calculateGroupType($ufFields, $includeTypeValues = FALSE, $ignoreFieldId = NULL) {
a6a0cdb7 2928 $groupType = $groupTypeValues = $customFieldIds = [];
6a488035
TO
2929 if (!empty($ufFields)) {
2930 foreach ($ufFields as $fieldName => $fieldValue) {
2931 //ignore field from group type when provided.
2932 //in case of update profile field.
2933 if ($ignoreFieldId && ($ignoreFieldId == $fieldValue['field_id'])) {
2934 continue;
2935 }
2936 if (!in_array($fieldValue['field_type'], $groupType)) {
2937 $groupType[$fieldValue['field_type']] = $fieldValue['field_type'];
2938 }
2939
2940 if ($includeTypeValues && ($fldId = CRM_Core_BAO_CustomField::getKeyID($fieldName))) {
2941 $customFieldIds[$fldId] = $fldId;
2942 }
2943 }
2944 }
2945
2946 if (!empty($customFieldIds)) {
2947 $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) . ')';
2948
2949 $customGroups = CRM_Core_DAO::executeQuery($query);
2950 while ($customGroups->fetch()) {
2951 if (!$customGroups->extends_entity_column_value) {
2952 continue;
2953 }
2954
2955 $groupTypeName = "{$customGroups->extends}Type";
2956 if ($customGroups->extends == 'Participant' && $customGroups->extends_entity_column_id) {
233319bf 2957 $groupTypeName = CRM_Core_PseudoConstant::getName('CRM_Core_DAO_CustomGroup', 'extends_entity_column_id', $customGroups->extends_entity_column_id);
6a488035
TO
2958 }
2959
2960 foreach (explode(CRM_Core_DAO::VALUE_SEPARATOR, $customGroups->extends_entity_column_value) as $val) {
2961 if ($val) {
2962 $groupTypeValues[$groupTypeName][$val] = $val;
2963 }
2964 }
2965 }
2966
2967 if (!empty($groupTypeValues)) {
2968 $groupType = array_merge($groupType, $groupTypeValues);
2969 }
2970 }
2971
2972 return $groupType;
2973 }
2974
2975 /**
2976 * Update the profile type 'group_type' as per profile fields including group types and group subtype values.
2977 * Build and store string like: group_type1,group_type2[VALUE_SEPERATOR]group_type1Type:1:2:3,group_type2Type:1:2
2978 *
2979 * FIELDS GROUP_TYPE
2980 * BirthDate + Email Individual,Contact
2981 * BirthDate + Subject Individual,Activity
2982 * BirthDate + Subject + SurveyOnlyField Individual,Activity\0ActivityType:28
2983 * BirthDate + Subject + SurveyOnlyField + PhoneOnlyField (Not allowed)
2984 * BirthDate + SurveyOnlyField Individual,Activity\0ActivityType:28
2985 * BirthDate + Subject + SurveyOrPhoneField Individual,Activity\0ActivityType:2:28
2986 * BirthDate + SurveyOrPhoneField Individual,Activity\0ActivityType:2:28
2987 * BirthDate + SurveyOrPhoneField + SurveyOnlyField Individual,Activity\0ActivityType:2:28
2988 * BirthDate + StudentField + Subject + SurveyOnlyField Individual,Activity,Student\0ActivityType:28
2989 *
c490a46a 2990 * @param int $gId
6a0b768e
TO
2991 * @param array $groupTypes
2992 * With key having group type names.
6a488035 2993 *
e7483cbe 2994 * @return bool
6a488035 2995 */
a6a0cdb7 2996 public static function updateGroupTypes($gId, $groupTypes = []) {
6a488035
TO
2997 if (!is_array($groupTypes) || !$gId) {
2998 return FALSE;
2999 }
3000
3001 // If empty group types set group_type as 'null'
3002 if (empty($groupTypes)) {
3003 return CRM_Core_DAO::setFieldValue('CRM_Core_DAO_UFGroup', $gId, 'group_type', 'null');
3004 }
3005
a6a0cdb7 3006 $componentGroupTypes = ['Contribution', 'Participant', 'Membership', 'Activity', 'Case'];
3007 $validGroupTypes = array_merge([
5d6ac993
TO
3008 'Contact',
3009 'Individual',
3010 'Organization',
21dfd5f5 3011 'Household',
a6a0cdb7 3012 ], $componentGroupTypes, CRM_Contact_BAO_ContactType::subTypes());
6a488035 3013
a6a0cdb7 3014 $gTypes = $gTypeValues = [];
6a488035 3015
a6a0cdb7 3016 $participantExtends = ['ParticipantRole', 'ParticipantEventName', 'ParticipantEventType'];
6a488035
TO
3017 // Get valid group type and group subtypes
3018 foreach ($groupTypes as $groupType => $value) {
3019 if (in_array($groupType, $validGroupTypes) && !in_array($groupType, $gTypes)) {
3020 $gTypes[] = $groupType;
3021 }
3022
3023 $subTypesOf = NULL;
3024
3025 if (in_array($groupType, $participantExtends)) {
3026 $subTypesOf = $groupType;
3027 }
3028 elseif (strpos($groupType, 'Type') > 0) {
3029 $subTypesOf = substr($groupType, 0, strpos($groupType, 'Type'));
3030 }
3031 else {
3032 continue;
3033 }
3034
3035 if (!empty($value) &&
3036 (in_array($subTypesOf, $componentGroupTypes) ||
3037 in_array($subTypesOf, $participantExtends)
3038 )
3039 ) {
3040 $gTypeValues[$subTypesOf] = $groupType . ":" . implode(':', $value);
3041 }
3042 }
3043
3044 if (empty($gTypes)) {
3045 return FALSE;
3046 }
3047
3048 // Build String to store group types and group subtypes
3049 $groupTypeString = implode(',', $gTypes);
3050 if (!empty($gTypeValues)) {
3051 $groupTypeString .= CRM_Core_DAO::VALUE_SEPARATOR . implode(',', $gTypeValues);
3052 }
3053
3054 return CRM_Core_DAO::setFieldValue('CRM_Core_DAO_UFGroup', $gId, 'group_type', $groupTypeString);
3055 }
3056
3057 /**
fe482240 3058 * Create a "group_type" string.
6a488035 3059 *
6a0b768e
TO
3060 * @param array $coreTypes
3061 * E.g. array('Individual','Contact','Student').
3062 * @param array $subTypes
3063 * E.g. array('ActivityType' => array(7, 11)).
6a488035 3064 * @param string $delim
1fd63589
EM
3065 *
3066 * @return string
6a488035
TO
3067 * @throws CRM_Core_Exception
3068 */
00be9182 3069 public static function encodeGroupType($coreTypes, $subTypes, $delim = CRM_Core_DAO::VALUE_SEPARATOR) {
6a488035
TO
3070 $groupTypeExpr = '';
3071 if ($coreTypes) {
3072 $groupTypeExpr .= implode(',', $coreTypes);
3073 }
3074 if ($subTypes) {
99e239bc 3075 //CRM-15427 Allow Multiple subtype filtering
3076 //if (count($subTypes) > 1) {
5d6ac993 3077 //throw new CRM_Core_Exception("Multiple subtype filtering is not currently supported by widget.");
99e239bc 3078 //}
6a488035
TO
3079 foreach ($subTypes as $subType => $subTypeIds) {
3080 $groupTypeExpr .= $delim . $subType . ':' . implode(':', $subTypeIds);
3081 }
3082 }
3083 return $groupTypeExpr;
3084 }
3085
3086 /**
dc195289 3087 * setDefault componet specific profile fields.
6a488035 3088 *
6a0b768e
TO
3089 * @param array $fields
3090 * Profile fields.
3091 * @param int $componentId
3092 * ComponetID.
3093 * @param string $component
3094 * Component name.
3095 * @param array $defaults
3096 * An array of default values.
1fd63589
EM
3097 *
3098 * @param bool $isStandalone
6a488035 3099 */
f0385140 3100 public static function setComponentDefaults(&$fields, $componentId, $component, &$defaults, $isStandalone = FALSE) {
6a488035 3101 if (!$componentId ||
a6a0cdb7 3102 !in_array($component, ['Contribute', 'Membership', 'Event', 'Activity', 'Case'])
6a488035
TO
3103 ) {
3104 return;
3105 }
3106
3107 $componentBAO = $componentSubType = NULL;
3108 switch ($component) {
3109 case 'Membership':
5d6ac993 3110 $componentBAO = 'CRM_Member_BAO_Membership';
6a488035 3111 $componentBAOName = 'Membership';
a6a0cdb7 3112 $componentSubType = ['membership_type_id'];
6a488035
TO
3113 break;
3114
3115 case 'Contribute':
5d6ac993 3116 $componentBAO = 'CRM_Contribute_BAO_Contribution';
6a488035 3117 $componentBAOName = 'Contribution';
a6a0cdb7 3118 $componentSubType = ['financial_type_id'];
6a488035
TO
3119 break;
3120
3121 case 'Event':
5d6ac993 3122 $componentBAO = 'CRM_Event_BAO_Participant';
6a488035 3123 $componentBAOName = 'Participant';
a6a0cdb7 3124 $componentSubType = ['role_id', 'event_id', 'event_type_id'];
6a488035
TO
3125 break;
3126
3127 case 'Activity':
5d6ac993 3128 $componentBAO = 'CRM_Activity_BAO_Activity';
6a488035 3129 $componentBAOName = 'Activity';
a6a0cdb7 3130 $componentSubType = ['activity_type_id'];
6a488035 3131 break;
888da08c
MW
3132
3133 case 'Case':
3134 $componentBAO = 'CRM_Case_BAO_Case';
3135 $componentBAOName = 'Case';
a6a0cdb7 3136 $componentSubType = ['case_type_id'];
888da08c 3137 break;
6a488035
TO
3138 }
3139
a6a0cdb7 3140 $values = [];
3141 $params = ['id' => $componentId];
6a488035
TO
3142
3143 //get the component values.
3144 CRM_Core_DAO::commonRetrieve($componentBAO, $params, $values);
d623de42 3145 if ($componentBAOName == 'Participant') {
a6a0cdb7 3146 $values += ['event_type_id' => CRM_Core_DAO::getFieldValue('CRM_Event_DAO_Event', $values['event_id'], 'event_type_id')];
d623de42 3147 }
6a488035 3148
a6a0cdb7 3149 $formattedGroupTree = [];
a86839e7 3150
6a488035
TO
3151 foreach ($fields as $name => $field) {
3152 $fldName = $isStandalone ? $name : "field[$componentId][$name]";
3d927ee7 3153 if (array_key_exists($name, $values)) {
6a488035
TO
3154 $defaults[$fldName] = $values[$name];
3155 }
3156 elseif ($name == 'participant_note') {
5d6ac993 3157 $noteDetails = CRM_Core_BAO_Note::getNote($componentId, 'civicrm_participant');
6a488035
TO
3158 $defaults[$fldName] = array_pop($noteDetails);
3159 }
a6a0cdb7 3160 elseif (in_array($name, [
5d6ac993
TO
3161 'financial_type',
3162 'payment_instrument',
3163 'participant_status',
21dfd5f5 3164 'participant_role',
a6a0cdb7 3165 ])) {
6a488035
TO
3166 $defaults[$fldName] = $values["{$name}_id"];
3167 }
3168 elseif ($name == 'membership_type') {
3169 // since membership_type field is a hierselect -
e7483cbe
J
3170 $defaults[$fldName][0]
3171 = CRM_Core_DAO::getFieldValue('CRM_Member_DAO_MembershipType', $values['membership_type_id'], 'member_of_contact_id', 'id');
6a488035
TO
3172 $defaults[$fldName][1] = $values['membership_type_id'];
3173 }
3174 elseif ($name == 'membership_status') {
3175 $defaults[$fldName] = $values['status_id'];
3176 }
888da08c
MW
3177 elseif ($name == 'case_status') {
3178 $defaults[$fldName] = $values['case_status_id'];
3179 }
a6a0cdb7 3180 elseif (CRM_Core_BAO_CustomField::getKeyID($name, TRUE) !== [NULL, NULL]) {
6a488035
TO
3181 if (empty($formattedGroupTree)) {
3182 //get the groupTree as per subTypes.
a6a0cdb7 3183 $groupTree = [];
6a488035 3184 foreach ($componentSubType as $subType) {
0b330e6d 3185 $subTree = CRM_Core_BAO_CustomGroup::getTree($componentBAOName, NULL,
6a488035
TO
3186 $componentId, 0, $values[$subType]
3187 );
3188 $groupTree = CRM_Utils_Array::crmArrayMerge($groupTree, $subTree);
3189 }
1273d77c 3190 $formattedGroupTree = CRM_Core_BAO_CustomGroup::formatGroupTree($groupTree, 1);
6a488035
TO
3191 CRM_Core_BAO_CustomGroup::setDefaults($formattedGroupTree, $defaults);
3192 }
3193
3194 //FIX ME: We need to loop defaults, but once we move to custom_1_x convention this code can be simplified.
3195 foreach ($defaults as $customKey => $customValue) {
3196 if ($customFieldDetails = CRM_Core_BAO_CustomField::getKeyID($customKey, TRUE)) {
3197 if ($name == 'custom_' . $customFieldDetails[0]) {
3198
3199 //hack to set default for checkbox
3200 //basically this is for weired field name like field[33][custom_19]
3201 //we are converting this field name to array structure and assign value.
3202 $skipValue = FALSE;
3203
3204 foreach ($formattedGroupTree as $tree) {
d623de42
M
3205 if (!empty($tree['fields'][$customFieldDetails[0]])) {
3206 if ('CheckBox' == CRM_Utils_Array::value('html_type', $tree['fields'][$customFieldDetails[0]])) {
3207 $skipValue = TRUE;
3208 $defaults['field'][$componentId][$name] = $customValue;
3209 break;
3210 }
3211 elseif (CRM_Utils_Array::value('data_type', $tree['fields'][$customFieldDetails[0]]) == 'Date') {
3212 $skipValue = TRUE;
6a488035 3213
d623de42
M
3214 // CRM-6681, $default contains formatted date, time values.
3215 $defaults[$fldName] = $customValue;
3216 if (!empty($defaults[$customKey . '_time'])) {
3217 $defaults['field'][$componentId][$name . '_time'] = $defaults[$customKey . '_time'];
3218 }
6a488035
TO
3219 }
3220 }
3221 }
3222
3223 if (!$skipValue || $isStandalone) {
3224 $defaults[$fldName] = $customValue;
3225 }
3226 unset($defaults[$customKey]);
3227 break;
3228 }
3229 }
3230 }
3231 }
04b40eab 3232 elseif (isset($values[$fldName])) {
3233 $defaults[$fldName] = $values[$fldName];
3234 }
6a488035
TO
3235 }
3236 }
3237
6a488035 3238 /**
fe482240 3239 * Retrieve groups of profiles.
6a488035 3240 *
6a0b768e
TO
3241 * @param int $profileID
3242 * Id of the profile.
6a488035 3243 *
a6c01b45
CW
3244 * @return array
3245 * returns array
6a488035 3246 */
00be9182 3247 public static function profileGroups($profileID) {
a6a0cdb7 3248 $groupTypes = [];
6a488035
TO
3249 $profileTypes = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_UFGroup', $profileID, 'group_type');
3250 if ($profileTypes) {
3251 $groupTypeParts = explode(CRM_Core_DAO::VALUE_SEPARATOR, $profileTypes);
3252 $groupTypes = explode(',', $groupTypeParts[0]);
3253 }
3254 return $groupTypes;
3255 }
3256
3257 /**
100fef9d 3258 * Alter contact params by filtering existing subscribed groups and returns
6a488035
TO
3259 * unsubscribed groups array for subscription.
3260 *
6a0b768e
TO
3261 * @param array $params
3262 * Contact params.
3263 * @param int $contactId
3264 * User contact id.
6a488035 3265 *
a6c01b45
CW
3266 * @return array
3267 * This contains array of groups for subscription
6a488035 3268 */
00be9182 3269 public static function getDoubleOptInGroupIds(&$params, $contactId = NULL) {
6a488035 3270 $config = CRM_Core_Config::singleton();
a6a0cdb7 3271 $subscribeGroupIds = [];
6a488035
TO
3272
3273 // process further only if profileDoubleOptIn enabled and if groups exist
3274 if (!array_key_exists('group', $params) ||
3275 !self::isProfileDoubleOptin() ||
3276 CRM_Utils_System::isNull($params['group'])
3277 ) {
3278 return $subscribeGroupIds;
3279 }
3280
3281 //check if contact email exist.
3282 $hasEmails = FALSE;
3283 foreach ($params as $name => $value) {
3284 if (strpos($name, 'email-') !== FALSE) {
3285 $hasEmails = TRUE;
3286 break;
3287 }
3288 }
3289
3290 //Proceed furthur only if email present
3291 if (!$hasEmails) {
3292 return $subscribeGroupIds;
3293 }
3294
3295 //do check for already subscriptions.
a6a0cdb7 3296 $contactGroups = [];
6a488035
TO
3297 if ($contactId) {
3298 $query = "
3299SELECT group_id
3300 FROM civicrm_group_contact
3301 WHERE status = 'Added'
3302 AND contact_id = %1";
3303
a6a0cdb7 3304 $dao = CRM_Core_DAO::executeQuery($query, [1 => [$contactId, 'Integer']]);
6a488035
TO
3305 while ($dao->fetch()) {
3306 $contactGroups[$dao->group_id] = $dao->group_id;
3307 }
3308 }
3309
3310 //since we don't have names, compare w/ label.
3311 $mailingListGroupType = array_search('Mailing List', CRM_Core_OptionGroup::values('group_type'));
3312
3313 //actual processing start.
3314 foreach ($params['group'] as $groupId => $isSelected) {
3315 //unset group those are not selected.
3316 if (!$isSelected) {
3317 unset($params['group'][$groupId]);
3318 continue;
3319 }
3320
3321 $groupTypes = explode(CRM_Core_DAO::VALUE_SEPARATOR,
3322 CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Group', $groupId, 'group_type', 'id')
3323 );
3324 //get only mailing type group and unset it from params
3325 if (in_array($mailingListGroupType, $groupTypes) && !in_array($groupId, $contactGroups)) {
3326 $subscribeGroupIds[$groupId] = $groupId;
3327 unset($params['group'][$groupId]);
3328 }
3329 }
3330
3331 return $subscribeGroupIds;
3332 }
3333
3334 /**
fe482240 3335 * Check if we are rendering mixed profiles.
6a488035 3336 *
6a0b768e
TO
3337 * @param array $profileIds
3338 * Associated array of profile ids.
6a488035 3339 *
e7483cbe 3340 * @return bool
a6c01b45 3341 * true if profile is mixed
6a488035 3342 */
00be9182 3343 public static function checkForMixProfiles($profileIds) {
6a488035
TO
3344 $mixProfile = FALSE;
3345
a6a0cdb7 3346 $contactTypes = ['Individual', 'Household', 'Organization'];
6a488035
TO
3347 $subTypes = CRM_Contact_BAO_ContactType::subTypes();
3348
a6a0cdb7 3349 $components = ['Contribution', 'Participant', 'Membership', 'Activity'];
6a488035 3350
a6a0cdb7 3351 $typeCount = ['ctype' => [], 'subtype' => []];
6a488035
TO
3352 foreach ($profileIds as $gid) {
3353 $profileType = CRM_Core_BAO_UFField::getProfileType($gid);
3354 // ignore profile of type Contact
3355 if ($profileType == 'Contact') {
3356 continue;
3357 }
3358 if (in_array($profileType, $contactTypes)) {
3359 if (!isset($typeCount['ctype'][$profileType])) {
3360 $typeCount['ctype'][$profileType] = 1;
3361 }
3362
3363 // check if we are rendering profile of different contact types
3364 if (count($typeCount['ctype']) == 2) {
3365 $mixProfile = TRUE;
3366 break;
3367 }
3368 }
3369 elseif (in_array($profileType, $components)) {
3370 $mixProfile = TRUE;
3371 break;
3372 }
3373 else {
3374 if (!isset($typeCount['subtype'][$profileType])) {
3375 $typeCount['subtype'][$profileType] = 1;
3376 }
3377 // check if we are rendering profile of different contact sub types
3378 if (count($typeCount['subtype']) == 2) {
3379 $mixProfile = TRUE;
3380 break;
3381 }
3382 }
3383 }
3384 return $mixProfile;
3385 }
3386
3387 /**
fe482240 3388 * Determine of we show overlay profile or not.
6a488035 3389 *
e7483cbe 3390 * @return bool
a6c01b45 3391 * true if profile should be shown else false
6a488035 3392 */
00be9182 3393 public static function showOverlayProfile() {
6a488035
TO
3394 $showOverlay = TRUE;
3395
3396 // get the id of overlay profile
3397 $overlayProfileId = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_UFGroup', 'summary_overlay', 'id', 'name');
3398 $query = "SELECT count(id) FROM civicrm_uf_field WHERE uf_group_id = {$overlayProfileId} AND visibility IN ('Public Pages', 'Public Pages and Listings') ";
3399
3400 $count = CRM_Core_DAO::singleValueQuery($query);
3401
3402 //check if there are no public fields and use is anonymous
3403 $session = CRM_Core_Session::singleton();
3404 if (!$count && !$session->get('userID')) {
3405 $showOverlay = FALSE;
3406 }
3407
3408 return $showOverlay;
3409 }
3410
3411 /**
fe482240 3412 * Get group type values of the profile.
6a488035 3413 *
c490a46a
CW
3414 * @param int $profileId
3415 * @param string $groupType
1fd63589 3416 *
e7483cbe 3417 * @return array
a6c01b45 3418 * group type values
6a488035 3419 */
00be9182 3420 public static function groupTypeValues($profileId, $groupType = NULL) {
a6a0cdb7 3421 $groupTypeValue = [];
6a488035
TO
3422 $groupTypes = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_UFGroup', $profileId, 'group_type');
3423
3424 $groupTypeParts = explode(CRM_Core_DAO::VALUE_SEPARATOR, $groupTypes);
a7488080 3425 if (empty($groupTypeParts[1])) {
6a488035
TO
3426 return $groupTypeValue;
3427 }
a6a0cdb7 3428 $participantExtends = ['ParticipantRole', 'ParticipantEventName', 'ParticipantEventType'];
6a488035
TO
3429
3430 foreach (explode(',', $groupTypeParts[1]) as $groupTypeValues) {
a6a0cdb7 3431 $values = [];
6a488035
TO
3432 $valueParts = explode(':', $groupTypeValues);
3433 if ($groupType &&
3434 ($valueParts[0] != "{$groupType}Type" ||
3435 ($groupType == 'Participant' &&
3436 !in_array($valueParts[0], $participantExtends)
3437 )
3438 )
3439 ) {
3440 continue;
3441 }
3442 foreach ($valueParts as $val) {
3443 if (CRM_Utils_Rule::integer($val)) {
3444 $values[$val] = $val;
3445 }
3446 }
3447 if (!empty($values)) {
3448 $typeName = substr($valueParts[0], 0, -4);
3449 if (in_array($valueParts[0], $participantExtends)) {
3450 $typeName = $valueParts[0];
3451 }
3452 $groupTypeValue[$typeName] = $values;
3453 }
3454 }
3455
3456 return $groupTypeValue;
3457 }
3458
b5c2afd0
EM
3459 /**
3460 * @return bool|object
3461 */
00be9182 3462 public static function isProfileDoubleOptin() {
6a488035
TO
3463 // check for double optin
3464 $config = CRM_Core_Config::singleton();
3465 if (in_array('CiviMail', $config->enableComponents)) {
aaffa79f 3466 return Civi::settings()->get('profile_double_optin');
6a488035
TO
3467 }
3468 return FALSE;
3469 }
3470
b5c2afd0
EM
3471 /**
3472 * @return bool|object
3473 */
00be9182 3474 public static function isProfileAddToGroupDoubleOptin() {
6a488035
TO
3475 // check for add to group double optin
3476 $config = CRM_Core_Config::singleton();
3477 if (in_array('CiviMail', $config->enableComponents)) {
aaffa79f 3478 return Civi::settings()->get('profile_add_to_group_double_optin');
6a488035
TO
3479 }
3480 return FALSE;
3481 }
3482
3483 /**
fe482240 3484 * Get profiles used for batch entry.
6a488035 3485 *
a6c01b45
CW
3486 * @return array
3487 * profileIds profile ids
6a488035 3488 */
00be9182 3489 public static function getBatchProfiles() {
6a488035
TO
3490 $query = "SELECT id
3491 FROM civicrm_uf_group
3492 WHERE name IN ('contribution_batch_entry', 'membership_batch_entry')";
5d6ac993 3493 $dao = CRM_Core_DAO::executeQuery($query);
a6a0cdb7 3494 $profileIds = [];
5d6ac993 3495 while ($dao->fetch()) {
6a488035
TO
3496 $profileIds[$dao->id] = $dao->id;
3497 }
3498 return $profileIds;
3499 }
3500
1fd63589 3501 /**
1fd63589
EM
3502 * @param $source
3503 * @param $destination
3504 * @param bool $returnMultiSummaryFields
3505 *
3506 * @return array|null
a6a0cdb7 3507 * @todo what do I do?
1fd63589 3508 */
00be9182 3509 public static function shiftMultiRecordFields(&$source, &$destination, $returnMultiSummaryFields = FALSE) {
a6a0cdb7 3510 $multiSummaryFields = $returnMultiSummaryFields ? [] : NULL;
6a488035
TO
3511 foreach ($source as $field => $properties) {
3512 if (!CRM_Core_BAO_CustomField::getKeyID($field)) {
3513 continue;
3514 }
3515 if (CRM_Core_BAO_CustomField::isMultiRecordField($field)) {
3516 $destination[$field] = $properties;
3517 if ($returnMultiSummaryFields) {
3518 if ($properties['is_multi_summary']) {
3519 $multiSummaryFields[$field] = $properties;
3520 }
3521 }
3522 unset($source[$field]);
3523 }
3524 }
3525 return $multiSummaryFields;
3526 }
3527
3528 /**
fe482240 3529 * This is function is used to format pseudo fields.
6a488035 3530 *
6a0b768e
TO
3531 * @param array $fields
3532 * Associated array of profile fields.
6a488035 3533 *
6a488035 3534 */
00be9182 3535 public static function reformatProfileFields(&$fields) {
6a488035
TO
3536 //reformat fields array
3537 foreach ($fields as $name => $field) {
3538 //reformat phone and extension field
5d6ac993 3539 if (substr($field['name'], 0, 13) == 'phone_and_ext') {
6a488035
TO
3540 $fieldSuffix = str_replace('phone_and_ext-', '', $field['name']);
3541
3542 // retain existing element properties and just update and replace key
3543 CRM_Utils_Array::crmReplaceKey($fields, $name, "phone-{$fieldSuffix}");
3544 $fields["phone-{$fieldSuffix}"]['name'] = "phone-{$fieldSuffix}";
3545 $fields["phone-{$fieldSuffix}"]['where'] = 'civicrm_phone.phone';
3546
3547 // add additional phone extension field
3548 $fields["phone_ext-{$fieldSuffix}"] = $field;
5d6ac993 3549 $fields["phone_ext-{$fieldSuffix}"]['title'] = $field['title'] . ' - ' . ts('Ext.');
6a488035
TO
3550 $fields["phone_ext-{$fieldSuffix}"]['name'] = "phone_ext-{$fieldSuffix}";
3551 $fields["phone_ext-{$fieldSuffix}"]['where'] = 'civicrm_phone.phone_ext';
3552 $fields["phone_ext-{$fieldSuffix}"]['skipDisplay'] = 1;
3553 //ignore required for extension field
3554 $fields["phone_ext-{$fieldSuffix}"]['is_required'] = 0;
3555 }
3556 }
3557 }
96025800 3558
ed7e2e99 3559 /**
3560 * Get the frontend_title for the profile, falling back on 'title' if none.
3561 *
3562 * @param int $profileID
3563 *
3564 * @return string
3565 *
3566 * @throws \CiviCRM_API3_Exception
3567 */
3568 public static function getFrontEndTitle(int $profileID) {
3569 $profile = civicrm_api3('UFGroup', 'getsingle', ['id' => $profileID, 'return' => ['title', 'frontend_title']]);
3570 return $profile['frontend_title'] ?? $profile['title'];
3571 }
3572
cd48635d 3573 /**
d4502c25 3574 * Format custom field value for use in prepopulating a quickform profile field.
cd48635d
VP
3575 *
3576 * @param array $field
d4502c25 3577 * Field metadata.
cd48635d 3578 * @param string $value
d4502c25 3579 * Raw value
cd48635d 3580 *
d4502c25 3581 * @return mixed
cd48635d
VP
3582 * String or array, depending on the html type
3583 */
d4502c25
CW
3584 private static function formatCustomValue($field, $value) {
3585 if (CRM_Core_BAO_CustomField::isSerialized($field)) {
3586 $value = CRM_Utils_Array::explodePadded($value);
cd48635d 3587
d4502c25
CW
3588 if ($field['html_type'] === 'CheckBox') {
3589 $checkboxes = [];
3590 foreach (array_filter($value) as $item) {
3591 $checkboxes[$item] = 1;
3592 // CRM-2969 seems like we need this for QF style checkboxes in profile where its multiindexed
3593 $checkboxes["[{$item}]"] = 1;
cd48635d 3594 }
d4502c25
CW
3595 return $checkboxes;
3596 }
cd48635d 3597 }
d4502c25 3598 return $value;
cd48635d
VP
3599 }
3600
6a488035 3601}