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