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