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