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