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