PR#12083 - Correct typing of "Payflow Pro" in various messages.
[civicrm-core.git] / CRM / Core / BAO / UFGroup.php
1 <?php
2 /*
3 +--------------------------------------------------------------------+
4 | CiviCRM version 5 |
5 +--------------------------------------------------------------------+
6 | Copyright CiviCRM LLC (c) 2004-2018 |
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-2018
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 Object
120 * CRM_Core_DAO_UFGroup object on success, null otherwise
121 */
122 public static function setIsActive($id, $is_active) {
123 return CRM_Core_DAO::setFieldValue('CRM_Core_DAO_UFGroup', $id, 'is_active', $is_active);
124 }
125
126 /**
127 * Get all the registration fields.
128 *
129 * @param int $action
130 * What action are we doing.
131 * @param int $mode
132 * Mode.
133 *
134 * @param null $ctype
135 *
136 * @return array
137 * the fields that are needed for registration
138 */
139 public static function getRegistrationFields($action, $mode, $ctype = NULL) {
140 if ($mode & CRM_Profile_Form::MODE_REGISTER) {
141 $ufGroups = CRM_Core_BAO_UFGroup::getModuleUFGroup('User Registration');
142 }
143 else {
144 $ufGroups = CRM_Core_BAO_UFGroup::getModuleUFGroup('Profile');
145 }
146
147 if (!is_array($ufGroups)) {
148 return FALSE;
149 }
150
151 $fields = array();
152
153 foreach ($ufGroups as $id => $title) {
154 if ($ctype) {
155 $fieldType = CRM_Core_BAO_UFField::getProfileType($id);
156 if (($fieldType != 'Contact') &&
157 ($fieldType != $ctype) &&
158 !CRM_Contact_BAO_ContactType::isExtendsContactType($fieldType, $ctype)
159 ) {
160 continue;
161 }
162 if (CRM_Contact_BAO_ContactType::isaSubType($fieldType)) {
163 $profileSubType = $fieldType;
164 }
165 }
166
167 $subset = self::getFields($id, TRUE, $action,
168 NULL, NULL, FALSE, NULL, TRUE, $ctype
169 );
170
171 // we do not allow duplicates. the first field is the winner
172 foreach ($subset as $name => $field) {
173 if (empty($fields[$name])) {
174 $fields[$name] = $field;
175 }
176 }
177 }
178
179 return $fields;
180 }
181
182 /**
183 * Get all the listing fields.
184 *
185 * @param int $action
186 * What action are we doing.
187 * @param int $visibility
188 * Visibility of fields we are interested in.
189 * @param bool $considerSelector
190 * Whether to consider the in_selector parameter.
191 * @param array $ufGroupIds
192 * @param bool $searchable
193 *
194 * @param null $restrict
195 * @param bool $skipPermission
196 * @param int $permissionType
197 * @return array
198 * the fields that are listings related
199 */
200 public static function getListingFields(
201 $action,
202 $visibility,
203 $considerSelector = FALSE,
204 $ufGroupIds = NULL,
205 $searchable = NULL,
206 $restrict = NULL,
207 $skipPermission = FALSE,
208 $permissionType = CRM_Core_Permission::SEARCH
209 ) {
210 if ($ufGroupIds) {
211 $subset = self::getFields($ufGroupIds, FALSE, $action,
212 $visibility, $searchable,
213 FALSE, $restrict,
214 $skipPermission,
215 NULL,
216 $permissionType
217 );
218 if ($considerSelector) {
219 // drop the fields not meant for the selector
220 foreach ($subset as $name => $field) {
221 if (!$field['in_selector']) {
222 unset($subset[$name]);
223 }
224 }
225 }
226 $fields = $subset;
227 }
228 else {
229 $ufGroups = CRM_Core_PseudoConstant::get('CRM_Core_DAO_UFField', 'uf_group_id');
230
231 $fields = array();
232 foreach ($ufGroups as $id => $title) {
233 $subset = self::getFields($id, FALSE, $action,
234 $visibility, $searchable,
235 FALSE, $restrict,
236 $skipPermission,
237 NULL,
238 $permissionType
239 );
240 if ($considerSelector) {
241 // drop the fields not meant for the selector
242 foreach ($subset as $name => $field) {
243 if (!$field['in_selector']) {
244 unset($subset[$name]);
245 }
246 }
247 }
248 $fields = array_merge($fields, $subset);
249 }
250 }
251 return $fields;
252 }
253
254 /**
255 * Get all the fields that belong to the group with the name title,
256 * and format for use with buildProfile. This is the SQL analog of
257 * formatUFFields().
258 *
259 * @param mix $id
260 * The id of the UF group or ids of ufgroup.
261 * @param bool|int $register are we interested in registration fields
262 * @param int $action
263 * What action are we doing.
264 * @param int $visibility
265 * Visibility of fields we are interested in.
266 * @param $searchable
267 * @param bool $showAll
268 * @param string $restrict
269 * Should we restrict based on a specified profile type.
270 * @param bool $skipPermission
271 * @param null $ctype
272 * @param int $permissionType
273 * @param string $orderBy
274 * @param null $orderProfiles
275 *
276 * @param bool $eventProfile
277 *
278 * @return array
279 * The fields that belong to this ufgroup(s)
280 * @throws \Exception
281 */
282 public static function getFields(
283 $id,
284 $register = FALSE,
285 $action = NULL,
286 $visibility = NULL,
287 $searchable = NULL,
288 $showAll = FALSE,
289 $restrict = NULL,
290 $skipPermission = FALSE,
291 $ctype = NULL,
292 $permissionType = CRM_Core_Permission::CREATE,
293 $orderBy = 'field_name',
294 $orderProfiles = NULL,
295 $eventProfile = FALSE
296 ) {
297 if (!is_array($id)) {
298 $id = CRM_Utils_Type::escape($id, 'Positive');
299 $profileIds = array($id);
300 }
301 else {
302 $profileIds = $id;
303 }
304
305 $gids = implode(',', $profileIds);
306 $params = array();
307 if ($restrict) {
308 $query = "SELECT g.* from civicrm_uf_group g
309 LEFT JOIN civicrm_uf_join j ON (j.uf_group_id = g.id)
310 WHERE g.id IN ( {$gids} )
311 AND ((j.uf_group_id IN ( {$gids} ) AND j.module = %1) OR g.is_reserved = 1 )
312 ";
313 $params = array(1 => array($restrict, 'String'));
314 }
315 else {
316 $query = "SELECT g.* from civicrm_uf_group g WHERE g.id IN ( {$gids} ) ";
317 }
318
319 if (!$showAll) {
320 $query .= " AND g.is_active = 1";
321 }
322
323 $checkPermission = array(
324 array(
325 'administer CiviCRM',
326 'manage event profiles',
327 ),
328 );
329 if ($eventProfile && CRM_Core_Permission::check($checkPermission)) {
330 $skipPermission = TRUE;
331 }
332
333 // add permissioning for profiles only if not registration
334 if (!$skipPermission) {
335 $permissionClause = CRM_Core_Permission::ufGroupClause($permissionType, 'g.');
336 $query .= " AND $permissionClause ";
337 }
338
339 if ($orderProfiles AND count($profileIds) > 1) {
340 $query .= " ORDER BY FIELD( g.id, {$gids} )";
341 }
342 $group = CRM_Core_DAO::executeQuery($query, $params);
343 $fields = array();
344 $validGroup = FALSE;
345
346 while ($group->fetch()) {
347 $validGroup = TRUE;
348 $query = self::createUFFieldQuery($group->id, $searchable, $showAll, $visibility, $orderBy);
349 $field = CRM_Core_DAO::executeQuery($query);
350
351 $importableFields = self::getProfileFieldMetadata($showAll);
352 list($customFields, $addressCustomFields) = self::getCustomFields($ctype);
353
354 while ($field->fetch()) {
355 list($name, $formattedField) = self::formatUFField($group, $field, $customFields, $addressCustomFields, $importableFields, $permissionType);
356 if ($formattedField !== NULL) {
357 $fields[$name] = $formattedField;
358 }
359 }
360 $field->free();
361 }
362
363 if (empty($fields) && !$validGroup) {
364 CRM_Core_Error::fatal(ts('The requested Profile (gid=%1) is disabled OR it is not configured to be used for \'Profile\' listings in its Settings OR there is no Profile with that ID OR you do not have permission to access this profile. Please contact the site administrator if you need assistance.',
365 array(1 => implode(',', $profileIds))
366 ));
367 }
368 else {
369 self::reformatProfileFields($fields);
370 }
371
372 return $fields;
373 }
374
375 /**
376 * Format a list of UFFields for use with buildProfile. This is the in-memory analog
377 * of getFields().
378 *
379 * @param array $groupArr
380 * (mimic CRM_UF_DAO_UFGroup).
381 * @param array $fieldArrs
382 * List of fields (each mimics CRM_UF_DAO_UFField).
383 * @param bool $visibility
384 * Visibility of fields we are interested in.
385 * @param bool $searchable
386 * @param bool $showAll
387 * @param null $ctype
388 * @param int $permissionType
389 *
390 * @return array
391 * @see self::getFields
392 */
393 public static function formatUFFields(
394 $groupArr,
395 $fieldArrs,
396 $visibility = NULL,
397 $searchable = NULL,
398 $showAll = FALSE,
399 $ctype = NULL,
400 $permissionType = CRM_Core_Permission::CREATE
401 ) {
402 // $group = new CRM_Core_DAO_UFGroup();
403 // $group->copyValues($groupArr); // no... converts string('') to string('null')
404 $group = (object) $groupArr;
405
406 // Refactoring note: The $fieldArrs here may be slightly different than the $ufFields
407 // used by calculateGroupType, but I don't think the missing fields matter, and -- if
408 // they did -- the obvious fix would produce mutual recursion.
409 $ufGroupType = self::_calculateGroupType($fieldArrs);
410 $profileType = CRM_Core_BAO_UFField::calculateProfileType(implode(',', $ufGroupType));
411 $contactActivityProfile = CRM_Core_BAO_UFField::checkContactActivityProfileTypeByGroupType(implode(',', $ufGroupType));
412 $importableFields = self::getImportableFields($showAll, $profileType, $contactActivityProfile);
413 list($customFields, $addressCustomFields) = self::getCustomFields($ctype);
414
415 $formattedFields = array();
416 foreach ($fieldArrs as $fieldArr) {
417 $field = (object) $fieldArr;
418 if (!self::filterUFField($field, $searchable, $showAll, $visibility)) {
419 continue;
420 }
421
422 list($name, $formattedField) = self::formatUFField($group, $field, $customFields, $addressCustomFields, $importableFields, $permissionType);
423 if ($formattedField !== NULL) {
424 $formattedFields[$name] = $formattedField;
425 }
426 }
427 return $formattedFields;
428 }
429
430 /**
431 * Prepare a field for rendering with CRM_Core_BAO_UFGroup::buildProfile.
432 *
433 * @param CRM_Core_DAO_UFGroup|CRM_Core_DAO $group
434 * @param CRM_Core_DAO_UFField|CRM_Core_DAO $field
435 * @param array $customFields
436 * @param array $addressCustomFields
437 * @param array $importableFields
438 * @param int $permissionType
439 * Eg CRM_Core_Permission::CREATE.
440 * @return array
441 */
442 protected static function formatUFField(
443 $group,
444 $field,
445 $customFields,
446 $addressCustomFields,
447 $importableFields,
448 $permissionType = CRM_Core_Permission::CREATE
449 ) {
450 $name = $field->field_name;
451 $title = $field->label;
452
453 $addressCustom = FALSE;
454 if (in_array($permissionType, array(
455 CRM_Core_Permission::CREATE,
456 CRM_Core_Permission::EDIT,
457 )) &&
458 in_array($field->field_name, array_keys($addressCustomFields))
459 ) {
460 $addressCustom = TRUE;
461 $name = "address_{$name}";
462 }
463 if ($field->field_name == 'url') {
464 $name .= "-{$field->website_type_id}";
465 }
466 elseif (!empty($field->location_type_id)) {
467 $name .= "-{$field->location_type_id}";
468 }
469 else {
470 $locationFields = self::getLocationFields();
471 if (in_array($field->field_name, $locationFields) || $addressCustom) {
472 $name .= '-Primary';
473 }
474 }
475
476 if (isset($field->phone_type_id)) {
477 $name .= "-{$field->phone_type_id}";
478 }
479 $fieldMetaData = CRM_Utils_Array::value($name, $importableFields, (isset($importableFields[$field->field_name]) ? $importableFields[$field->field_name] : array()));
480
481 // No lie: this is bizarre; why do we need to mix so many UFGroup properties into UFFields?
482 // I guess to make field self sufficient with all the required data and avoid additional calls
483 $formattedField = array(
484 'name' => $name,
485 'groupTitle' => $group->title,
486 'groupName' => $group->name,
487 'groupDisplayTitle' => (!empty($group->frontend_title)) ? $group->frontend_title : $group->title,
488 'groupHelpPre' => empty($group->help_pre) ? '' : $group->help_pre,
489 'groupHelpPost' => empty($group->help_post) ? '' : $group->help_post,
490 'title' => $title,
491 'where' => CRM_Utils_Array::value('where', CRM_Utils_Array::value($field->field_name, $importableFields)),
492 'attributes' => CRM_Core_DAO::makeAttribute(CRM_Utils_Array::value($field->field_name, $importableFields)),
493 'is_required' => $field->is_required,
494 'is_view' => $field->is_view,
495 'help_pre' => $field->help_pre,
496 'help_post' => $field->help_post,
497 'visibility' => $field->visibility,
498 'in_selector' => $field->in_selector,
499 'rule' => CRM_Utils_Array::value('rule', CRM_Utils_Array::value($field->field_name, $importableFields)),
500 'location_type_id' => isset($field->location_type_id) ? $field->location_type_id : NULL,
501 'website_type_id' => isset($field->website_type_id) ? $field->website_type_id : NULL,
502 'phone_type_id' => isset($field->phone_type_id) ? $field->phone_type_id : NULL,
503 'group_id' => $group->id,
504 'add_to_group_id' => isset($group->add_to_group_id) ? $group->add_to_group_id : NULL,
505 'add_captcha' => isset($group->add_captcha) ? $group->add_captcha : NULL,
506 'field_type' => $field->field_type,
507 'field_id' => $field->id,
508 'pseudoconstant' => CRM_Utils_Array::value(
509 'pseudoconstant',
510 CRM_Utils_Array::value($field->field_name, $importableFields)
511 ),
512 // obsolete this when we remove the name / dbName discrepancy with gender/suffix/prefix
513 'dbName' => CRM_Utils_Array::value(
514 'dbName',
515 CRM_Utils_Array::value($field->field_name, $importableFields)
516 ),
517 'skipDisplay' => 0,
518 'data_type' => CRM_Utils_Type::getDataTypeFromFieldMetadata($fieldMetaData),
519 'bao' => CRM_Utils_Array::value('bao', $fieldMetaData),
520 );
521
522 $formattedField = CRM_Utils_Date::addDateMetadataToField($fieldMetaData, $formattedField);
523
524 //adding custom field property
525 if (substr($field->field_name, 0, 6) == 'custom' ||
526 substr($field->field_name, 0, 14) === 'address_custom'
527 ) {
528 // if field is not present in customFields, that means the user
529 // DOES NOT HAVE permission to access that field
530 if (array_key_exists($field->field_name, $customFields)) {
531 $formattedField['is_search_range'] = $customFields[$field->field_name]['is_search_range'];
532 // fix for CRM-1994
533 $formattedField['options_per_line'] = $customFields[$field->field_name]['options_per_line'];
534 $formattedField['html_type'] = $customFields[$field->field_name]['html_type'];
535
536 if (CRM_Utils_Array::value('html_type', $formattedField) == 'Select Date') {
537 $formattedField['date_format'] = $customFields[$field->field_name]['date_format'];
538 $formattedField['time_format'] = $customFields[$field->field_name]['time_format'];
539 $formattedField['is_datetime_field'] = TRUE;
540 $formattedField['smarty_view_format'] = CRM_Utils_Date::getDateFieldViewFormat($formattedField['date_format']);
541 }
542
543 $formattedField['is_multi_summary'] = $field->is_multi_summary;
544 return array($name, $formattedField);
545 }
546 else {
547 $formattedField = NULL;
548 return array($name, $formattedField);
549 }
550 }
551 return array($name, $formattedField);
552 }
553
554 /**
555 * Create a query to find all visible UFFields in a UFGroup.
556 *
557 * This is the SQL-variant of checkUFFieldDisplayable().
558 *
559 * @param int $groupId
560 * @param bool $searchable
561 * @param bool $showAll
562 * @param int $visibility
563 * @param string $orderBy
564 * Comma-delimited list of SQL columns.
565 * @return string
566 */
567 protected static function createUFFieldQuery($groupId, $searchable, $showAll, $visibility, $orderBy) {
568 $where = " WHERE uf_group_id = {$groupId}";
569
570 if ($searchable) {
571 $where .= " AND is_searchable = 1";
572 }
573
574 if (!$showAll) {
575 $where .= " AND is_active = 1";
576 }
577
578 if ($visibility) {
579 $clause = array();
580 if ($visibility & self::PUBLIC_VISIBILITY) {
581 $clause[] = 'visibility = "Public Pages"';
582 }
583 if ($visibility & self::ADMIN_VISIBILITY) {
584 $clause[] = 'visibility = "User and User Admin Only"';
585 }
586 if ($visibility & self::LISTINGS_VISIBILITY) {
587 $clause[] = 'visibility = "Public Pages and Listings"';
588 }
589 if (!empty($clause)) {
590 $where .= ' AND ( ' . implode(' OR ', $clause) . ' ) ';
591 }
592 }
593
594 $query = "SELECT * FROM civicrm_uf_field $where ORDER BY weight";
595 if ($orderBy) {
596 $query .= ", " . $orderBy;
597 return $query;
598 }
599 return $query;
600 }
601
602 /**
603 * Create a query to find all visible UFFields in a UFGroup.
604 *
605 * This is the PHP in-memory variant of createUFFieldQuery().
606 *
607 * @param CRM_Core_DAO_UFField|CRM_Core_DAO $field
608 * @param bool $searchable
609 * @param bool $showAll
610 * @param int $visibility
611 * @return bool
612 * TRUE if field is displayable
613 */
614 protected static function filterUFField($field, $searchable, $showAll, $visibility) {
615 if ($searchable && $field->is_searchable != 1) {
616 return FALSE;
617 }
618
619 if (!$showAll && $field->is_active != 1) {
620 return FALSE;
621 }
622
623 if ($visibility) {
624 $allowedVisibilities = array();
625 if ($visibility & self::PUBLIC_VISIBILITY) {
626 $allowedVisibilities[] = 'Public Pages';
627 }
628 if ($visibility & self::ADMIN_VISIBILITY) {
629 $allowedVisibilities[] = 'User and User Admin Only';
630 }
631 if ($visibility & self::LISTINGS_VISIBILITY) {
632 $allowedVisibilities[] = 'Public Pages and Listings';
633 }
634 // !empty($allowedVisibilities) seems silly to me, but it is equivalent to the pre-existing SQL
635 if (!empty($allowedVisibilities) && !in_array($field->visibility, $allowedVisibilities)) {
636 return FALSE;
637 }
638 }
639
640 return TRUE;
641 }
642
643 /**
644 * Get a list of filtered field metadata.
645 *
646 * @deprecated use getProfileFieldMetadata
647 *
648 * @param $showAll
649 * @param $profileType
650 * @param $contactActivityProfile
651 * @param bool $filterMode
652 * Filter mode means you are using importable fields for filtering rather than just getting metadata.
653 * With filter mode = FALSE BOTH activity fields and component fields are returned.
654 * I can't see why you would ever want to use this function in filter mode as the component fields are
655 * still unfiltered. However, I feel scared enough to leave it as it is. I have marked this function as
656 * deprecated and am recommending the wrapper 'getProfileFieldMetadata' in order to try to
657 * send this confusion to history.
658 *
659 * @return array
660 */
661 protected static function getImportableFields($showAll, $profileType, $contactActivityProfile, $filterMode = TRUE) {
662 if (!$showAll) {
663 $importableFields = CRM_Contact_BAO_Contact::importableFields('All', FALSE, FALSE, FALSE, TRUE, TRUE);
664 }
665 else {
666 $importableFields = CRM_Contact_BAO_Contact::importableFields('All', FALSE, TRUE, FALSE, TRUE, TRUE);
667 }
668
669 $activityFields = CRM_Activity_BAO_Activity::getProfileFields();
670 $componentFields = CRM_Core_Component::getQueryFields();
671 if ($filterMode == TRUE) {
672 if ($profileType == 'Activity' || $contactActivityProfile) {
673 $importableFields = array_merge($importableFields, $activityFields);
674 }
675 else {
676 $importableFields = array_merge($importableFields, $componentFields);
677 }
678 }
679 else {
680 $importableFields = array_merge($importableFields, $activityFields, $componentFields);
681 }
682
683 $importableFields['group']['title'] = ts('Group(s)');
684 $importableFields['group']['where'] = NULL;
685 $importableFields['tag']['title'] = ts('Tag(s)');
686 $importableFields['tag']['where'] = NULL;
687 return $importableFields;
688 }
689
690 /**
691 * Get the metadata for all potential profile fields.
692 *
693 * @param bool $isIncludeInactive
694 * Should disabled fields be included.
695 *
696 * @return array
697 * Field metadata for all fields that might potentially be in a profile.
698 */
699 protected static function getProfileFieldMetadata($isIncludeInactive) {
700 return self::getImportableFields($isIncludeInactive, NULL, NULL, NULL, TRUE);
701 }
702
703 /**
704 * Get the fields relating to locations.
705 *
706 * @return array
707 */
708 public static function getLocationFields() {
709 static $locationFields = array(
710 'street_address',
711 'supplemental_address_1',
712 'supplemental_address_2',
713 'supplemental_address_3',
714 'city',
715 'postal_code',
716 'postal_code_suffix',
717 'geo_code_1',
718 'geo_code_2',
719 'state_province',
720 'country',
721 'county',
722 'phone',
723 'phone_and_ext',
724 'email',
725 'im',
726 'address_name',
727 'phone_ext',
728 );
729 return $locationFields;
730 }
731
732 /**
733 * @param $ctype
734 *
735 * @return mixed
736 */
737 protected static function getCustomFields($ctype) {
738 static $customFieldCache = array();
739 if (!isset($customFieldCache[$ctype])) {
740 $customFields = CRM_Core_BAO_CustomField::getFieldsForImport($ctype, FALSE, FALSE, FALSE, TRUE, TRUE);
741
742 // hack to add custom data for components
743 $components = array('Contribution', 'Participant', 'Membership', 'Activity', 'Case');
744 foreach ($components as $value) {
745 $customFields = array_merge($customFields, CRM_Core_BAO_CustomField::getFieldsForImport($value));
746 }
747 $addressCustomFields = CRM_Core_BAO_CustomField::getFieldsForImport('Address');
748 $customFields = array_merge($customFields, $addressCustomFields);
749 $customFieldCache[$ctype] = array($customFields, $addressCustomFields);
750 }
751 return $customFieldCache[$ctype];
752 }
753
754 /**
755 * Check the data validity.
756 *
757 * @param int $userID
758 * The user id that we are actually editing.
759 * @param string $name
760 * The machine-name of the group we are interested in.
761 * @param bool $register
762 * @param int $action
763 * The action of the form.
764 *
765 * @pram boolean $register is this the registrtion form
766 * @return bool
767 * true if form is valid
768 */
769 public static function isValid($userID, $name, $register = FALSE, $action = NULL) {
770 if ($register) {
771 $controller = new CRM_Core_Controller_Simple('CRM_Profile_Form_Dynamic',
772 ts('Dynamic Form Creator'),
773 $action
774 );
775 $controller->set('id', $userID);
776 $controller->set('register', 1);
777 $controller->process();
778 return $controller->validate();
779 }
780 else {
781 // make sure we have a valid group
782 $group = new CRM_Core_DAO_UFGroup();
783
784 $group->name = $name;
785
786 if ($group->find(TRUE) && $userID) {
787 $controller = new CRM_Core_Controller_Simple('CRM_Profile_Form_Dynamic', ts('Dynamic Form Creator'), $action);
788 $controller->set('gid', $group->id);
789 $controller->set('id', $userID);
790 $controller->set('register', 0);
791 $controller->process();
792 return $controller->validate();
793 }
794 return TRUE;
795 }
796 }
797
798 /**
799 * Get the html for the form that represents this particular group.
800 *
801 * @param int $userID
802 * The user id that we are actually editing.
803 * @param string $title
804 * The title of the group we are interested in.
805 * @param int $action
806 * The action of the form.
807 * @param bool $register
808 * Is this the registration form.
809 * @param bool $reset
810 * Should we reset the form?.
811 * @param int $profileID
812 * Do we have the profile ID?.
813 *
814 * @param bool $doNotProcess
815 * @param null $ctype
816 *
817 * @return string
818 * the html for the form on success, otherwise empty string
819 */
820 public static function getEditHTML(
821 $userID,
822 $title,
823 $action = NULL,
824 $register = FALSE,
825 $reset = FALSE,
826 $profileID = NULL,
827 $doNotProcess = FALSE,
828 $ctype = NULL
829 ) {
830
831 if ($register) {
832 $controller = new CRM_Core_Controller_Simple('CRM_Profile_Form_Dynamic',
833 ts('Dynamic Form Creator'),
834 $action
835 );
836 if ($reset || $doNotProcess) {
837 // hack to make sure we do not process this form
838 $oldQFDefault = CRM_Utils_Array::value('_qf_default',
839 $_POST
840 );
841 unset($_POST['_qf_default']);
842 unset($_REQUEST['_qf_default']);
843 if ($reset) {
844 $controller->reset();
845 }
846 }
847
848 $controller->set('id', $userID);
849 $controller->set('register', 1);
850 $controller->set('skipPermission', 1);
851 $controller->set('ctype', $ctype);
852 $controller->process();
853 if ($doNotProcess || !empty($_POST)) {
854 $controller->validate();
855 }
856 $controller->setEmbedded(TRUE);
857
858 //CRM-5839 - though we want to process form, get the control back.
859 $controller->setSkipRedirection(($doNotProcess) ? FALSE : TRUE);
860
861 $controller->run();
862
863 // we are done processing so restore the POST/REQUEST vars
864 if (($reset || $doNotProcess) && $oldQFDefault) {
865 $_POST['_qf_default'] = $_REQUEST['_qf_default'] = $oldQFDefault;
866 }
867
868 $template = CRM_Core_Smarty::singleton();
869
870 // Hide CRM error messages if they are displayed using drupal form_set_error.
871 if (!empty($_POST)) {
872 $template->assign('suppressForm', TRUE);
873 }
874
875 return trim($template->fetch('CRM/Profile/Form/Dynamic.tpl'));
876 }
877 else {
878 if (!$profileID) {
879 // make sure we have a valid group
880 $group = new CRM_Core_DAO_UFGroup();
881
882 $group->title = $title;
883
884 if ($group->find(TRUE)) {
885 $profileID = $group->id;
886 }
887 }
888
889 if ($profileID) {
890 // make sure profileID and ctype match if ctype exists
891 if ($ctype) {
892 $profileType = CRM_Core_BAO_UFField::getProfileType($profileID);
893 if (CRM_Contact_BAO_ContactType::isaSubType($profileType)) {
894 $profileType = CRM_Contact_BAO_ContactType::getBasicType($profileType);
895 }
896
897 if (($profileType != 'Contact') && ($profileType != $ctype)) {
898 return NULL;
899 }
900 }
901
902 $controller = new CRM_Core_Controller_Simple('CRM_Profile_Form_Dynamic',
903 ts('Dynamic Form Creator'),
904 $action
905 );
906 if ($reset) {
907 $controller->reset();
908 }
909 $controller->set('gid', $profileID);
910 $controller->set('id', $userID);
911 $controller->set('register', 0);
912 $controller->set('skipPermission', 1);
913 if ($ctype) {
914 $controller->set('ctype', $ctype);
915 }
916 $controller->process();
917 $controller->setEmbedded(TRUE);
918
919 //CRM-5846 - give the control back to drupal.
920 $controller->setSkipRedirection(($doNotProcess) ? FALSE : TRUE);
921 $controller->run();
922
923 $template = CRM_Core_Smarty::singleton();
924
925 // Hide CRM error messages if they are displayed using drupal form_set_error.
926 if (!empty($_POST) && CRM_Core_Config::singleton()->userFramework == 'Drupal') {
927 if (arg(0) == 'user' || (arg(0) == 'admin' && arg(1) == 'people')) {
928 $template->assign('suppressForm', TRUE);
929 }
930 }
931
932 $templateFile = "CRM/Profile/Form/{$profileID}/Dynamic.tpl";
933 if (!$template->template_exists($templateFile)) {
934 $templateFile = 'CRM/Profile/Form/Dynamic.tpl';
935 }
936 return trim($template->fetch($templateFile));
937 }
938 else {
939 $userEmail = CRM_Contact_BAO_Contact_Location::getEmailDetails($userID);
940
941 // if post not empty then only proceed
942 if (!empty($_POST)) {
943 // get the new email
944 $config = CRM_Core_Config::singleton();
945 $email = CRM_Utils_Array::value('mail', $_POST);
946
947 if (CRM_Utils_Rule::email($email) && ($email != $userEmail[1])) {
948 CRM_Core_BAO_UFMatch::updateContactEmail($userID, $email);
949 }
950 }
951 }
952 }
953 return '';
954 }
955
956 /**
957 * Given a contact id and a field set, return the values from the db.
958 *
959 * @param int $cid
960 * @param array $fields
961 * The profile fields of interest.
962 * @param array $values
963 * The values for the above fields.
964 * @param bool $searchable
965 * Searchable or not.
966 * @param array $componentWhere
967 * Component condition.
968 * @param bool $absolute
969 * Return urls in absolute form (useful when sending an email).
970 * @param null $additionalWhereClause
971 *
972 * @return null|array
973 */
974 public static function getValues(
975 $cid, &$fields, &$values,
976 $searchable = TRUE, $componentWhere = NULL,
977 $absolute = FALSE, $additionalWhereClause = NULL
978 ) {
979 if (empty($cid) && empty($componentWhere)) {
980 return NULL;
981 }
982
983 // get the contact details (hier)
984 $returnProperties = CRM_Contact_BAO_Contact::makeHierReturnProperties($fields);
985 $params = $cid ? array(array('contact_id', '=', $cid, 0, 0)) : array();
986
987 // add conditions specified by components. eg partcipant_id etc
988 if (!empty($componentWhere)) {
989 $params = array_merge($params, $componentWhere);
990 }
991
992 $query = new CRM_Contact_BAO_Query($params, $returnProperties, $fields);
993
994 $details = $query->searchQuery(0, 0, NULL, FALSE, FALSE,
995 FALSE, FALSE, FALSE, $additionalWhereClause);
996 if (!$details->fetch()) {
997 return;
998 }
999 $query->convertToPseudoNames($details);
1000 $config = CRM_Core_Config::singleton();
1001
1002 $locationTypes = CRM_Core_PseudoConstant::get('CRM_Core_DAO_Address', 'location_type_id');
1003 $imProviders = CRM_Core_PseudoConstant::get('CRM_Core_DAO_IM', 'provider_id');
1004 $websiteTypes = CRM_Core_PseudoConstant::get('CRM_Core_DAO_Website', 'website_type_id');
1005
1006 $multipleFields = array('url');
1007
1008 //start of code to set the default values
1009 foreach ($fields as $name => $field) {
1010 // fix for CRM-3962
1011 if ($name == 'id') {
1012 $name = 'contact_id';
1013 }
1014
1015 // skip fields that should not be displayed separately
1016 if (!empty($field['skipDisplay'])) {
1017 continue;
1018 }
1019
1020 // Create a unique, non-empty index for each field.
1021 $index = $field['title'];
1022 if ($index === '') {
1023 $index = ' ';
1024 }
1025 while (array_key_exists($index, $values)) {
1026 $index .= ' ';
1027 }
1028
1029 $params[$index] = $values[$index] = '';
1030 $customFieldName = NULL;
1031 // hack for CRM-665
1032 if (isset($details->$name) || $name == 'group' || $name == 'tag') {
1033 // to handle gender / suffix / prefix
1034 if (in_array(substr($name, 0, -3), array('gender', 'prefix', 'suffix'))) {
1035 $params[$index] = $details->$name;
1036 $values[$index] = $details->$name;
1037 }
1038 elseif (in_array($name, CRM_Contact_BAO_Contact::$_greetingTypes)) {
1039 $dname = $name . '_display';
1040 $values[$index] = $details->$dname;
1041 $name = $name . '_id';
1042 $params[$index] = $details->$name;
1043 }
1044 elseif (in_array($name, array(
1045 'state_province',
1046 'country',
1047 'county',
1048 ))) {
1049 $values[$index] = $details->$name;
1050 $idx = $name . '_id';
1051 $params[$index] = $details->$idx;
1052 }
1053 elseif ($name === 'preferred_language') {
1054 $params[$index] = $details->$name;
1055 $values[$index] = CRM_Core_PseudoConstant::getLabel('CRM_Contact_DAO_Contact', 'preferred_language', $details->$name);
1056 }
1057 elseif ($name == 'group') {
1058 $groups = CRM_Contact_BAO_GroupContact::getContactGroup($cid, 'Added', NULL, FALSE, TRUE);
1059 $title = $ids = array();
1060
1061 foreach ($groups as $g) {
1062 // CRM-8362: User and User Admin visibility groups should be included in display if user has
1063 // VIEW permission on that group
1064 $groupPerm = CRM_Contact_BAO_Group::checkPermission($g['group_id'], TRUE);
1065
1066 if ($g['visibility'] != 'User and User Admin Only' ||
1067 CRM_Utils_Array::key(CRM_Core_Permission::VIEW, $groupPerm)
1068 ) {
1069 $title[] = $g['title'];
1070 if ($g['visibility'] == 'Public Pages') {
1071 $ids[] = $g['group_id'];
1072 }
1073 }
1074 }
1075 $values[$index] = implode(', ', $title);
1076 $params[$index] = implode(',', $ids);
1077 }
1078 elseif ($name == 'tag') {
1079 $entityTags = CRM_Core_BAO_EntityTag::getTag($cid);
1080 $allTags = CRM_Core_PseudoConstant::get('CRM_Core_DAO_EntityTag', 'tag_id', array('onlyActive' => FALSE));
1081 $title = array();
1082 foreach ($entityTags as $tagId) {
1083 $title[] = $allTags[$tagId];
1084 }
1085 $values[$index] = implode(', ', $title);
1086 $params[$index] = implode(',', $entityTags);
1087 }
1088 elseif ($name == 'activity_status_id') {
1089 $activityStatus = CRM_Core_PseudoConstant::activityStatus();
1090 $values[$index] = $activityStatus[$details->$name];
1091 $params[$index] = $details->$name;
1092 }
1093 elseif ($name == 'activity_date_time') {
1094 $values[$index] = CRM_Utils_Date::customFormat($details->$name);
1095 $params[$index] = $details->$name;
1096 }
1097 elseif ($name == 'contact_sub_type') {
1098 $contactSubTypeNames = explode(CRM_Core_DAO::VALUE_SEPARATOR, $details->$name);
1099 if (!empty($contactSubTypeNames)) {
1100 $contactSubTypeLabels = array();
1101 // get all contact subtypes
1102 $allContactSubTypes = CRM_Contact_BAO_ContactType::subTypeInfo();
1103 // build contact subtype labels array
1104 foreach ($contactSubTypeNames as $cstName) {
1105 if ($cstName) {
1106 $contactSubTypeLabels[] = $allContactSubTypes[$cstName]['label'];
1107 }
1108 }
1109 $values[$index] = implode(',', $contactSubTypeLabels);
1110 }
1111
1112 $params[$index] = $details->$name;
1113 }
1114 else {
1115 if (substr($name, 0, 7) === 'do_not_' || substr($name, 0, 3) === 'is_') {
1116 if ($details->$name) {
1117 $values[$index] = '[ x ]';
1118 }
1119 }
1120 else {
1121 if ($cfID = CRM_Core_BAO_CustomField::getKeyID($name)) {
1122 $htmlType = $field['html_type'];
1123
1124 // field_type is only set when we are retrieving profile values
1125 // when sending email, we call the same function to get custom field
1126 // values etc, i.e. emulating a profile
1127 $fieldType = CRM_Utils_Array::value('field_type', $field);
1128
1129 if ($htmlType == 'File') {
1130 $entityId = $cid;
1131 if (!$cid &&
1132 $fieldType == 'Activity' && !empty($componentWhere[0][2])
1133 ) {
1134 $entityId = $componentWhere[0][2];
1135 }
1136
1137 $fileURL = CRM_Core_BAO_CustomField::getFileURL($entityId,
1138 $cfID,
1139 NULL,
1140 $absolute,
1141 $additionalWhereClause
1142 );
1143 $params[$index] = $values[$index] = $fileURL['file_url'];
1144 }
1145 else {
1146 $customVal = NULL;
1147 if (isset($dao) && property_exists($dao, 'data_type') &&
1148 ($dao->data_type == 'Int' ||
1149 $dao->data_type == 'Boolean'
1150 )
1151 ) {
1152 $customVal = (int ) ($details->{$name});
1153 }
1154 elseif (isset($dao) && property_exists($dao, 'data_type')
1155 && $dao->data_type == 'Float'
1156 ) {
1157 $customVal = (float ) ($details->{$name});
1158 }
1159 elseif (!CRM_Utils_System::isNull(explode(CRM_Core_DAO::VALUE_SEPARATOR,
1160 $details->{$name}
1161 ))
1162 ) {
1163 $customVal = $details->{$name};
1164 }
1165
1166 //CRM-4582
1167 if (CRM_Utils_System::isNull($customVal)) {
1168 continue;
1169 }
1170
1171 $params[$index] = $customVal;
1172 $values[$index] = CRM_Core_BAO_CustomField::displayValue($customVal, $cfID);
1173 if ($field['data_type'] == 'ContactReference') {
1174 $params[$index] = $values[$index];
1175 }
1176 if (CRM_Core_DAO::getFieldValue('CRM_Core_DAO_CustomField',
1177 $cfID, 'is_search_range'
1178 )
1179 ) {
1180 $customFieldName = "{$name}_from";
1181 }
1182 }
1183 }
1184 elseif ($name == 'image_URL') {
1185 list($width, $height) = getimagesize(CRM_Utils_String::unstupifyUrl($details->$name));
1186 list($thumbWidth, $thumbHeight) = CRM_Contact_BAO_Contact::getThumbSize($width, $height);
1187
1188 $image_URL = '<img src="' . $details->$name . '" height= ' . $thumbHeight . ' width= ' . $thumbWidth . ' />';
1189 $values[$index] = "<a href='#' onclick='contactImagePopUp(\"{$details->$name}\", {$width}, {$height});'>{$image_URL}</a>";
1190 }
1191 elseif (in_array($name, array(
1192 'birth_date',
1193 'deceased_date',
1194 ))) {
1195 // @todo this set should be determined from metadata, not hard-coded.
1196 $values[$index] = CRM_Utils_Date::customFormat($details->$name);
1197 $params[$index] = CRM_Utils_Date::isoToMysql($details->$name);
1198 }
1199 else {
1200 $dao = '';
1201 if ($index == 'Campaign') {
1202 $dao = 'CRM_Campaign_DAO_Campaign';
1203 }
1204 elseif ($index == 'Contribution Page') {
1205 $dao = 'CRM_Contribute_DAO_ContributionPage';
1206 }
1207 if ($dao) {
1208 $value = CRM_Core_DAO::getFieldValue($dao, $details->$name, 'title');
1209 }
1210 else {
1211 $value = $details->$name;
1212 }
1213 $values[$index] = $value;
1214 }
1215 }
1216 }
1217 }
1218 elseif (strpos($name, '-') !== FALSE) {
1219 list($fieldName, $id, $type) = CRM_Utils_System::explode('-', $name, 3);
1220
1221 if (!in_array($fieldName, $multipleFields)) {
1222 if ($id == 'Primary') {
1223 // fix for CRM-1543
1224 // not sure why we'd every use Primary location type id
1225 // we need to fix the source if we are using it
1226 // $locationTypeName = CRM_Contact_BAO_Contact::getPrimaryLocationType( $cid );
1227 $locationTypeName = 1;
1228 }
1229 else {
1230 $locationTypeName = CRM_Utils_Array::value($id, $locationTypes);
1231 }
1232
1233 if (!$locationTypeName) {
1234 continue;
1235 }
1236
1237 $detailName = "{$locationTypeName}-{$fieldName}";
1238 $detailName = str_replace(' ', '_', $detailName);
1239
1240 if (in_array($fieldName, array(
1241 'phone',
1242 'im',
1243 'email',
1244 'openid',
1245 ))) {
1246 if ($type) {
1247 $detailName .= "-{$type}";
1248 }
1249 }
1250
1251 if (in_array($fieldName, array(
1252 'state_province',
1253 'country',
1254 'county',
1255 ))) {
1256 $values[$index] = $details->$detailName;
1257 $idx = $detailName . '_id';
1258 $params[$index] = $details->$idx;
1259 }
1260 elseif ($fieldName == 'im') {
1261 $providerId = $detailName . '-provider_id';
1262 if (isset($imProviders[$details->$providerId])) {
1263 $values[$index] = $details->$detailName . " (" . $imProviders[$details->$providerId] . ")";
1264 }
1265 else {
1266 $values[$index] = $details->$detailName;
1267 }
1268 $params[$index] = $details->$detailName;
1269 }
1270 elseif ($fieldName == 'phone') {
1271 $phoneExtField = str_replace('phone', 'phone_ext', $detailName);
1272 if (isset($details->$phoneExtField)) {
1273 $values[$index] = $details->$detailName . " (" . $details->$phoneExtField . ")";
1274 }
1275 else {
1276 $values[$index] = $details->$detailName;
1277 }
1278 $params[$index] = $details->$detailName;
1279 }
1280 else {
1281 $values[$index] = $params[$index] = $details->$detailName;
1282 }
1283 }
1284 else {
1285 $detailName = "website-{$id}-{$fieldName}";
1286 $url = CRM_Utils_System::fixURL($details->$detailName);
1287 if ($details->$detailName) {
1288 $websiteTypeId = "website-{$id}-website_type_id";
1289 $websiteType = $websiteTypes[$details->$websiteTypeId];
1290 $values[$index] = "<a href=\"$url\">{$details->$detailName} ( {$websiteType} )</a>";
1291 }
1292 else {
1293 $values[$index] = '';
1294 }
1295 }
1296 }
1297
1298 if ((CRM_Utils_Array::value('visibility', $field) == 'Public Pages and Listings') &&
1299 CRM_Core_Permission::check('profile listings and forms')
1300 ) {
1301
1302 if (CRM_Utils_System::isNull($params[$index])) {
1303 $params[$index] = $values[$index];
1304 }
1305 if (!isset($params[$index])) {
1306 continue;
1307 }
1308 if (!$customFieldName) {
1309 $fieldName = $field['name'];
1310 }
1311 else {
1312 $fieldName = $customFieldName;
1313 }
1314
1315 $url = NULL;
1316 if (CRM_Core_BAO_CustomField::getKeyID($field['name'])) {
1317 $htmlType = $field['html_type'];
1318 if ($htmlType == 'Link') {
1319 $url = $params[$index];
1320 }
1321 elseif (in_array($htmlType, array(
1322 'CheckBox',
1323 'Multi-Select',
1324 'AdvMulti-Select',
1325 'Multi-Select State/Province',
1326 'Multi-Select Country',
1327 ))) {
1328 $valSeperator = CRM_Core_DAO::VALUE_SEPARATOR;
1329 $selectedOptions = explode($valSeperator, $params[$index]);
1330
1331 foreach ($selectedOptions as $key => $multiOption) {
1332 if ($multiOption) {
1333 $url[] = CRM_Utils_System::url('civicrm/profile',
1334 'reset=1&force=1&gid=' . $field['group_id'] . '&' .
1335 urlencode($fieldName) .
1336 '=' .
1337 urlencode($multiOption)
1338 );
1339 }
1340 }
1341 }
1342 else {
1343 $url = CRM_Utils_System::url('civicrm/profile',
1344 'reset=1&force=1&gid=' . $field['group_id'] . '&' .
1345 urlencode($fieldName) .
1346 '=' .
1347 urlencode($params[$index])
1348 );
1349 }
1350 }
1351 else {
1352 $url = CRM_Utils_System::url('civicrm/profile',
1353 'reset=1&force=1&gid=' . $field['group_id'] . '&' .
1354 urlencode($fieldName) .
1355 '=' .
1356 urlencode($params[$index])
1357 );
1358 }
1359
1360 if ($url &&
1361 !empty($values[$index]) &&
1362 $searchable
1363 ) {
1364
1365 if (is_array($url) && !empty($url)) {
1366 $links = array();
1367 $eachMultiValue = explode(', ', $values[$index]);
1368 foreach ($eachMultiValue as $key => $valueLabel) {
1369 $links[] = '<a href="' . $url[$key] . '">' . $valueLabel . '</a>';
1370 }
1371 $values[$index] = implode(', ', $links);
1372 }
1373 else {
1374 $values[$index] = '<a href="' . $url . '">' . $values[$index] . '</a>';
1375 }
1376 }
1377 }
1378 }
1379 }
1380
1381 /**
1382 * Check if profile Group used by any module.
1383 *
1384 * @param int $id
1385 * Profile Id.
1386 *
1387 * @return bool
1388 *
1389 */
1390 public static function usedByModule($id) {
1391 //check whether this group is used by any module(check uf join records)
1392 $sql = "SELECT id
1393 FROM civicrm_uf_join
1394 WHERE civicrm_uf_join.uf_group_id=$id";
1395
1396 $dao = new CRM_Core_DAO();
1397 $dao->query($sql);
1398 if ($dao->fetch()) {
1399 return TRUE;
1400 }
1401 else {
1402 return FALSE;
1403 }
1404 }
1405
1406 /**
1407 * Delete the profile Group.
1408 *
1409 * @param int $id
1410 * Profile Id.
1411 *
1412 * @return bool
1413 *
1414 */
1415 public static function del($id) {
1416 //check whether this group contains any profile fields
1417 $profileField = new CRM_Core_DAO_UFField();
1418 $profileField->uf_group_id = $id;
1419 $profileField->find();
1420 while ($profileField->fetch()) {
1421 CRM_Core_BAO_UFField::del($profileField->id);
1422 }
1423
1424 //delete records from uf join table
1425 $ufJoin = new CRM_Core_DAO_UFJoin();
1426 $ufJoin->uf_group_id = $id;
1427 $ufJoin->delete();
1428
1429 //delete profile group
1430 $group = new CRM_Core_DAO_UFGroup();
1431 $group->id = $id;
1432 $group->delete();
1433 return 1;
1434 }
1435
1436 /**
1437 * Add the UF Group.
1438 *
1439 * @param array $params
1440 * Reference array contains the values submitted by the form.
1441 * @param array $ids
1442 * Reference array contains the id.
1443 *
1444 *
1445 * @return object
1446 */
1447 public static function add(&$params, $ids = array()) {
1448 $fields = array(
1449 'is_active',
1450 'add_captcha',
1451 'is_map',
1452 'is_update_dupe',
1453 'is_edit_link',
1454 'is_uf_link',
1455 'is_cms_user',
1456 );
1457 foreach ($fields as $field) {
1458 $params[$field] = CRM_Utils_Array::value($field, $params, FALSE);
1459 }
1460
1461 $params['limit_listings_group_id'] = CRM_Utils_Array::value('group', $params);
1462 $params['add_to_group_id'] = CRM_Utils_Array::value('add_contact_to_group', $params);
1463
1464 //CRM-15427
1465 if (!empty($params['group_type']) && is_array($params['group_type'])) {
1466 $params['group_type'] = implode(',', $params['group_type']);
1467 }
1468 $ufGroup = new CRM_Core_DAO_UFGroup();
1469 $ufGroup->copyValues($params);
1470
1471 $ufGroupID = CRM_Utils_Array::value('ufgroup', $ids, CRM_Utils_Array::value('id', $params));
1472 if (!$ufGroupID && empty($params['name'])) {
1473 $ufGroup->name = CRM_Utils_String::munge($ufGroup->title, '_', 56);
1474 }
1475 $ufGroup->id = $ufGroupID;
1476
1477 $ufGroup->save();
1478
1479 if (!$ufGroupID && empty($params['name'])) {
1480 $ufGroup->name = $ufGroup->name . "_{$ufGroup->id}";
1481 $ufGroup->save();
1482 }
1483
1484 return $ufGroup;
1485 }
1486
1487 /**
1488 * Make uf join entries for an uf group.
1489 *
1490 * @param array $params
1491 * (reference) an assoc array of name/value pairs.
1492 * @param int $ufGroupId
1493 * Ufgroup id.
1494 */
1495 public static function createUFJoin(&$params, $ufGroupId) {
1496 $groupTypes = CRM_Utils_Array::value('uf_group_type', $params);
1497
1498 // get ufjoin records for uf group
1499 $ufGroupRecord = CRM_Core_BAO_UFGroup::getUFJoinRecord($ufGroupId);
1500
1501 // get the list of all ufgroup types
1502 $allUFGroupType = CRM_Core_SelectValues::ufGroupTypes();
1503
1504 // this fix is done to prevent warning generated by array_key_exits incase of empty array is given as input
1505 if (!is_array($groupTypes)) {
1506 $groupTypes = array();
1507 }
1508
1509 // this fix is done to prevent warning generated by array_key_exits incase of empty array is given as input
1510 if (!is_array($ufGroupRecord)) {
1511 $ufGroupRecord = array();
1512 }
1513
1514 // check which values has to be inserted/deleted for contact
1515 $menuRebuild = FALSE;
1516 foreach ($allUFGroupType as $key => $value) {
1517 $joinParams = array();
1518 $joinParams['uf_group_id'] = $ufGroupId;
1519 $joinParams['module'] = $key;
1520 if ($key == 'User Account') {
1521 $menuRebuild = TRUE;
1522 }
1523 if (array_key_exists($key, $groupTypes) && !in_array($key, $ufGroupRecord)) {
1524 // insert a new record
1525 CRM_Core_BAO_UFGroup::addUFJoin($joinParams);
1526 }
1527 elseif (!array_key_exists($key, $groupTypes) && in_array($key, $ufGroupRecord)) {
1528 // delete a record for existing ufgroup
1529 CRM_Core_BAO_UFGroup::delUFJoin($joinParams);
1530 }
1531 }
1532
1533 //update the weight
1534 $query = "
1535 UPDATE civicrm_uf_join
1536 SET weight = %1
1537 WHERE uf_group_id = %2
1538 AND ( entity_id IS NULL OR entity_id <= 0 )
1539 ";
1540 $p = array(
1541 1 => array($params['weight'], 'Integer'),
1542 2 => array($ufGroupId, 'Integer'),
1543 );
1544 CRM_Core_DAO::executeQuery($query, $p);
1545
1546 // Do a menu rebuild, so it gets all the new menu entries for user account
1547 if ($menuRebuild) {
1548 $config = CRM_Core_Config::singleton();
1549 $config->userSystem->updateCategories();
1550 }
1551 }
1552
1553 /**
1554 * Get the UF Join records for an ufgroup id.
1555 *
1556 * @param int $ufGroupId
1557 * Uf group id.
1558 * @param int $displayName
1559 * If set return display name in array.
1560 * @param int $status
1561 * If set return module other than default modules (User Account/User registration/Profile).
1562 *
1563 * @return array
1564 *
1565 */
1566 public static function getUFJoinRecord($ufGroupId = NULL, $displayName = NULL, $status = NULL) {
1567 if ($displayName) {
1568 $UFGroupType = array();
1569 $UFGroupType = CRM_Core_SelectValues::ufGroupTypes();
1570 }
1571
1572 $ufJoin = array();
1573 $dao = new CRM_Core_DAO_UFJoin();
1574
1575 if ($ufGroupId) {
1576 $dao->uf_group_id = $ufGroupId;
1577 }
1578
1579 $dao->find();
1580 $ufJoin = array();
1581
1582 while ($dao->fetch()) {
1583 if (!$displayName) {
1584 $ufJoin[$dao->id] = $dao->module;
1585 }
1586 else {
1587 if (isset($UFGroupType[$dao->module])) {
1588 // skip the default modules
1589 if (!$status) {
1590 $ufJoin[$dao->id] = $UFGroupType[$dao->module];
1591 }
1592 // added for CRM-1475
1593 }
1594 elseif (!CRM_Utils_Array::key($dao->module, $ufJoin)) {
1595 $ufJoin[$dao->id] = $dao->module;
1596 }
1597 }
1598 }
1599 return $ufJoin;
1600 }
1601
1602 /**
1603 * Function takes an associative array and creates a ufjoin record for ufgroup.
1604 *
1605 * @param array $params
1606 * (reference) an assoc array of name/value pairs.
1607 *
1608 * @return CRM_Core_BAO_UFJoin
1609 */
1610 public static function addUFJoin(&$params) {
1611 $ufJoin = new CRM_Core_DAO_UFJoin();
1612 $ufJoin->copyValues($params);
1613 $ufJoin->save();
1614 return $ufJoin;
1615 }
1616
1617 /**
1618 * Delete the uf join record for an uf group.
1619 *
1620 * @param array $params
1621 * (reference) an assoc array of name/value pairs.
1622 */
1623 public static function delUFJoin(&$params) {
1624 $ufJoin = new CRM_Core_DAO_UFJoin();
1625 $ufJoin->copyValues($params);
1626 $ufJoin->delete();
1627 }
1628
1629 /**
1630 * Get the weight for ufjoin record.
1631 *
1632 * @param int $ufGroupId
1633 * If $ufGroupId get update weight or add weight.
1634 *
1635 * @return int
1636 * weight of the UFGroup
1637 */
1638 public static function getWeight($ufGroupId = NULL) {
1639 //calculate the weight
1640 $p = array();
1641 if (!$ufGroupId) {
1642 $queryString = "SELECT ( MAX(civicrm_uf_join.weight)+1) as new_weight
1643 FROM civicrm_uf_join
1644 WHERE module = 'User Registration' OR module = 'User Account' OR module = 'Profile'";
1645 }
1646 else {
1647 $queryString = "SELECT MAX(civicrm_uf_join.weight) as new_weight
1648 FROM civicrm_uf_join
1649 WHERE civicrm_uf_join.uf_group_id = %1
1650 AND ( entity_id IS NULL OR entity_id <= 0 )";
1651 $p[1] = array($ufGroupId, 'Integer');
1652 }
1653
1654 $dao = CRM_Core_DAO::executeQuery($queryString, $p);
1655 $dao->fetch();
1656 return ($dao->new_weight) ? $dao->new_weight : 1;
1657 }
1658
1659 /**
1660 * Get the uf group for a module.
1661 *
1662 * @param string $moduleName
1663 * Module name.
1664 * @param int $count
1665 * No to increment the weight.
1666 * @param bool $skipPermission
1667 * @param int $op
1668 * Which operation (view, edit, create, etc) to check permission for.
1669 * @param array|NULL $returnFields list of UFGroup fields to return; NULL for default
1670 *
1671 * @return array
1672 * array of ufgroups for a module
1673 */
1674 public static function getModuleUFGroup($moduleName = NULL, $count = 0, $skipPermission = TRUE, $op = CRM_Core_Permission::VIEW, $returnFields = NULL) {
1675 $selectFields = array('id', 'title', 'created_id', 'is_active', 'is_reserved', 'group_type');
1676
1677 if (CRM_Core_DAO::checkFieldExists('civicrm_uf_group', 'description')) {
1678 // CRM-13555, since description field was added later (4.4), and to avoid any problems with upgrade
1679 $selectFields[] = 'description';
1680 }
1681
1682 if (CRM_Core_DAO::checkFieldExists('civicrm_uf_group', 'frontend_title')) {
1683 $selectFields[] = 'frontend_title';
1684 }
1685
1686 if (!empty($returnFields)) {
1687 $selectFields = array_merge($returnFields, array_diff($selectFields, $returnFields));
1688 }
1689
1690 $queryString = 'SELECT civicrm_uf_group.' . implode(', civicrm_uf_group.', $selectFields) . '
1691 FROM civicrm_uf_group
1692 LEFT JOIN civicrm_uf_join ON (civicrm_uf_group.id = uf_group_id)';
1693 $p = array();
1694 if ($moduleName) {
1695 $queryString .= ' AND civicrm_uf_group.is_active = 1
1696 WHERE civicrm_uf_join.module = %2';
1697 $p[2] = array($moduleName, 'String');
1698 }
1699
1700 // add permissioning for profiles only if not registration
1701 if (!$skipPermission) {
1702 $permissionClause = CRM_Core_Permission::ufGroupClause($op, 'civicrm_uf_group.');
1703 if (strpos($queryString, 'WHERE') !== FALSE) {
1704 $queryString .= " AND $permissionClause ";
1705 }
1706 else {
1707 $queryString .= " $permissionClause ";
1708 }
1709 }
1710
1711 $queryString .= ' ORDER BY civicrm_uf_join.weight, civicrm_uf_group.title';
1712 $dao = CRM_Core_DAO::executeQuery($queryString, $p);
1713
1714 $ufGroups = array();
1715 while ($dao->fetch()) {
1716 //skip mix profiles in user Registration / User Account
1717 if (($moduleName == 'User Registration' || $moduleName == 'User Account') &&
1718 CRM_Core_BAO_UFField::checkProfileType($dao->id)
1719 ) {
1720 continue;
1721 }
1722 foreach ($selectFields as $key => $field) {
1723 if ($field == 'id') {
1724 continue;
1725 }
1726 $ufGroups[$dao->id][$field] = $dao->$field;
1727 }
1728 }
1729
1730 // Allow other modules to alter/override the UFGroups.
1731 CRM_Utils_Hook::buildUFGroupsForModule($moduleName, $ufGroups);
1732
1733 return $ufGroups;
1734 }
1735
1736 /**
1737 * Filter ufgroups based on logged in user contact type.
1738 *
1739 * @param int $ufGroupId
1740 * Uf group id (profile id).
1741 * @param int $contactID
1742 *
1743 * @return bool
1744 * true or false
1745 */
1746 public static function filterUFGroups($ufGroupId, $contactID = NULL) {
1747 if (!$contactID) {
1748 $session = CRM_Core_Session::singleton();
1749 $contactID = $session->get('userID');
1750 }
1751
1752 if ($contactID) {
1753 //get the contact type
1754 $contactType = CRM_Contact_BAO_Contact::getContactType($contactID);
1755
1756 //match if exixting contact type is same as profile contact type
1757 $profileType = CRM_Core_BAO_UFField::getProfileType($ufGroupId);
1758
1759 if (CRM_Contact_BAO_ContactType::isaSubType($profileType)) {
1760 $profileType = CRM_Contact_BAO_ContactType::getBasicType($profileType);
1761
1762 //in some cases getBasicType() returns a cached array instead of string. Example: array ('sponsor' => 'organization')
1763 if (is_array($profileType)) {
1764 $profileType = array_shift($profileType);
1765 }
1766 }
1767
1768 //allow special mix profiles for Contribution and Participant
1769 $specialProfiles = array('Contribution', 'Participant', 'Membership');
1770
1771 if (in_array($profileType, $specialProfiles)) {
1772 return TRUE;
1773 }
1774
1775 if (($contactType == $profileType) || $profileType == 'Contact') {
1776 return TRUE;
1777 }
1778 }
1779
1780 return FALSE;
1781 }
1782
1783 /**
1784 * Add profile field to a form.
1785 *
1786 * @param CRM_Core_Form $form
1787 * @param array $field
1788 * Properties.
1789 * @param int $mode
1790 * Profile mode.
1791 * @param int $contactId
1792 * @param bool $online
1793 * @param string $usedFor
1794 * For building up prefixed fieldname for special cases (e.g. onBehalf, Honor).
1795 * @param int $rowNumber
1796 * @param string $prefix
1797 *
1798 * @return null
1799 */
1800 public static function buildProfile(
1801 &$form,
1802 &$field,
1803 $mode,
1804 $contactId = NULL,
1805 $online = FALSE,
1806 $usedFor = NULL,
1807 $rowNumber = NULL,
1808 $prefix = ''
1809 ) {
1810 $defaultValues = array();
1811 $fieldName = $field['name'];
1812 $title = $field['title'];
1813 $attributes = $field['attributes'];
1814 $rule = $field['rule'];
1815 $view = $field['is_view'];
1816 $required = ($mode == CRM_Profile_Form::MODE_SEARCH) ? FALSE : $field['is_required'];
1817 $search = ($mode == CRM_Profile_Form::MODE_SEARCH) ? TRUE : FALSE;
1818 $isShared = CRM_Utils_Array::value('is_shared', $field, 0);
1819
1820 // do not display view fields in drupal registration form
1821 // CRM-4632
1822 if ($view && $mode == CRM_Profile_Form::MODE_REGISTER) {
1823 return NULL;
1824 }
1825
1826 if ($usedFor == 'onbehalf') {
1827 $name = "onbehalf[$fieldName]";
1828 }
1829 elseif ($usedFor == 'honor') {
1830 $name = "honor[$fieldName]";
1831 }
1832 elseif ($contactId && !$online) {
1833 $name = "field[$contactId][$fieldName]";
1834 }
1835 elseif ($rowNumber) {
1836 $name = "field[$rowNumber][$fieldName]";
1837 }
1838 elseif (!empty($prefix)) {
1839 $name = $prefix . "[$fieldName]";
1840 }
1841 else {
1842 $name = $fieldName;
1843 }
1844
1845 $selectAttributes = array('class' => 'crm-select2', 'placeholder' => TRUE);
1846
1847 if ($fieldName == 'image_URL' && $mode == CRM_Profile_Form::MODE_EDIT) {
1848 $deleteExtra = json_encode(ts('Are you sure you want to delete contact image.'));
1849 $deleteURL = array(
1850 CRM_Core_Action::DELETE => array(
1851 'name' => ts('Delete Contact Image'),
1852 'url' => 'civicrm/contact/image',
1853 'qs' => 'reset=1&id=%%id%%&gid=%%gid%%&action=delete',
1854 'extra' => 'onclick = "' . htmlspecialchars("if (confirm($deleteExtra)) this.href+='&confirmed=1'; else return false;") . '"',
1855 ),
1856 );
1857 $deleteURL = CRM_Core_Action::formLink($deleteURL,
1858 CRM_Core_Action::DELETE,
1859 array(
1860 'id' => $form->get('id'),
1861 'gid' => $form->get('gid'),
1862 ),
1863 ts('more'),
1864 FALSE,
1865 'contact.profileimage.delete',
1866 'Contact',
1867 $form->get('id')
1868 );
1869 $form->assign('deleteURL', $deleteURL);
1870 }
1871 $addressOptions = CRM_Core_BAO_Setting::valueOptions(CRM_Core_BAO_Setting::SYSTEM_PREFERENCES_NAME,
1872 'address_options', TRUE, NULL, TRUE
1873 );
1874
1875 if (substr($fieldName, 0, 14) === 'state_province') {
1876 $form->addChainSelect($name, array('label' => $title, 'required' => $required));
1877 $config = CRM_Core_Config::singleton();
1878 if (!in_array($mode, array(
1879 CRM_Profile_Form::MODE_EDIT,
1880 CRM_Profile_Form::MODE_SEARCH,
1881 )) &&
1882 $config->defaultContactStateProvince
1883 ) {
1884 $defaultValues[$name] = $config->defaultContactStateProvince;
1885 $form->setDefaults($defaultValues);
1886 }
1887 }
1888 elseif (substr($fieldName, 0, 7) === 'country') {
1889 $form->add('select', $name, $title, array('' => ts('- select -')) + CRM_Core_PseudoConstant::country(), $required, $selectAttributes);
1890 $config = CRM_Core_Config::singleton();
1891 if (!in_array($mode, array(
1892 CRM_Profile_Form::MODE_EDIT,
1893 CRM_Profile_Form::MODE_SEARCH,
1894 )) &&
1895 $config->defaultContactCountry
1896 ) {
1897 $defaultValues[$name] = $config->defaultContactCountry;
1898 $form->setDefaults($defaultValues);
1899 }
1900 }
1901 elseif (substr($fieldName, 0, 6) === 'county') {
1902 if ($addressOptions['county']) {
1903 $form->addChainSelect($name, array('label' => $title, 'required' => $required));
1904 }
1905 }
1906 elseif (substr($fieldName, 0, 9) === 'image_URL') {
1907 $form->add('file', $name, $title, $attributes, $required);
1908 $form->addUploadElement($name);
1909 }
1910 elseif (substr($fieldName, 0, 2) === 'im') {
1911 $form->add('text', $name, $title, $attributes, $required);
1912 if (!$contactId) {
1913 if ($usedFor) {
1914 if (substr($name, -1) == ']') {
1915 $providerName = substr($name, 0, -1) . '-provider_id]';
1916 }
1917 $form->add('select', $providerName, NULL,
1918 array(
1919 '' => ts('- select -'),
1920 ) + CRM_Core_PseudoConstant::get('CRM_Core_DAO_IM', 'provider_id'), $required
1921 );
1922 }
1923 else {
1924 $form->add('select', $name . '-provider_id', $title,
1925 array(
1926 '' => ts('- select -'),
1927 ) + CRM_Core_PseudoConstant::get('CRM_Core_DAO_IM', 'provider_id'), $required
1928 );
1929 }
1930
1931 if ($view && $mode != CRM_Profile_Form::MODE_SEARCH) {
1932 $form->freeze($name . '-provider_id');
1933 }
1934 }
1935 }
1936 elseif (CRM_Utils_Array::value('name', $field) == 'membership_type') {
1937 list($orgInfo, $types) = CRM_Member_BAO_MembershipType::getMembershipTypeInfo();
1938 $sel = &$form->addElement('hierselect', $name, $title);
1939 $select = array('' => ts('- select -'));
1940 if (count($orgInfo) == 1 && $field['is_required']) {
1941 // we only have one org - so we should default to it. Not sure about defaulting to first type
1942 // as it could be missed - so adding a select
1943 // however, possibly that is more similar to the membership form
1944 if (count($types[1]) > 1) {
1945 $types[1] = $select + $types[1];
1946 }
1947 }
1948 else {
1949 $orgInfo = $select + $orgInfo;
1950 }
1951 $sel->setOptions(array($orgInfo, $types));
1952 }
1953 elseif (CRM_Utils_Array::value('name', $field) == 'membership_status') {
1954 $form->add('select', $name, $title,
1955 array(
1956 '' => ts('- select -'),
1957 ) + CRM_Member_PseudoConstant::membershipStatus(NULL, NULL, 'label'), $required
1958 );
1959 }
1960 elseif (in_array($fieldName, array('gender_id', 'communication_style_id'))) {
1961 $options = array();
1962 $pseudoValues = CRM_Core_PseudoConstant::get('CRM_Contact_DAO_Contact', $fieldName);
1963 foreach ($pseudoValues as $key => $var) {
1964 $options[$key] = $form->createElement('radio', NULL, ts($title), $var, $key);
1965 }
1966 $group = $form->addGroup($options, $name, $title);
1967 if ($required) {
1968 $form->addRule($name, ts('%1 is a required field.', array(1 => $title)), 'required');
1969 }
1970 else {
1971 $group->setAttribute('allowClear', TRUE);
1972 }
1973 }
1974 elseif ($fieldName === 'prefix_id' || $fieldName === 'suffix_id') {
1975 $form->addSelect($name, array(
1976 'label' => $title,
1977 'entity' => 'contact',
1978 'field' => $fieldName,
1979 'class' => 'six',
1980 'placeholder' => '',
1981 ), $required);
1982 }
1983 elseif ($fieldName === 'contact_sub_type') {
1984 $gId = $form->get('gid') ? $form->get('gid') : CRM_Utils_Array::value('group_id', $field);
1985 if ($usedFor == 'onbehalf') {
1986 $profileType = 'Organization';
1987 }
1988 elseif ($usedFor == 'honor') {
1989 $profileType = CRM_Core_BAO_UFField::getProfileType($form->_params['honoree_profile_id']);
1990 }
1991 else {
1992 $profileType = $gId ? CRM_Core_BAO_UFField::getProfileType($gId) : NULL;
1993 if ($profileType == 'Contact') {
1994 $profileType = 'Individual';
1995 }
1996 }
1997
1998 $setSubtype = FALSE;
1999 if (CRM_Contact_BAO_ContactType::isaSubType($profileType)) {
2000 $setSubtype = $profileType;
2001 $profileType = CRM_Contact_BAO_ContactType::getBasicType($profileType);
2002 }
2003
2004 $subtypes = $profileType ? CRM_Contact_BAO_ContactType::subTypePairs($profileType) : array();
2005
2006 if ($setSubtype) {
2007 $subtypeList = array();
2008 $subtypeList[$setSubtype] = $subtypes[$setSubtype];
2009 }
2010 else {
2011 $subtypeList = $subtypes;
2012 }
2013
2014 $form->add('select', $name, $title, $subtypeList, $required, array('class' => 'crm-select2', 'multiple' => TRUE));
2015 }
2016 elseif (in_array($fieldName, CRM_Contact_BAO_Contact::$_greetingTypes)) {
2017 //add email greeting, postal greeting, addressee, CRM-4575
2018 $gId = $form->get('gid') ? $form->get('gid') : CRM_Utils_Array::value('group_id', $field);
2019 $profileType = CRM_Core_BAO_UFField::getProfileType($gId, TRUE, FALSE, TRUE);
2020
2021 if (empty($profileType) || in_array($profileType, array(
2022 'Contact',
2023 'Contribution',
2024 'Participant',
2025 'Membership',
2026 ))
2027 ) {
2028 $profileType = 'Individual';
2029 }
2030 if (CRM_Contact_BAO_ContactType::isaSubType($profileType)) {
2031 $profileType = CRM_Contact_BAO_ContactType::getBasicType($profileType);
2032 }
2033 $greeting = array(
2034 'contact_type' => $profileType,
2035 'greeting_type' => $fieldName,
2036 );
2037 $form->add('select', $name, $title,
2038 array(
2039 '' => ts('- select -'),
2040 ) + CRM_Core_PseudoConstant::greeting($greeting), $required
2041 );
2042 // add custom greeting element
2043 $form->add('text', $fieldName . '_custom', ts('Custom %1', array(1 => ucwords(str_replace('_', ' ', $fieldName)))),
2044 NULL, FALSE
2045 );
2046 }
2047 elseif ($fieldName === 'preferred_communication_method') {
2048 $communicationFields = CRM_Core_PseudoConstant::get('CRM_Contact_DAO_Contact', 'preferred_communication_method');
2049 foreach ($communicationFields as $key => $var) {
2050 if ($key == '') {
2051 continue;
2052 }
2053 $communicationOptions[] = $form->createElement('checkbox', $key, NULL, $var);
2054 }
2055 $form->addGroup($communicationOptions, $name, $title, '<br/>');
2056 }
2057 elseif ($fieldName === 'preferred_mail_format') {
2058 $form->add('select', $name, $title, CRM_Core_SelectValues::pmf());
2059 }
2060 elseif ($fieldName === 'preferred_language') {
2061 $form->add('select', $name, $title, array('' => ts('- select -')) + CRM_Contact_BAO_Contact::buildOptions('preferred_language'));
2062 }
2063 elseif ($fieldName == 'external_identifier') {
2064 $form->add('text', $name, $title, $attributes, $required);
2065 $contID = $contactId;
2066 if (!$contID) {
2067 $contID = $form->get('id');
2068 }
2069 $form->addRule($name,
2070 ts('External ID already exists in Database.'),
2071 'objectExists',
2072 array('CRM_Contact_DAO_Contact', $contID, 'external_identifier')
2073 );
2074 }
2075 elseif ($fieldName === 'group') {
2076 CRM_Contact_Form_Edit_TagsAndGroups::buildQuickForm($form, $contactId,
2077 CRM_Contact_Form_Edit_TagsAndGroups::GROUP,
2078 TRUE, $required,
2079 $title, NULL, $name
2080 );
2081 }
2082 elseif ($fieldName === 'tag') {
2083 CRM_Contact_Form_Edit_TagsAndGroups::buildQuickForm($form, $contactId,
2084 CRM_Contact_Form_Edit_TagsAndGroups::TAG,
2085 FALSE, $required,
2086 NULL, $title, $name
2087 );
2088 }
2089 elseif (substr($fieldName, 0, 4) === 'url-') {
2090 $form->add('text', $name, $title, CRM_Core_DAO::getAttribute('CRM_Core_DAO_Website', 'url'), $required);
2091 $form->addRule($name, ts('Enter a valid web address beginning with \'http://\' or \'https://\'.'), 'url');
2092 }
2093 // Note should be rendered as textarea
2094 elseif (substr($fieldName, -4) == 'note') {
2095 $form->add('textarea', $name, $title, $attributes, $required);
2096 }
2097 elseif (substr($fieldName, 0, 6) === 'custom') {
2098 $customFieldID = CRM_Core_BAO_CustomField::getKeyID($fieldName);
2099 if ($customFieldID) {
2100 CRM_Core_BAO_CustomField::addQuickFormElement($form, $name, $customFieldID, $required, $search, $title);
2101 }
2102 }
2103 elseif (substr($fieldName, 0, 14) === 'address_custom') {
2104 list($fName, $locTypeId) = CRM_Utils_System::explode('-', $fieldName, 2);
2105 $customFieldID = CRM_Core_BAO_CustomField::getKeyID(substr($fName, 8));
2106 if ($customFieldID) {
2107 CRM_Core_BAO_CustomField::addQuickFormElement($form, $name, $customFieldID, $required, $search, $title);
2108 }
2109 }
2110 elseif ($fieldName == 'send_receipt') {
2111 $form->addElement('checkbox', $name, $title);
2112 }
2113 elseif ($fieldName == 'soft_credit') {
2114 $form->addEntityRef("soft_credit_contact_id[$rowNumber]", ts('Soft Credit To'), array('create' => TRUE));
2115 $form->addMoney("soft_credit_amount[{$rowNumber}]", ts('Amount'), FALSE, NULL, FALSE);
2116 }
2117 elseif ($fieldName == 'product_name') {
2118 list($products, $options) = CRM_Contribute_BAO_Premium::getPremiumProductInfo();
2119 $sel = &$form->addElement('hierselect', $name, $title);
2120 $products = array(
2121 '0' => ts('- select -'),
2122 ) + $products;
2123 $sel->setOptions(array($products, $options));
2124 }
2125 elseif ($fieldName == 'payment_instrument') {
2126 $form->add('select', $name, $title,
2127 array('' => ts('- select -')) + CRM_Contribute_PseudoConstant::paymentInstrument(), $required);
2128 }
2129 elseif ($fieldName == 'financial_type') {
2130 $form->add('select', $name, $title,
2131 array(
2132 '' => ts('- select -'),
2133 ) + CRM_Contribute_PseudoConstant::financialType(), $required
2134 );
2135 }
2136 elseif ($fieldName == 'contribution_status_id') {
2137 $contributionStatuses = CRM_Contribute_PseudoConstant::contributionStatus();
2138 $statusName = CRM_Contribute_PseudoConstant::contributionStatus(NULL, 'name');
2139 foreach (array(
2140 'In Progress',
2141 'Overdue',
2142 'Refunded',
2143 ) as $suppress) {
2144 unset($contributionStatuses[CRM_Utils_Array::key($suppress, $statusName)]);
2145 }
2146
2147 $form->add('select', $name, $title,
2148 array(
2149 '' => ts('- select -'),
2150 ) + $contributionStatuses, $required
2151 );
2152 }
2153 elseif ($fieldName == 'soft_credit_type') {
2154 $name = "soft_credit_type[$rowNumber]";
2155 $form->add('select', $name, $title,
2156 array(
2157 '' => ts('- select -'),
2158 ) + CRM_Core_OptionGroup::values("soft_credit_type")
2159 );
2160 //CRM-15350: choose SCT field default value as 'Gift' for membership use
2161 //else (for contribution), use configured SCT default value
2162 $SCTDefaultValue = CRM_Core_OptionGroup::getDefaultValue("soft_credit_type");
2163 if ($field['field_type'] == 'Membership') {
2164 $SCTDefaultValue = CRM_Core_PseudoConstant::getKey('CRM_Contribute_BAO_ContributionSoft', 'soft_credit_type_id', 'gift');
2165 }
2166 $form->addElement('hidden', 'sct_default_id', $SCTDefaultValue, array('id' => 'sct_default_id'));
2167 }
2168 elseif ($fieldName == 'contribution_soft_credit_pcp_id') {
2169 CRM_Contribute_Form_SoftCredit::addPCPFields($form, "[$rowNumber]");
2170 }
2171 elseif ($fieldName == 'currency') {
2172 $form->addCurrency($name, $title, $required, NULL, FALSE, FALSE);
2173 }
2174 elseif ($fieldName == 'contribution_page_id') {
2175 $form->add('select', $name, $title,
2176 array(
2177 '' => ts('- select -'),
2178 ) + CRM_Contribute_PseudoConstant::contributionPage(), $required, 'class="big"'
2179 );
2180 }
2181 elseif ($fieldName == 'activity_status_id') {
2182 $form->add('select', $name, $title,
2183 array(
2184 '' => ts('- select -'),
2185 ) + CRM_Core_PseudoConstant::activityStatus(), $required
2186 );
2187 }
2188 elseif ($fieldName == 'activity_engagement_level') {
2189 $form->add('select', $name, $title,
2190 array(
2191 '' => ts('- select -'),
2192 ) + CRM_Campaign_PseudoConstant::engagementLevel(), $required
2193 );
2194 }
2195 elseif ($fieldName == 'participant_status') {
2196 $cond = NULL;
2197 if ($online == TRUE) {
2198 $cond = 'visibility_id = 1';
2199 }
2200 $form->add('select', $name, $title,
2201 array(
2202 '' => ts('- select -'),
2203 ) + CRM_Event_PseudoConstant::participantStatus(NULL, $cond, 'label'), $required
2204 );
2205 }
2206 elseif ($fieldName == 'participant_role') {
2207 if (!empty($field['is_multiple'])) {
2208 $form->addCheckBox($name, $title, CRM_Event_PseudoConstant::participantRole(), NULL, NULL, NULL, NULL, '&nbsp', TRUE);
2209 }
2210 else {
2211 $form->add('select', $name, $title,
2212 array(
2213 '' => ts('- select -'),
2214 ) + CRM_Event_PseudoConstant::participantRole(), $required
2215 );
2216 }
2217 }
2218 elseif ($fieldName == 'world_region') {
2219 $form->add('select', $name, $title, CRM_Core_PseudoConstant::worldRegion(), $required, $selectAttributes);
2220 }
2221 elseif ($fieldName == 'signature_html') {
2222 $form->add('wysiwyg', $name, $title, CRM_Core_DAO::getAttribute('CRM_Core_DAO_Email', $fieldName));
2223 }
2224 elseif ($fieldName == 'signature_text') {
2225 $form->add('textarea', $name, $title, CRM_Core_DAO::getAttribute('CRM_Core_DAO_Email', $fieldName));
2226 }
2227 elseif (substr($fieldName, -11) == 'campaign_id') {
2228 if (CRM_Campaign_BAO_Campaign::isCampaignEnable()) {
2229 $campaigns = CRM_Campaign_BAO_Campaign::getCampaigns(CRM_Utils_Array::value($contactId,
2230 $form->_componentCampaigns
2231 ));
2232 $form->add('select', $name, $title,
2233 array(
2234 '' => ts('- select -'),
2235 ) + $campaigns, $required, 'class="crm-select2 big"'
2236 );
2237 }
2238 }
2239 elseif ($fieldName == 'activity_details') {
2240 $form->add('wysiwyg', $fieldName, $title, array('rows' => 4, 'cols' => 60), $required);
2241 }
2242 elseif ($fieldName == 'activity_duration') {
2243 $form->add('text', $name, $title, $attributes, $required);
2244 $form->addRule($name, ts('Please enter the duration as number of minutes (integers only).'), 'positiveInteger');
2245 }
2246 elseif ($fieldName == 'case_status') {
2247 $form->add('select', $name, $title,
2248 array(
2249 '' => ts('- select -'),
2250 ) + CRM_Case_BAO_Case::buildOptions('case_status_id', 'create'),
2251 $required
2252 );
2253 }
2254 else {
2255 if (substr($fieldName, 0, 3) === 'is_' or substr($fieldName, 0, 7) === 'do_not_') {
2256 $form->add('advcheckbox', $name, $title, $attributes, $required);
2257 }
2258 elseif (CRM_Utils_Array::value('html_type', $field) === 'Select Date') {
2259 $extra = isset($field['datepicker']) ? $field['datepicker']['extra'] : CRM_Utils_Date::getDatePickerExtra($field);
2260 $attributes = isset($field['datepicker']) ? $field['datepicker']['attributes'] : CRM_Utils_Date::getDatePickerAttributes($field);
2261 $form->add('datepicker', $name, $title, $attributes, $required, $extra);
2262 }
2263 else {
2264 $form->add('text', $name, $title, $attributes, $required);
2265 }
2266 }
2267
2268 static $hiddenSubtype = FALSE;
2269 if (!$hiddenSubtype && CRM_Contact_BAO_ContactType::isaSubType($field['field_type'])) {
2270 // In registration mode params are submitted via POST and we don't have any clue
2271 // about profile-id or the profile-type (which could be a subtype)
2272 // To generalize the behavior and simplify the process,
2273 // lets always add the hidden
2274 //subtype value if there is any, and we won't have to
2275 // compute it while processing.
2276 if ($usedFor) {
2277 $form->addElement('hidden', $usedFor . '[contact_sub_type]', $field['field_type']);
2278 }
2279 else {
2280 $form->addElement('hidden', 'contact_sub_type_hidden', $field['field_type']);
2281 }
2282 $hiddenSubtype = TRUE;
2283 }
2284
2285 if (($view && $mode != CRM_Profile_Form::MODE_SEARCH) || $isShared) {
2286 $form->freeze($name);
2287 }
2288
2289 //add the rules
2290 if (in_array($fieldName, array(
2291 'non_deductible_amount',
2292 'total_amount',
2293 'fee_amount',
2294 'net_amount',
2295 ))) {
2296 $form->addRule($name, ts('Please enter a valid amount.'), 'money');
2297 }
2298 if ($rule) {
2299 if (!($rule == 'email' && $mode == CRM_Profile_Form::MODE_SEARCH)) {
2300 $form->addRule($name, ts('Please enter a valid %1', array(1 => $title)), $rule);
2301 }
2302 }
2303 }
2304
2305 /**
2306 * Set profile defaults.
2307 *
2308 * @param int $contactId
2309 * Contact id.
2310 * @param array $fields
2311 * Associative array of fields.
2312 * @param array $defaults
2313 * Defaults array.
2314 * @param bool $singleProfile
2315 * True for single profile else false(Update multiple items).
2316 * @param int $componentId
2317 * Id for specific components like contribute, event etc.
2318 * @param null $component
2319 */
2320 public static function setProfileDefaults(
2321 $contactId, &$fields, &$defaults,
2322 $singleProfile = TRUE, $componentId = NULL, $component = NULL
2323 ) {
2324 if (!$componentId) {
2325 //get the contact details
2326 list($contactDetails, $options) = CRM_Contact_BAO_Contact::getHierContactDetails($contactId, $fields);
2327 $details = CRM_Utils_Array::value($contactId, $contactDetails);
2328 $multipleFields = array('website' => 'url');
2329
2330 //start of code to set the default values
2331 foreach ($fields as $name => $field) {
2332 // skip pseudo fields
2333 if (substr($name, 0, 9) == 'phone_ext') {
2334 continue;
2335 }
2336
2337 //set the field name depending upon the profile mode(single/multiple)
2338 if ($singleProfile) {
2339 $fldName = $name;
2340 }
2341 else {
2342 $fldName = "field[$contactId][$name]";
2343 }
2344
2345 if ($name == 'group') {
2346 CRM_Contact_Form_Edit_TagsAndGroups::setDefaults($contactId, $defaults, CRM_Contact_Form_Edit_TagsAndGroups::GROUP, $fldName);
2347 }
2348 if ($name == 'tag') {
2349 CRM_Contact_Form_Edit_TagsAndGroups::setDefaults($contactId, $defaults, CRM_Contact_Form_Edit_TagsAndGroups::TAG, $fldName);
2350 }
2351
2352 if (!empty($details[$name]) || isset($details[$name])) {
2353 //to handle custom data (checkbox) to be written
2354 // to handle birth/deceased date, greeting_type and few other fields
2355 if (in_array($name, CRM_Contact_BAO_Contact::$_greetingTypes)) {
2356 $defaults[$fldName] = $details[$name . '_id'];
2357 $defaults[$name . '_custom'] = $details[$name . '_custom'];
2358 }
2359 elseif ($name == 'preferred_communication_method') {
2360 $v = $details[$name];
2361 if (!is_array($details[$name])) {
2362 $v = explode(CRM_Core_DAO::VALUE_SEPARATOR, $v);
2363 }
2364 foreach ($v as $item) {
2365 if ($item) {
2366 $defaults[$fldName . "[$item]"] = 1;
2367 }
2368 }
2369 }
2370 elseif ($name == 'contact_sub_type') {
2371 $defaults[$fldName] = explode(CRM_Core_DAO::VALUE_SEPARATOR, trim($details[$name], CRM_Core_DAO::VALUE_SEPARATOR));
2372 }
2373 elseif ($name == 'world_region') {
2374 $defaults[$fldName] = $details['worldregion_id'];
2375 }
2376 elseif ($customFieldId = CRM_Core_BAO_CustomField::getKeyID($name)) {
2377 // @todo retrieving the custom fields here seems obsolete - $field holds more data for the fields.
2378 $customFields = CRM_Core_BAO_CustomField::getFields(CRM_Utils_Array::value('contact_type', $details));
2379
2380 // hack to add custom data for components
2381 $components = array('Contribution', 'Participant', 'Membership', 'Activity');
2382 foreach ($components as $value) {
2383 $customFields = CRM_Utils_Array::crmArrayMerge($customFields,
2384 CRM_Core_BAO_CustomField::getFieldsForImport($value)
2385 );
2386 }
2387
2388 switch ($customFields[$customFieldId]['html_type']) {
2389 case 'Multi-Select State/Province':
2390 case 'Multi-Select Country':
2391 case 'AdvMulti-Select':
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_OptionGroup::getValue('custom_data_type', $customGroups->extends_entity_column_id, 'value', 'String', 'name');
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 * @param array|string $profiles - name of profile(s) to create links for
3327 * @param array $appendProfiles
3328 * Name of profile(s) to append to each link.
3329 *
3330 * @return array
3331 */
3332 public static function getCreateLinks($profiles = '', $appendProfiles = array()) {
3333 // Default to contact profiles
3334 if (!$profiles) {
3335 $profiles = array('new_individual', 'new_organization', 'new_household');
3336 }
3337 $profiles = (array) $profiles;
3338 $toGet = array_merge($profiles, (array) $appendProfiles);
3339 $retrieved = civicrm_api3('uf_group', 'get', array(
3340 'name' => array('IN' => $toGet),
3341 'is_active' => 1,
3342 ));
3343 $links = $append = array();
3344 if (!empty($retrieved['values'])) {
3345 foreach ($retrieved['values'] as $id => $profile) {
3346 if (in_array($profile['name'], $profiles)) {
3347 $links[] = array(
3348 'label' => $profile['title'],
3349 'url' => CRM_Utils_System::url('civicrm/profile/create', "reset=1&context=dialog&gid=$id",
3350 NULL, NULL, FALSE, FALSE, TRUE),
3351 'type' => ucfirst(str_replace('new_', '', $profile['name'])),
3352 );
3353 }
3354 else {
3355 $append[] = $id;
3356 }
3357 }
3358 foreach ($append as $id) {
3359 foreach ($links as &$link) {
3360 $link['url'] .= ",$id";
3361 }
3362 }
3363 }
3364 return $links;
3365 }
3366
3367 /**
3368 * Retrieve groups of profiles.
3369 *
3370 * @param int $profileID
3371 * Id of the profile.
3372 *
3373 * @return array
3374 * returns array
3375 */
3376 public static function profileGroups($profileID) {
3377 $groupTypes = array();
3378 $profileTypes = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_UFGroup', $profileID, 'group_type');
3379 if ($profileTypes) {
3380 $groupTypeParts = explode(CRM_Core_DAO::VALUE_SEPARATOR, $profileTypes);
3381 $groupTypes = explode(',', $groupTypeParts[0]);
3382 }
3383 return $groupTypes;
3384 }
3385
3386 /**
3387 * Alter contact params by filtering existing subscribed groups and returns
3388 * unsubscribed groups array for subscription.
3389 *
3390 * @param array $params
3391 * Contact params.
3392 * @param int $contactId
3393 * User contact id.
3394 *
3395 * @return array
3396 * This contains array of groups for subscription
3397 */
3398 public static function getDoubleOptInGroupIds(&$params, $contactId = NULL) {
3399 $config = CRM_Core_Config::singleton();
3400 $subscribeGroupIds = array();
3401
3402 // process further only if profileDoubleOptIn enabled and if groups exist
3403 if (!array_key_exists('group', $params) ||
3404 !self::isProfileDoubleOptin() ||
3405 CRM_Utils_System::isNull($params['group'])
3406 ) {
3407 return $subscribeGroupIds;
3408 }
3409
3410 //check if contact email exist.
3411 $hasEmails = FALSE;
3412 foreach ($params as $name => $value) {
3413 if (strpos($name, 'email-') !== FALSE) {
3414 $hasEmails = TRUE;
3415 break;
3416 }
3417 }
3418
3419 //Proceed furthur only if email present
3420 if (!$hasEmails) {
3421 return $subscribeGroupIds;
3422 }
3423
3424 //do check for already subscriptions.
3425 $contactGroups = array();
3426 if ($contactId) {
3427 $query = "
3428 SELECT group_id
3429 FROM civicrm_group_contact
3430 WHERE status = 'Added'
3431 AND contact_id = %1";
3432
3433 $dao = CRM_Core_DAO::executeQuery($query, array(1 => array($contactId, 'Integer')));
3434 while ($dao->fetch()) {
3435 $contactGroups[$dao->group_id] = $dao->group_id;
3436 }
3437 }
3438
3439 //since we don't have names, compare w/ label.
3440 $mailingListGroupType = array_search('Mailing List', CRM_Core_OptionGroup::values('group_type'));
3441
3442 //actual processing start.
3443 foreach ($params['group'] as $groupId => $isSelected) {
3444 //unset group those are not selected.
3445 if (!$isSelected) {
3446 unset($params['group'][$groupId]);
3447 continue;
3448 }
3449
3450 $groupTypes = explode(CRM_Core_DAO::VALUE_SEPARATOR,
3451 CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Group', $groupId, 'group_type', 'id')
3452 );
3453 //get only mailing type group and unset it from params
3454 if (in_array($mailingListGroupType, $groupTypes) && !in_array($groupId, $contactGroups)) {
3455 $subscribeGroupIds[$groupId] = $groupId;
3456 unset($params['group'][$groupId]);
3457 }
3458 }
3459
3460 return $subscribeGroupIds;
3461 }
3462
3463 /**
3464 * Check if we are rendering mixed profiles.
3465 *
3466 * @param array $profileIds
3467 * Associated array of profile ids.
3468 *
3469 * @return bool
3470 * true if profile is mixed
3471 */
3472 public static function checkForMixProfiles($profileIds) {
3473 $mixProfile = FALSE;
3474
3475 $contactTypes = array('Individual', 'Household', 'Organization');
3476 $subTypes = CRM_Contact_BAO_ContactType::subTypes();
3477
3478 $components = array('Contribution', 'Participant', 'Membership', 'Activity');
3479
3480 $typeCount = array('ctype' => array(), 'subtype' => array());
3481 foreach ($profileIds as $gid) {
3482 $profileType = CRM_Core_BAO_UFField::getProfileType($gid);
3483 // ignore profile of type Contact
3484 if ($profileType == 'Contact') {
3485 continue;
3486 }
3487 if (in_array($profileType, $contactTypes)) {
3488 if (!isset($typeCount['ctype'][$profileType])) {
3489 $typeCount['ctype'][$profileType] = 1;
3490 }
3491
3492 // check if we are rendering profile of different contact types
3493 if (count($typeCount['ctype']) == 2) {
3494 $mixProfile = TRUE;
3495 break;
3496 }
3497 }
3498 elseif (in_array($profileType, $components)) {
3499 $mixProfile = TRUE;
3500 break;
3501 }
3502 else {
3503 if (!isset($typeCount['subtype'][$profileType])) {
3504 $typeCount['subtype'][$profileType] = 1;
3505 }
3506 // check if we are rendering profile of different contact sub types
3507 if (count($typeCount['subtype']) == 2) {
3508 $mixProfile = TRUE;
3509 break;
3510 }
3511 }
3512 }
3513 return $mixProfile;
3514 }
3515
3516 /**
3517 * Determine of we show overlay profile or not.
3518 *
3519 * @return bool
3520 * true if profile should be shown else false
3521 */
3522 public static function showOverlayProfile() {
3523 $showOverlay = TRUE;
3524
3525 // get the id of overlay profile
3526 $overlayProfileId = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_UFGroup', 'summary_overlay', 'id', 'name');
3527 $query = "SELECT count(id) FROM civicrm_uf_field WHERE uf_group_id = {$overlayProfileId} AND visibility IN ('Public Pages', 'Public Pages and Listings') ";
3528
3529 $count = CRM_Core_DAO::singleValueQuery($query);
3530
3531 //check if there are no public fields and use is anonymous
3532 $session = CRM_Core_Session::singleton();
3533 if (!$count && !$session->get('userID')) {
3534 $showOverlay = FALSE;
3535 }
3536
3537 return $showOverlay;
3538 }
3539
3540 /**
3541 * Get group type values of the profile.
3542 *
3543 * @param int $profileId
3544 * @param string $groupType
3545 *
3546 * @return array
3547 * group type values
3548 */
3549 public static function groupTypeValues($profileId, $groupType = NULL) {
3550 $groupTypeValue = array();
3551 $groupTypes = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_UFGroup', $profileId, 'group_type');
3552
3553 $groupTypeParts = explode(CRM_Core_DAO::VALUE_SEPARATOR, $groupTypes);
3554 if (empty($groupTypeParts[1])) {
3555 return $groupTypeValue;
3556 }
3557 $participantExtends = array('ParticipantRole', 'ParticipantEventName', 'ParticipantEventType');
3558
3559 foreach (explode(',', $groupTypeParts[1]) as $groupTypeValues) {
3560 $values = array();
3561 $valueParts = explode(':', $groupTypeValues);
3562 if ($groupType &&
3563 ($valueParts[0] != "{$groupType}Type" ||
3564 ($groupType == 'Participant' &&
3565 !in_array($valueParts[0], $participantExtends)
3566 )
3567 )
3568 ) {
3569 continue;
3570 }
3571 foreach ($valueParts as $val) {
3572 if (CRM_Utils_Rule::integer($val)) {
3573 $values[$val] = $val;
3574 }
3575 }
3576 if (!empty($values)) {
3577 $typeName = substr($valueParts[0], 0, -4);
3578 if (in_array($valueParts[0], $participantExtends)) {
3579 $typeName = $valueParts[0];
3580 }
3581 $groupTypeValue[$typeName] = $values;
3582 }
3583 }
3584
3585 return $groupTypeValue;
3586 }
3587
3588 /**
3589 * @return bool|object
3590 */
3591 public static function isProfileDoubleOptin() {
3592 // check for double optin
3593 $config = CRM_Core_Config::singleton();
3594 if (in_array('CiviMail', $config->enableComponents)) {
3595 return Civi::settings()->get('profile_double_optin');
3596 }
3597 return FALSE;
3598 }
3599
3600 /**
3601 * @return bool|object
3602 */
3603 public static function isProfileAddToGroupDoubleOptin() {
3604 // check for add to group double optin
3605 $config = CRM_Core_Config::singleton();
3606 if (in_array('CiviMail', $config->enableComponents)) {
3607 return Civi::settings()->get('profile_add_to_group_double_optin');
3608 }
3609 return FALSE;
3610 }
3611
3612 /**
3613 * Get profiles used for batch entry.
3614 *
3615 * @return array
3616 * profileIds profile ids
3617 */
3618 public static function getBatchProfiles() {
3619 $query = "SELECT id
3620 FROM civicrm_uf_group
3621 WHERE name IN ('contribution_batch_entry', 'membership_batch_entry')";
3622 $dao = CRM_Core_DAO::executeQuery($query);
3623 $profileIds = array();
3624 while ($dao->fetch()) {
3625 $profileIds[$dao->id] = $dao->id;
3626 }
3627 return $profileIds;
3628 }
3629
3630 /**
3631 * @todo what do I do?
3632 * @param $source
3633 * @param $destination
3634 * @param bool $returnMultiSummaryFields
3635 *
3636 * @return array|null
3637 */
3638 public static function shiftMultiRecordFields(&$source, &$destination, $returnMultiSummaryFields = FALSE) {
3639 $multiSummaryFields = $returnMultiSummaryFields ? array() : NULL;
3640 foreach ($source as $field => $properties) {
3641 if (!CRM_Core_BAO_CustomField::getKeyID($field)) {
3642 continue;
3643 }
3644 if (CRM_Core_BAO_CustomField::isMultiRecordField($field)) {
3645 $destination[$field] = $properties;
3646 if ($returnMultiSummaryFields) {
3647 if ($properties['is_multi_summary']) {
3648 $multiSummaryFields[$field] = $properties;
3649 }
3650 }
3651 unset($source[$field]);
3652 }
3653 }
3654 return $multiSummaryFields;
3655 }
3656
3657 /**
3658 * This is function is used to format pseudo fields.
3659 *
3660 * @param array $fields
3661 * Associated array of profile fields.
3662 *
3663 */
3664 public static function reformatProfileFields(&$fields) {
3665 //reformat fields array
3666 foreach ($fields as $name => $field) {
3667 //reformat phone and extension field
3668 if (substr($field['name'], 0, 13) == 'phone_and_ext') {
3669 $fieldSuffix = str_replace('phone_and_ext-', '', $field['name']);
3670
3671 // retain existing element properties and just update and replace key
3672 CRM_Utils_Array::crmReplaceKey($fields, $name, "phone-{$fieldSuffix}");
3673 $fields["phone-{$fieldSuffix}"]['name'] = "phone-{$fieldSuffix}";
3674 $fields["phone-{$fieldSuffix}"]['where'] = 'civicrm_phone.phone';
3675
3676 // add additional phone extension field
3677 $fields["phone_ext-{$fieldSuffix}"] = $field;
3678 $fields["phone_ext-{$fieldSuffix}"]['title'] = $field['title'] . ' - ' . ts('Ext.');
3679 $fields["phone_ext-{$fieldSuffix}"]['name'] = "phone_ext-{$fieldSuffix}";
3680 $fields["phone_ext-{$fieldSuffix}"]['where'] = 'civicrm_phone.phone_ext';
3681 $fields["phone_ext-{$fieldSuffix}"]['skipDisplay'] = 1;
3682 //ignore required for extension field
3683 $fields["phone_ext-{$fieldSuffix}"]['is_required'] = 0;
3684 }
3685 }
3686 }
3687
3688 }