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