Merge pull request #11163 from mickadoo/CRM-21334-fire-hooks-on-contact-image-deletion
[civicrm-core.git] / CRM / Core / BAO / UFGroup.php
1 <?php
2 /*
3 +--------------------------------------------------------------------+
4 | CiviCRM version 4.7 |
5 +--------------------------------------------------------------------+
6 | Copyright CiviCRM LLC (c) 2004-2017 |
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-2017
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_OptionGroup::getValue('soft_credit_type', 'Gift', 'name');
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 else {
2247 if (substr($fieldName, 0, 3) === 'is_' or substr($fieldName, 0, 7) === 'do_not_') {
2248 $form->add('advcheckbox', $name, $title, $attributes, $required);
2249 }
2250 elseif (CRM_Utils_Array::value('html_type', $field) === 'Select Date') {
2251 $extra = isset($field['datepicker']) ? $field['datepicker']['extra'] : CRM_Utils_Date::getDatePickerExtra($field);
2252 $attributes = isset($field['datepicker']) ? $field['datepicker']['attributes'] : CRM_Utils_Date::getDatePickerAttributes($field);
2253 $form->add('datepicker', $name, $title, $attributes, $required, $extra);
2254 }
2255 else {
2256 $form->add('text', $name, $title, $attributes, $required);
2257 }
2258 }
2259
2260 static $hiddenSubtype = FALSE;
2261 if (!$hiddenSubtype && CRM_Contact_BAO_ContactType::isaSubType($field['field_type'])) {
2262 // In registration mode params are submitted via POST and we don't have any clue
2263 // about profile-id or the profile-type (which could be a subtype)
2264 // To generalize the behavior and simplify the process,
2265 // lets always add the hidden
2266 //subtype value if there is any, and we won't have to
2267 // compute it while processing.
2268 if ($usedFor) {
2269 $form->addElement('hidden', $usedFor . '[contact_sub_type]', $field['field_type']);
2270 }
2271 else {
2272 $form->addElement('hidden', 'contact_sub_type_hidden', $field['field_type']);
2273 }
2274 $hiddenSubtype = TRUE;
2275 }
2276
2277 if (($view && $mode != CRM_Profile_Form::MODE_SEARCH) || $isShared) {
2278 $form->freeze($name);
2279 }
2280
2281 //add the rules
2282 if (in_array($fieldName, array(
2283 'non_deductible_amount',
2284 'total_amount',
2285 'fee_amount',
2286 'net_amount',
2287 ))) {
2288 $form->addRule($name, ts('Please enter a valid amount.'), 'money');
2289 }
2290 if ($rule) {
2291 if (!($rule == 'email' && $mode == CRM_Profile_Form::MODE_SEARCH)) {
2292 $form->addRule($name, ts('Please enter a valid %1', array(1 => $title)), $rule);
2293 }
2294 }
2295 }
2296
2297 /**
2298 * Set profile defaults.
2299 *
2300 * @param int $contactId
2301 * Contact id.
2302 * @param array $fields
2303 * Associative array of fields.
2304 * @param array $defaults
2305 * Defaults array.
2306 * @param bool $singleProfile
2307 * True for single profile else false(Update multiple items).
2308 * @param int $componentId
2309 * Id for specific components like contribute, event etc.
2310 * @param null $component
2311 */
2312 public static function setProfileDefaults(
2313 $contactId, &$fields, &$defaults,
2314 $singleProfile = TRUE, $componentId = NULL, $component = NULL
2315 ) {
2316 if (!$componentId) {
2317 //get the contact details
2318 list($contactDetails, $options) = CRM_Contact_BAO_Contact::getHierContactDetails($contactId, $fields);
2319 $details = CRM_Utils_Array::value($contactId, $contactDetails);
2320 $multipleFields = array('website' => 'url');
2321
2322 //start of code to set the default values
2323 foreach ($fields as $name => $field) {
2324 // skip pseudo fields
2325 if (substr($name, 0, 9) == 'phone_ext') {
2326 continue;
2327 }
2328
2329 //set the field name depending upon the profile mode(single/multiple)
2330 if ($singleProfile) {
2331 $fldName = $name;
2332 }
2333 else {
2334 $fldName = "field[$contactId][$name]";
2335 }
2336
2337 if ($name == 'group') {
2338 CRM_Contact_Form_Edit_TagsAndGroups::setDefaults($contactId, $defaults, CRM_Contact_Form_Edit_TagsAndGroups::GROUP, $fldName);
2339 }
2340 if ($name == 'tag') {
2341 CRM_Contact_Form_Edit_TagsAndGroups::setDefaults($contactId, $defaults, CRM_Contact_Form_Edit_TagsAndGroups::TAG, $fldName);
2342 }
2343
2344 if (!empty($details[$name]) || isset($details[$name])) {
2345 //to handle custom data (checkbox) to be written
2346 // to handle birth/deceased date, greeting_type and few other fields
2347 if (in_array($name, CRM_Contact_BAO_Contact::$_greetingTypes)) {
2348 $defaults[$fldName] = $details[$name . '_id'];
2349 $defaults[$name . '_custom'] = $details[$name . '_custom'];
2350 }
2351 elseif ($name == 'preferred_communication_method') {
2352 $v = $details[$name];
2353 if (!is_array($details[$name])) {
2354 $v = explode(CRM_Core_DAO::VALUE_SEPARATOR, $v);
2355 }
2356 foreach ($v as $item) {
2357 if ($item) {
2358 $defaults[$fldName . "[$item]"] = 1;
2359 }
2360 }
2361 }
2362 elseif ($name == 'contact_sub_type') {
2363 $defaults[$fldName] = explode(CRM_Core_DAO::VALUE_SEPARATOR, trim($details[$name], CRM_Core_DAO::VALUE_SEPARATOR));
2364 }
2365 elseif ($name == 'world_region') {
2366 $defaults[$fldName] = $details['worldregion_id'];
2367 }
2368 elseif ($customFieldId = CRM_Core_BAO_CustomField::getKeyID($name)) {
2369 // @todo retrieving the custom fields here seems obsolete - $field holds more data for the fields.
2370 $customFields = CRM_Core_BAO_CustomField::getFields(CRM_Utils_Array::value('contact_type', $details));
2371
2372 // hack to add custom data for components
2373 $components = array('Contribution', 'Participant', 'Membership', 'Activity');
2374 foreach ($components as $value) {
2375 $customFields = CRM_Utils_Array::crmArrayMerge($customFields,
2376 CRM_Core_BAO_CustomField::getFieldsForImport($value)
2377 );
2378 }
2379
2380 switch ($customFields[$customFieldId]['html_type']) {
2381 case 'Multi-Select State/Province':
2382 case 'Multi-Select Country':
2383 case 'AdvMulti-Select':
2384 case 'Multi-Select':
2385 $v = explode(CRM_Core_DAO::VALUE_SEPARATOR, $details[$name]);
2386 foreach ($v as $item) {
2387 if ($item) {
2388 $defaults[$fldName][$item] = $item;
2389 }
2390 }
2391 break;
2392
2393 case 'CheckBox':
2394 $v = explode(CRM_Core_DAO::VALUE_SEPARATOR, $details[$name]);
2395 foreach ($v as $item) {
2396 if ($item) {
2397 $defaults[$fldName][$item] = 1;
2398 // seems like we need this for QF style checkboxes in profile where its multiindexed
2399 // CRM-2969
2400 $defaults["{$fldName}[{$item}]"] = 1;
2401 }
2402 }
2403 break;
2404
2405 default:
2406 $defaults[$fldName] = $details[$name];
2407 break;
2408 }
2409 }
2410 else {
2411 $defaults[$fldName] = $details[$name];
2412 }
2413 }
2414 else {
2415 $blocks = array('email', 'phone', 'im', 'openid');
2416 list($fieldName, $locTypeId, $phoneTypeId) = CRM_Utils_System::explode('-', $name, 3);
2417 if (!in_array($fieldName, $multipleFields)) {
2418 if (is_array($details)) {
2419 foreach ($details as $key => $value) {
2420 // when we fixed CRM-5319 - get primary loc
2421 // type as per loc field and removed below code.
2422 $primaryLocationType = FALSE;
2423 if ($locTypeId == 'Primary') {
2424 if (is_array($value) && array_key_exists($fieldName, $value)) {
2425 $primaryLocationType = TRUE;
2426 if (in_array($fieldName, $blocks)) {
2427 $locTypeId = CRM_Contact_BAO_Contact::getPrimaryLocationType($contactId, FALSE, $fieldName);
2428 }
2429 else {
2430 $locTypeId = CRM_Contact_BAO_Contact::getPrimaryLocationType($contactId, FALSE, 'address');
2431 }
2432 }
2433 }
2434
2435 // fixed for CRM-665
2436 if (is_numeric($locTypeId)) {
2437 if ($primaryLocationType || $locTypeId == CRM_Utils_Array::value('location_type_id', $value)) {
2438 if (!empty($value[$fieldName])) {
2439 //to handle stateprovince and country
2440 if ($fieldName == 'state_province') {
2441 $defaults[$fldName] = $value['state_province_id'];
2442 }
2443 elseif ($fieldName == 'county') {
2444 $defaults[$fldName] = $value['county_id'];
2445 }
2446 elseif ($fieldName == 'country') {
2447 if (!isset($value['country_id']) || !$value['country_id']) {
2448 $config = CRM_Core_Config::singleton();
2449 if ($config->defaultContactCountry) {
2450 $defaults[$fldName] = $config->defaultContactCountry;
2451 }
2452 }
2453 else {
2454 $defaults[$fldName] = $value['country_id'];
2455 }
2456 }
2457 elseif ($fieldName == 'phone') {
2458 if ($phoneTypeId) {
2459 if (isset($value['phone'][$phoneTypeId])) {
2460 $defaults[$fldName] = $value['phone'][$phoneTypeId];
2461 }
2462 if (isset($value['phone_ext'][$phoneTypeId])) {
2463 $defaults[str_replace('phone', 'phone_ext', $fldName)] = $value['phone_ext'][$phoneTypeId];
2464 }
2465 }
2466 else {
2467 $phoneDefault = CRM_Utils_Array::value('phone', $value);
2468 // CRM-9216
2469 if (!is_array($phoneDefault)) {
2470 $defaults[$fldName] = $phoneDefault;
2471 }
2472 }
2473 }
2474 elseif ($fieldName == 'email') {
2475 //adding the first email (currently we don't support multiple emails of same location type)
2476 $defaults[$fldName] = $value['email'];
2477 }
2478 elseif ($fieldName == 'im') {
2479 //adding the first im (currently we don't support multiple ims of same location type)
2480 $defaults[$fldName] = $value['im'];
2481 $defaults[$fldName . '-provider_id'] = $value['im_provider_id'];
2482 }
2483 else {
2484 $defaults[$fldName] = $value[$fieldName];
2485 }
2486 }
2487 elseif (substr($fieldName, 0, 14) === 'address_custom' &&
2488 CRM_Utils_Array::value(substr($fieldName, 8), $value)
2489 ) {
2490 $defaults[$fldName] = $value[substr($fieldName, 8)];
2491 }
2492 }
2493 }
2494 }
2495 }
2496 }
2497 else {
2498 if (is_array($details)) {
2499 if ($fieldName === 'url'
2500 && !empty($details['website'])
2501 && !empty($details['website'][$locTypeId])
2502 ) {
2503 $defaults[$fldName] = CRM_Utils_Array::value('url', $details['website'][$locTypeId]);
2504 }
2505 }
2506 }
2507 }
2508 }
2509 }
2510
2511 //Handling Contribution Part of the batch profile
2512 if (CRM_Core_Permission::access('CiviContribute') && $component == 'Contribute') {
2513 self::setComponentDefaults($fields, $componentId, $component, $defaults);
2514 }
2515
2516 //Handling Event Participation Part of the batch profile
2517 if (CRM_Core_Permission::access('CiviEvent') && $component == 'Event') {
2518 self::setComponentDefaults($fields, $componentId, $component, $defaults);
2519 }
2520
2521 //Handling membership Part of the batch profile
2522 if (CRM_Core_Permission::access('CiviMember') && $component == 'Membership') {
2523 self::setComponentDefaults($fields, $componentId, $component, $defaults);
2524 }
2525
2526 //Handling Activity Part of the batch profile
2527 if ($component == 'Activity') {
2528 self::setComponentDefaults($fields, $componentId, $component, $defaults);
2529 }
2530 }
2531
2532 /**
2533 * Get profiles by type eg: pure Individual etc
2534 *
2535 * @param array $types
2536 * Associative array of types eg: types('Individual').
2537 * @param bool $onlyPure
2538 * True if only pure profiles are required.
2539 *
2540 * @return array
2541 * associative array of profiles
2542 */
2543 public static function getProfiles($types, $onlyPure = FALSE) {
2544 $profiles = array();
2545 $ufGroups = CRM_Core_PseudoConstant::get('CRM_Core_DAO_UFField', 'uf_group_id');
2546
2547 CRM_Utils_Hook::aclGroup(CRM_Core_Permission::ADMIN, NULL, 'civicrm_uf_group', $ufGroups, $ufGroups);
2548
2549 // Exclude Batch Data Entry profiles - CRM-10901
2550 $batchProfiles = CRM_Core_BAO_UFGroup::getBatchProfiles();
2551
2552 foreach ($ufGroups as $id => $title) {
2553 $ptype = CRM_Core_BAO_UFField::getProfileType($id, FALSE, $onlyPure);
2554 if (in_array($ptype, $types) && !array_key_exists($id, $batchProfiles)) {
2555 $profiles[$id] = $title;
2556 }
2557 }
2558 return $profiles;
2559 }
2560
2561 /**
2562 * Check whether a profile is valid combination of
2563 * required and/or optional profile types
2564 *
2565 * @param array $required
2566 * Array of types those are required.
2567 * @param array $optional
2568 * Array of types those are optional.
2569 *
2570 * @return array
2571 * associative array of profiles
2572 */
2573 public static function getValidProfiles($required, $optional = NULL) {
2574 if (!is_array($required) || empty($required)) {
2575 return NULL;
2576 }
2577
2578 $profiles = array();
2579 $ufGroups = CRM_Core_PseudoConstant::get('CRM_Core_DAO_UFField', 'uf_group_id');
2580
2581 CRM_Utils_Hook::aclGroup(CRM_Core_Permission::ADMIN, NULL, 'civicrm_uf_group', $ufGroups, $ufGroups);
2582
2583 foreach ($ufGroups as $id => $title) {
2584 $type = CRM_Core_BAO_UFField::checkValidProfileType($id, $required, $optional);
2585 if ($type) {
2586 $profiles[$id] = $title;
2587 }
2588 }
2589
2590 return $profiles;
2591 }
2592
2593 /**
2594 * Check whether a profile is valid combination of
2595 * required profile fields
2596 *
2597 * @param array $ufId
2598 * Integer id of the profile.
2599 * @param array $required
2600 * Array of fields those are required in the profile.
2601 *
2602 * @return array
2603 * associative array of profiles
2604 */
2605 public static function checkValidProfile($ufId, $required = NULL) {
2606 $validProfile = FALSE;
2607 if (!$ufId) {
2608 return $validProfile;
2609 }
2610
2611 if (!CRM_Core_DAO::getFieldValue('CRM_Core_DAO_UFGroup', $ufId, 'is_active')) {
2612 return $validProfile;
2613 }
2614
2615 $profileFields = self::getFields($ufId, FALSE, CRM_Core_Action::VIEW, NULL,
2616 NULL, FALSE, NULL, FALSE, NULL,
2617 CRM_Core_Permission::CREATE, NULL
2618 );
2619
2620 $validProfile = array();
2621 if (!empty($profileFields)) {
2622 $fields = array_keys($profileFields);
2623 foreach ($fields as $val) {
2624 foreach ($required as $key => $field) {
2625 if (strpos($val, $field) === 0) {
2626 unset($required[$key]);
2627 }
2628 }
2629 }
2630
2631 $validProfile = (empty($required)) ? TRUE : FALSE;
2632 }
2633
2634 return $validProfile;
2635 }
2636
2637 /**
2638 * Get default value for Register.
2639 *
2640 * @param array $fields
2641 * @param array $defaults
2642 *
2643 * @return array
2644 */
2645 public static function setRegisterDefaults(&$fields, &$defaults) {
2646 $config = CRM_Core_Config::singleton();
2647 foreach ($fields as $name => $field) {
2648 if (substr($name, 0, 8) == 'country-') {
2649 if (!empty($config->defaultContactCountry)) {
2650 $defaults[$name] = $config->defaultContactCountry;
2651 }
2652 }
2653 elseif (substr($name, 0, 15) == 'state_province-') {
2654 if (!empty($config->defaultContactStateProvince)) {
2655 $defaults[$name] = $config->defaultContactStateProvince;
2656 }
2657 }
2658 }
2659 return $defaults;
2660 }
2661
2662 /**
2663 * make a copy of a profile, including
2664 * all the fields in the profile
2665 *
2666 * @param int $id
2667 * The profile id to copy.
2668 *
2669 * @return \CRM_Core_DAO
2670 */
2671 public static function copy($id) {
2672 $maxId = CRM_Core_DAO::singleValueQuery("SELECT max(id) FROM civicrm_uf_group");
2673
2674 $title = ts('[Copy id %1]', array(1 => $maxId + 1));
2675 $fieldsFix = array(
2676 'suffix' => array(
2677 'title' => ' ' . $title,
2678 'name' => '__Copy_id_' . ($maxId + 1) . '_',
2679 ),
2680 );
2681
2682 $copy = &CRM_Core_DAO::copyGeneric('CRM_Core_DAO_UFGroup',
2683 array('id' => $id),
2684 NULL,
2685 $fieldsFix
2686 );
2687
2688 if ($pos = strrpos($copy->name, "_{$id}")) {
2689 $copy->name = substr_replace($copy->name, '', $pos);
2690 }
2691 $copy->name = CRM_Utils_String::munge($copy->name, '_', 56) . "_{$copy->id}";
2692 $copy->save();
2693
2694 $copyUFJoin = &CRM_Core_DAO::copyGeneric('CRM_Core_DAO_UFJoin',
2695 array('uf_group_id' => $id),
2696 array('uf_group_id' => $copy->id),
2697 NULL,
2698 'entity_table'
2699 );
2700
2701 $copyUFField = &CRM_Core_DAO::copyGeneric('CRM_Core_BAO_UFField',
2702 array('uf_group_id' => $id),
2703 array('uf_group_id' => $copy->id)
2704 );
2705
2706 $maxWeight = CRM_Utils_Weight::getMax('CRM_Core_DAO_UFJoin', NULL, 'weight');
2707
2708 //update the weight
2709 $query = "
2710 UPDATE civicrm_uf_join
2711 SET weight = %1
2712 WHERE uf_group_id = %2
2713 AND ( entity_id IS NULL OR entity_id <= 0 )
2714 ";
2715 $p = array(
2716 1 => array($maxWeight + 1, 'Integer'),
2717 2 => array($copy->id, 'Integer'),
2718 );
2719 CRM_Core_DAO::executeQuery($query, $p);
2720 if ($copy->is_reserved) {
2721 $query = "UPDATE civicrm_uf_group SET is_reserved = 0 WHERE id = %1";
2722 $params = array(1 => array($copy->id, 'Integer'));
2723 CRM_Core_DAO::executeQuery($query, $params);
2724 }
2725 CRM_Utils_Hook::copy('UFGroup', $copy);
2726
2727 return $copy;
2728 }
2729
2730 /**
2731 * Process that send notification e-mails
2732 *
2733 * @param int $contactID
2734 * Contact id.
2735 * @param array $values
2736 * Associative array of name/value pair.
2737 */
2738 public static function commonSendMail($contactID, &$values) {
2739 if (!$contactID || !$values) {
2740 return;
2741
2742 }
2743 $template = CRM_Core_Smarty::singleton();
2744
2745 $displayName = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact',
2746 $contactID,
2747 'display_name'
2748 );
2749
2750 self::profileDisplay($values['id'], $values['values'], $template);
2751 $emailList = explode(',', $values['email']);
2752
2753 $contactLink = CRM_Utils_System::url('civicrm/contact/view',
2754 "reset=1&cid=$contactID",
2755 TRUE, NULL, FALSE, FALSE, TRUE
2756 );
2757
2758 //get the default domain email address.
2759 list($domainEmailName, $domainEmailAddress) = CRM_Core_BAO_Domain::getNameAndEmail();
2760
2761 if (!$domainEmailAddress || $domainEmailAddress == 'info@EXAMPLE.ORG') {
2762 $fixUrl = CRM_Utils_System::url('civicrm/admin/domain', 'action=update&reset=1');
2763 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)));
2764 }
2765
2766 foreach ($emailList as $emailTo) {
2767 // FIXME: take the below out of the foreach loop
2768 CRM_Core_BAO_MessageTemplate::sendTemplate(
2769 array(
2770 'groupName' => 'msg_tpl_workflow_uf',
2771 'valueName' => 'uf_notify',
2772 'contactId' => $contactID,
2773 'tplParams' => array(
2774 'displayName' => $displayName,
2775 'currentDate' => date('r'),
2776 'contactLink' => $contactLink,
2777 ),
2778 'from' => "$domainEmailName <$domainEmailAddress>",
2779 'toEmail' => $emailTo,
2780 )
2781 );
2782 }
2783 }
2784
2785 /**
2786 * Given a contact id and a group id, returns the field values from the db
2787 * for this group and notify email only if group's notify field is
2788 * set and field values are not empty
2789 *
2790 * @param int $gid
2791 * Group id.
2792 * @param int $cid
2793 * Contact id.
2794 * @param array $params
2795 * @param bool $skipCheck
2796 *
2797 * @return array
2798 */
2799 public function checkFieldsEmptyValues($gid, $cid, $params, $skipCheck = FALSE) {
2800 if ($gid) {
2801 if (CRM_Core_BAO_UFGroup::filterUFGroups($gid, $cid) || $skipCheck) {
2802 $values = array();
2803 $fields = CRM_Core_BAO_UFGroup::getFields($gid, FALSE, CRM_Core_Action::VIEW);
2804 CRM_Core_BAO_UFGroup::getValues($cid, $fields, $values, FALSE, $params, TRUE);
2805
2806 $email = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_UFGroup', $gid, 'notify');
2807
2808 if (!empty($values) &&
2809 !empty($email)
2810 ) {
2811 $val = array(
2812 'id' => $gid,
2813 'values' => $values,
2814 'email' => $email,
2815 );
2816 return $val;
2817 }
2818 }
2819 }
2820 return NULL;
2821 }
2822
2823 /**
2824 * Assign uf fields to template.
2825 *
2826 * @param int $gid
2827 * Group id.
2828 * @param array $values
2829 * @param CRM_Core_Smarty $template
2830 */
2831 static public function profileDisplay($gid, $values, $template) {
2832 $groupTitle = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_UFGroup', $gid, 'title');
2833 $template->assign('grouptitle', $groupTitle);
2834 if (count($values)) {
2835 $template->assign('values', $values);
2836 }
2837 }
2838
2839 /**
2840 * Format fields for dupe Contact Matching.
2841 *
2842 * @param array $params
2843 *
2844 * @param int $contactId
2845 *
2846 * @return array
2847 * associated formatted array
2848 */
2849 public static function formatFields($params, $contactId = NULL) {
2850 if ($contactId) {
2851 // get the primary location type id and email
2852 list($name, $primaryEmail, $primaryLocationType) = CRM_Contact_BAO_Contact_Location::getEmailDetails($contactId);
2853 }
2854 else {
2855 $defaultLocationType = CRM_Core_BAO_LocationType::getDefault();
2856 $primaryLocationType = $defaultLocationType->id;
2857 }
2858
2859 $data = array();
2860 $locationType = array();
2861 $count = 1;
2862 $primaryLocation = 0;
2863 foreach ($params as $key => $value) {
2864 list($fieldName, $locTypeId, $phoneTypeId) = explode('-', $key);
2865
2866 if ($locTypeId == 'Primary') {
2867 $locTypeId = $primaryLocationType;
2868 }
2869
2870 if (is_numeric($locTypeId)) {
2871 if (!in_array($locTypeId, $locationType)) {
2872 $locationType[$count] = $locTypeId;
2873 $count++;
2874 }
2875 $loc = CRM_Utils_Array::key($locTypeId, $locationType);
2876
2877 $data['location'][$loc]['location_type_id'] = $locTypeId;
2878
2879 // if we are getting in a new primary email, dont overwrite the new one
2880 if ($locTypeId == $primaryLocationType) {
2881 if (!empty($params['email-' . $primaryLocationType])) {
2882 $data['location'][$loc]['email'][$loc]['email'] = $fields['email-' . $primaryLocationType];
2883 }
2884 elseif (isset($primaryEmail)) {
2885 $data['location'][$loc]['email'][$loc]['email'] = $primaryEmail;
2886 }
2887 $primaryLocation++;
2888 }
2889
2890 if ($loc == 1) {
2891 $data['location'][$loc]['is_primary'] = 1;
2892 }
2893 if ($fieldName == 'phone') {
2894 if ($phoneTypeId) {
2895 $data['location'][$loc]['phone'][$loc]['phone_type_id'] = $phoneTypeId;
2896 }
2897 else {
2898 $data['location'][$loc]['phone'][$loc]['phone_type_id'] = '';
2899 }
2900 $data['location'][$loc]['phone'][$loc]['phone'] = $value;
2901 }
2902 elseif ($fieldName == 'email') {
2903 $data['location'][$loc]['email'][$loc]['email'] = $value;
2904 }
2905 elseif ($fieldName == 'im') {
2906 $data['location'][$loc]['im'][$loc]['name'] = $value;
2907 }
2908 else {
2909 if ($fieldName === 'state_province') {
2910 $data['location'][$loc]['address']['state_province_id'] = $value;
2911 }
2912 elseif ($fieldName === 'country') {
2913 $data['location'][$loc]['address']['country_id'] = $value;
2914 }
2915 else {
2916 $data['location'][$loc]['address'][$fieldName] = $value;
2917 }
2918 }
2919 }
2920 else {
2921 // TODO: prefix, suffix and gender translation may no longer be necessary - check inputs
2922 if ($key === 'individual_suffix') {
2923 $data['suffix_id'] = $value;
2924 }
2925 elseif ($key === 'individual_prefix') {
2926 $data['prefix_id'] = $value;
2927 }
2928 elseif ($key === 'gender') {
2929 $data['gender_id'] = $value;
2930 }
2931 elseif (substr($key, 0, 6) === 'custom') {
2932 if ($customFieldID = CRM_Core_BAO_CustomField::getKeyID($key)) {
2933 //fix checkbox
2934 if ($customFields[$customFieldID]['html_type'] == 'CheckBox') {
2935 $value = implode(CRM_Core_DAO::VALUE_SEPARATOR, array_keys($value));
2936 }
2937 // fix the date field
2938 if ($customFields[$customFieldID]['data_type'] == 'Date') {
2939 $date = CRM_Utils_Date::format($value);
2940 if (!$date) {
2941 $date = '';
2942 }
2943 $value = $date;
2944 }
2945
2946 $data['custom'][$customFieldID] = array(
2947 'id' => $id,
2948 'value' => $value,
2949 'extends' => $customFields[$customFieldID]['extends'],
2950 'type' => $customFields[$customFieldID]['data_type'],
2951 'custom_field_id' => $customFieldID,
2952 );
2953 }
2954 }
2955 elseif ($key == 'edit') {
2956 continue;
2957 }
2958 else {
2959 $data[$key] = $value;
2960 }
2961 }
2962 }
2963
2964 if (!$primaryLocation) {
2965 $loc++;
2966 $data['location'][$loc]['email'][$loc]['email'] = $primaryEmail;
2967 }
2968
2969 return $data;
2970 }
2971
2972 /**
2973 * Calculate the profile type 'group_type' as per profile fields.
2974 *
2975 * @param int $gId
2976 * Profile id.
2977 * @param bool $includeTypeValues
2978 * @param int $ignoreFieldId
2979 * Ignore particular profile field.
2980 *
2981 * @return array
2982 * list of calculated group type
2983 */
2984 public static function calculateGroupType($gId, $includeTypeValues = FALSE, $ignoreFieldId = NULL) {
2985 //get the profile fields.
2986 $ufFields = self::getFields($gId, FALSE, NULL, NULL, NULL, TRUE, NULL, TRUE);
2987 return self::_calculateGroupType($ufFields, $includeTypeValues, $ignoreFieldId);
2988 }
2989
2990 /**
2991 * Calculate the profile type 'group_type' as per profile fields.
2992 *
2993 * @param $ufFields
2994 * @param bool $includeTypeValues
2995 * @param int $ignoreFieldId
2996 * Ignore perticular profile field.
2997 *
2998 * @return array
2999 * list of calculated group type
3000 */
3001 public static function _calculateGroupType($ufFields, $includeTypeValues = FALSE, $ignoreFieldId = NULL) {
3002 $groupType = $groupTypeValues = $customFieldIds = array();
3003 if (!empty($ufFields)) {
3004 foreach ($ufFields as $fieldName => $fieldValue) {
3005 //ignore field from group type when provided.
3006 //in case of update profile field.
3007 if ($ignoreFieldId && ($ignoreFieldId == $fieldValue['field_id'])) {
3008 continue;
3009 }
3010 if (!in_array($fieldValue['field_type'], $groupType)) {
3011 $groupType[$fieldValue['field_type']] = $fieldValue['field_type'];
3012 }
3013
3014 if ($includeTypeValues && ($fldId = CRM_Core_BAO_CustomField::getKeyID($fieldName))) {
3015 $customFieldIds[$fldId] = $fldId;
3016 }
3017 }
3018 }
3019
3020 if (!empty($customFieldIds)) {
3021 $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) . ')';
3022
3023 $customGroups = CRM_Core_DAO::executeQuery($query);
3024 while ($customGroups->fetch()) {
3025 if (!$customGroups->extends_entity_column_value) {
3026 continue;
3027 }
3028
3029 $groupTypeName = "{$customGroups->extends}Type";
3030 if ($customGroups->extends == 'Participant' && $customGroups->extends_entity_column_id) {
3031 $groupTypeName = CRM_Core_OptionGroup::getValue('custom_data_type', $customGroups->extends_entity_column_id, 'value', 'String', 'name');
3032 }
3033
3034 foreach (explode(CRM_Core_DAO::VALUE_SEPARATOR, $customGroups->extends_entity_column_value) as $val) {
3035 if ($val) {
3036 $groupTypeValues[$groupTypeName][$val] = $val;
3037 }
3038 }
3039 }
3040
3041 if (!empty($groupTypeValues)) {
3042 $groupType = array_merge($groupType, $groupTypeValues);
3043 }
3044 }
3045
3046 return $groupType;
3047 }
3048
3049 /**
3050 * Update the profile type 'group_type' as per profile fields including group types and group subtype values.
3051 * Build and store string like: group_type1,group_type2[VALUE_SEPERATOR]group_type1Type:1:2:3,group_type2Type:1:2
3052 *
3053 * FIELDS GROUP_TYPE
3054 * BirthDate + Email Individual,Contact
3055 * BirthDate + Subject Individual,Activity
3056 * BirthDate + Subject + SurveyOnlyField Individual,Activity\0ActivityType:28
3057 * BirthDate + Subject + SurveyOnlyField + PhoneOnlyField (Not allowed)
3058 * BirthDate + SurveyOnlyField Individual,Activity\0ActivityType:28
3059 * BirthDate + Subject + SurveyOrPhoneField Individual,Activity\0ActivityType:2:28
3060 * BirthDate + SurveyOrPhoneField Individual,Activity\0ActivityType:2:28
3061 * BirthDate + SurveyOrPhoneField + SurveyOnlyField Individual,Activity\0ActivityType:2:28
3062 * BirthDate + StudentField + Subject + SurveyOnlyField Individual,Activity,Student\0ActivityType:28
3063 *
3064 * @param int $gId
3065 * @param array $groupTypes
3066 * With key having group type names.
3067 *
3068 * @return bool
3069 */
3070 public static function updateGroupTypes($gId, $groupTypes = array()) {
3071 if (!is_array($groupTypes) || !$gId) {
3072 return FALSE;
3073 }
3074
3075 // If empty group types set group_type as 'null'
3076 if (empty($groupTypes)) {
3077 return CRM_Core_DAO::setFieldValue('CRM_Core_DAO_UFGroup', $gId, 'group_type', 'null');
3078 }
3079
3080 $componentGroupTypes = array('Contribution', 'Participant', 'Membership', 'Activity', 'Case');
3081 $validGroupTypes = array_merge(array(
3082 'Contact',
3083 'Individual',
3084 'Organization',
3085 'Household',
3086 ), $componentGroupTypes, CRM_Contact_BAO_ContactType::subTypes());
3087
3088 $gTypes = $gTypeValues = array();
3089
3090 $participantExtends = array('ParticipantRole', 'ParticipantEventName', 'ParticipantEventType');
3091 // Get valid group type and group subtypes
3092 foreach ($groupTypes as $groupType => $value) {
3093 if (in_array($groupType, $validGroupTypes) && !in_array($groupType, $gTypes)) {
3094 $gTypes[] = $groupType;
3095 }
3096
3097 $subTypesOf = NULL;
3098
3099 if (in_array($groupType, $participantExtends)) {
3100 $subTypesOf = $groupType;
3101 }
3102 elseif (strpos($groupType, 'Type') > 0) {
3103 $subTypesOf = substr($groupType, 0, strpos($groupType, 'Type'));
3104 }
3105 else {
3106 continue;
3107 }
3108
3109 if (!empty($value) &&
3110 (in_array($subTypesOf, $componentGroupTypes) ||
3111 in_array($subTypesOf, $participantExtends)
3112 )
3113 ) {
3114 $gTypeValues[$subTypesOf] = $groupType . ":" . implode(':', $value);
3115 }
3116 }
3117
3118 if (empty($gTypes)) {
3119 return FALSE;
3120 }
3121
3122 // Build String to store group types and group subtypes
3123 $groupTypeString = implode(',', $gTypes);
3124 if (!empty($gTypeValues)) {
3125 $groupTypeString .= CRM_Core_DAO::VALUE_SEPARATOR . implode(',', $gTypeValues);
3126 }
3127
3128 return CRM_Core_DAO::setFieldValue('CRM_Core_DAO_UFGroup', $gId, 'group_type', $groupTypeString);
3129 }
3130
3131 /**
3132 * Create a "group_type" string.
3133 *
3134 * @param array $coreTypes
3135 * E.g. array('Individual','Contact','Student').
3136 * @param array $subTypes
3137 * E.g. array('ActivityType' => array(7, 11)).
3138 * @param string $delim
3139 *
3140 * @return string
3141 * @throws CRM_Core_Exception
3142 */
3143 public static function encodeGroupType($coreTypes, $subTypes, $delim = CRM_Core_DAO::VALUE_SEPARATOR) {
3144 $groupTypeExpr = '';
3145 if ($coreTypes) {
3146 $groupTypeExpr .= implode(',', $coreTypes);
3147 }
3148 if ($subTypes) {
3149 //CRM-15427 Allow Multiple subtype filtering
3150 //if (count($subTypes) > 1) {
3151 //throw new CRM_Core_Exception("Multiple subtype filtering is not currently supported by widget.");
3152 //}
3153 foreach ($subTypes as $subType => $subTypeIds) {
3154 $groupTypeExpr .= $delim . $subType . ':' . implode(':', $subTypeIds);
3155 }
3156 }
3157 return $groupTypeExpr;
3158 }
3159
3160 /**
3161 * setDefault componet specific profile fields.
3162 *
3163 * @param array $fields
3164 * Profile fields.
3165 * @param int $componentId
3166 * ComponetID.
3167 * @param string $component
3168 * Component name.
3169 * @param array $defaults
3170 * An array of default values.
3171 *
3172 * @param bool $isStandalone
3173 */
3174 public static function setComponentDefaults(&$fields, $componentId, $component, &$defaults, $isStandalone = FALSE) {
3175 if (!$componentId ||
3176 !in_array($component, array('Contribute', 'Membership', 'Event', 'Activity'))
3177 ) {
3178 return;
3179 }
3180
3181 $componentBAO = $componentSubType = NULL;
3182 switch ($component) {
3183 case 'Membership':
3184 $componentBAO = 'CRM_Member_BAO_Membership';
3185 $componentBAOName = 'Membership';
3186 $componentSubType = array('membership_type_id');
3187 break;
3188
3189 case 'Contribute':
3190 $componentBAO = 'CRM_Contribute_BAO_Contribution';
3191 $componentBAOName = 'Contribution';
3192 $componentSubType = array('financial_type_id');
3193 break;
3194
3195 case 'Event':
3196 $componentBAO = 'CRM_Event_BAO_Participant';
3197 $componentBAOName = 'Participant';
3198 $componentSubType = array('role_id', 'event_id', 'event_type_id');
3199 break;
3200
3201 case 'Activity':
3202 $componentBAO = 'CRM_Activity_BAO_Activity';
3203 $componentBAOName = 'Activity';
3204 $componentSubType = array('activity_type_id');
3205 break;
3206 }
3207
3208 $values = array();
3209 $params = array('id' => $componentId);
3210
3211 //get the component values.
3212 CRM_Core_DAO::commonRetrieve($componentBAO, $params, $values);
3213 if ($componentBAOName == 'Participant') {
3214 $values += array('event_type_id' => CRM_Core_DAO::getFieldValue('CRM_Event_DAO_Event', $values['event_id'], 'event_type_id'));
3215 }
3216
3217 $formattedGroupTree = array();
3218
3219 foreach ($fields as $name => $field) {
3220 $fldName = $isStandalone ? $name : "field[$componentId][$name]";
3221 if (array_key_exists($name, $values)) {
3222 $defaults[$fldName] = $values[$name];
3223 }
3224 elseif ($name == 'participant_note') {
3225 $noteDetails = CRM_Core_BAO_Note::getNote($componentId, 'civicrm_participant');
3226 $defaults[$fldName] = array_pop($noteDetails);
3227 }
3228 elseif (in_array($name, array(
3229 'financial_type',
3230 'payment_instrument',
3231 'participant_status',
3232 'participant_role',
3233 ))) {
3234 $defaults[$fldName] = $values["{$name}_id"];
3235 }
3236 elseif ($name == 'membership_type') {
3237 // since membership_type field is a hierselect -
3238 $defaults[$fldName][0]
3239 = CRM_Core_DAO::getFieldValue('CRM_Member_DAO_MembershipType', $values['membership_type_id'], 'member_of_contact_id', 'id');
3240 $defaults[$fldName][1] = $values['membership_type_id'];
3241 }
3242 elseif ($name == 'membership_status') {
3243 $defaults[$fldName] = $values['status_id'];
3244 }
3245 elseif (CRM_Core_BAO_CustomField::getKeyID($name, TRUE) !== array(NULL, NULL)) {
3246 if (empty($formattedGroupTree)) {
3247 //get the groupTree as per subTypes.
3248 $groupTree = array();
3249 foreach ($componentSubType as $subType) {
3250 $subTree = CRM_Core_BAO_CustomGroup::getTree($componentBAOName, NULL,
3251 $componentId, 0, $values[$subType]
3252 );
3253 $groupTree = CRM_Utils_Array::crmArrayMerge($groupTree, $subTree);
3254 }
3255 $formattedGroupTree = CRM_Core_BAO_CustomGroup::formatGroupTree($groupTree, 1);
3256 CRM_Core_BAO_CustomGroup::setDefaults($formattedGroupTree, $defaults);
3257 }
3258
3259 //FIX ME: We need to loop defaults, but once we move to custom_1_x convention this code can be simplified.
3260 foreach ($defaults as $customKey => $customValue) {
3261 if ($customFieldDetails = CRM_Core_BAO_CustomField::getKeyID($customKey, TRUE)) {
3262 if ($name == 'custom_' . $customFieldDetails[0]) {
3263
3264 //hack to set default for checkbox
3265 //basically this is for weired field name like field[33][custom_19]
3266 //we are converting this field name to array structure and assign value.
3267 $skipValue = FALSE;
3268
3269 foreach ($formattedGroupTree as $tree) {
3270 if (!empty($tree['fields'][$customFieldDetails[0]])) {
3271 if ('CheckBox' == CRM_Utils_Array::value('html_type', $tree['fields'][$customFieldDetails[0]])) {
3272 $skipValue = TRUE;
3273 $defaults['field'][$componentId][$name] = $customValue;
3274 break;
3275 }
3276 elseif (CRM_Utils_Array::value('data_type', $tree['fields'][$customFieldDetails[0]]) == 'Date') {
3277 $skipValue = TRUE;
3278
3279 // CRM-6681, $default contains formatted date, time values.
3280 $defaults[$fldName] = $customValue;
3281 if (!empty($defaults[$customKey . '_time'])) {
3282 $defaults['field'][$componentId][$name . '_time'] = $defaults[$customKey . '_time'];
3283 }
3284 }
3285 }
3286 }
3287
3288 if (!$skipValue || $isStandalone) {
3289 $defaults[$fldName] = $customValue;
3290 }
3291 unset($defaults[$customKey]);
3292 break;
3293 }
3294 }
3295 }
3296 }
3297 elseif (isset($values[$fldName])) {
3298 $defaults[$fldName] = $values[$fldName];
3299 }
3300 }
3301 }
3302
3303 /**
3304 * @param array|string $profiles - name of profile(s) to create links for
3305 * @param array $appendProfiles
3306 * Name of profile(s) to append to each link.
3307 *
3308 * @return array
3309 */
3310 public static function getCreateLinks($profiles = '', $appendProfiles = array()) {
3311 // Default to contact profiles
3312 if (!$profiles) {
3313 $profiles = array('new_individual', 'new_organization', 'new_household');
3314 }
3315 $profiles = (array) $profiles;
3316 $toGet = array_merge($profiles, (array) $appendProfiles);
3317 $retrieved = civicrm_api3('uf_group', 'get', array(
3318 'name' => array('IN' => $toGet),
3319 'is_active' => 1,
3320 ));
3321 $links = $append = array();
3322 if (!empty($retrieved['values'])) {
3323 foreach ($retrieved['values'] as $id => $profile) {
3324 if (in_array($profile['name'], $profiles)) {
3325 $links[] = array(
3326 'label' => $profile['title'],
3327 'url' => CRM_Utils_System::url('civicrm/profile/create', "reset=1&context=dialog&gid=$id",
3328 NULL, NULL, FALSE, FALSE, TRUE),
3329 'type' => ucfirst(str_replace('new_', '', $profile['name'])),
3330 );
3331 }
3332 else {
3333 $append[] = $id;
3334 }
3335 }
3336 foreach ($append as $id) {
3337 foreach ($links as &$link) {
3338 $link['url'] .= ",$id";
3339 }
3340 }
3341 }
3342 return $links;
3343 }
3344
3345 /**
3346 * Retrieve groups of profiles.
3347 *
3348 * @param int $profileID
3349 * Id of the profile.
3350 *
3351 * @return array
3352 * returns array
3353 */
3354 public static function profileGroups($profileID) {
3355 $groupTypes = array();
3356 $profileTypes = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_UFGroup', $profileID, 'group_type');
3357 if ($profileTypes) {
3358 $groupTypeParts = explode(CRM_Core_DAO::VALUE_SEPARATOR, $profileTypes);
3359 $groupTypes = explode(',', $groupTypeParts[0]);
3360 }
3361 return $groupTypes;
3362 }
3363
3364 /**
3365 * Alter contact params by filtering existing subscribed groups and returns
3366 * unsubscribed groups array for subscription.
3367 *
3368 * @param array $params
3369 * Contact params.
3370 * @param int $contactId
3371 * User contact id.
3372 *
3373 * @return array
3374 * This contains array of groups for subscription
3375 */
3376 public static function getDoubleOptInGroupIds(&$params, $contactId = NULL) {
3377 $config = CRM_Core_Config::singleton();
3378 $subscribeGroupIds = array();
3379
3380 // process further only if profileDoubleOptIn enabled and if groups exist
3381 if (!array_key_exists('group', $params) ||
3382 !self::isProfileDoubleOptin() ||
3383 CRM_Utils_System::isNull($params['group'])
3384 ) {
3385 return $subscribeGroupIds;
3386 }
3387
3388 //check if contact email exist.
3389 $hasEmails = FALSE;
3390 foreach ($params as $name => $value) {
3391 if (strpos($name, 'email-') !== FALSE) {
3392 $hasEmails = TRUE;
3393 break;
3394 }
3395 }
3396
3397 //Proceed furthur only if email present
3398 if (!$hasEmails) {
3399 return $subscribeGroupIds;
3400 }
3401
3402 //do check for already subscriptions.
3403 $contactGroups = array();
3404 if ($contactId) {
3405 $query = "
3406 SELECT group_id
3407 FROM civicrm_group_contact
3408 WHERE status = 'Added'
3409 AND contact_id = %1";
3410
3411 $dao = CRM_Core_DAO::executeQuery($query, array(1 => array($contactId, 'Integer')));
3412 while ($dao->fetch()) {
3413 $contactGroups[$dao->group_id] = $dao->group_id;
3414 }
3415 }
3416
3417 //since we don't have names, compare w/ label.
3418 $mailingListGroupType = array_search('Mailing List', CRM_Core_OptionGroup::values('group_type'));
3419
3420 //actual processing start.
3421 foreach ($params['group'] as $groupId => $isSelected) {
3422 //unset group those are not selected.
3423 if (!$isSelected) {
3424 unset($params['group'][$groupId]);
3425 continue;
3426 }
3427
3428 $groupTypes = explode(CRM_Core_DAO::VALUE_SEPARATOR,
3429 CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Group', $groupId, 'group_type', 'id')
3430 );
3431 //get only mailing type group and unset it from params
3432 if (in_array($mailingListGroupType, $groupTypes) && !in_array($groupId, $contactGroups)) {
3433 $subscribeGroupIds[$groupId] = $groupId;
3434 unset($params['group'][$groupId]);
3435 }
3436 }
3437
3438 return $subscribeGroupIds;
3439 }
3440
3441 /**
3442 * Check if we are rendering mixed profiles.
3443 *
3444 * @param array $profileIds
3445 * Associated array of profile ids.
3446 *
3447 * @return bool
3448 * true if profile is mixed
3449 */
3450 public static function checkForMixProfiles($profileIds) {
3451 $mixProfile = FALSE;
3452
3453 $contactTypes = array('Individual', 'Household', 'Organization');
3454 $subTypes = CRM_Contact_BAO_ContactType::subTypes();
3455
3456 $components = array('Contribution', 'Participant', 'Membership', 'Activity');
3457
3458 $typeCount = array('ctype' => array(), 'subtype' => array());
3459 foreach ($profileIds as $gid) {
3460 $profileType = CRM_Core_BAO_UFField::getProfileType($gid);
3461 // ignore profile of type Contact
3462 if ($profileType == 'Contact') {
3463 continue;
3464 }
3465 if (in_array($profileType, $contactTypes)) {
3466 if (!isset($typeCount['ctype'][$profileType])) {
3467 $typeCount['ctype'][$profileType] = 1;
3468 }
3469
3470 // check if we are rendering profile of different contact types
3471 if (count($typeCount['ctype']) == 2) {
3472 $mixProfile = TRUE;
3473 break;
3474 }
3475 }
3476 elseif (in_array($profileType, $components)) {
3477 $mixProfile = TRUE;
3478 break;
3479 }
3480 else {
3481 if (!isset($typeCount['subtype'][$profileType])) {
3482 $typeCount['subtype'][$profileType] = 1;
3483 }
3484 // check if we are rendering profile of different contact sub types
3485 if (count($typeCount['subtype']) == 2) {
3486 $mixProfile = TRUE;
3487 break;
3488 }
3489 }
3490 }
3491 return $mixProfile;
3492 }
3493
3494 /**
3495 * Determine of we show overlay profile or not.
3496 *
3497 * @return bool
3498 * true if profile should be shown else false
3499 */
3500 public static function showOverlayProfile() {
3501 $showOverlay = TRUE;
3502
3503 // get the id of overlay profile
3504 $overlayProfileId = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_UFGroup', 'summary_overlay', 'id', 'name');
3505 $query = "SELECT count(id) FROM civicrm_uf_field WHERE uf_group_id = {$overlayProfileId} AND visibility IN ('Public Pages', 'Public Pages and Listings') ";
3506
3507 $count = CRM_Core_DAO::singleValueQuery($query);
3508
3509 //check if there are no public fields and use is anonymous
3510 $session = CRM_Core_Session::singleton();
3511 if (!$count && !$session->get('userID')) {
3512 $showOverlay = FALSE;
3513 }
3514
3515 return $showOverlay;
3516 }
3517
3518 /**
3519 * Get group type values of the profile.
3520 *
3521 * @param int $profileId
3522 * @param string $groupType
3523 *
3524 * @return array
3525 * group type values
3526 */
3527 public static function groupTypeValues($profileId, $groupType = NULL) {
3528 $groupTypeValue = array();
3529 $groupTypes = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_UFGroup', $profileId, 'group_type');
3530
3531 $groupTypeParts = explode(CRM_Core_DAO::VALUE_SEPARATOR, $groupTypes);
3532 if (empty($groupTypeParts[1])) {
3533 return $groupTypeValue;
3534 }
3535 $participantExtends = array('ParticipantRole', 'ParticipantEventName', 'ParticipantEventType');
3536
3537 foreach (explode(',', $groupTypeParts[1]) as $groupTypeValues) {
3538 $values = array();
3539 $valueParts = explode(':', $groupTypeValues);
3540 if ($groupType &&
3541 ($valueParts[0] != "{$groupType}Type" ||
3542 ($groupType == 'Participant' &&
3543 !in_array($valueParts[0], $participantExtends)
3544 )
3545 )
3546 ) {
3547 continue;
3548 }
3549 foreach ($valueParts as $val) {
3550 if (CRM_Utils_Rule::integer($val)) {
3551 $values[$val] = $val;
3552 }
3553 }
3554 if (!empty($values)) {
3555 $typeName = substr($valueParts[0], 0, -4);
3556 if (in_array($valueParts[0], $participantExtends)) {
3557 $typeName = $valueParts[0];
3558 }
3559 $groupTypeValue[$typeName] = $values;
3560 }
3561 }
3562
3563 return $groupTypeValue;
3564 }
3565
3566 /**
3567 * @return bool|object
3568 */
3569 public static function isProfileDoubleOptin() {
3570 // check for double optin
3571 $config = CRM_Core_Config::singleton();
3572 if (in_array('CiviMail', $config->enableComponents)) {
3573 return Civi::settings()->get('profile_double_optin');
3574 }
3575 return FALSE;
3576 }
3577
3578 /**
3579 * @return bool|object
3580 */
3581 public static function isProfileAddToGroupDoubleOptin() {
3582 // check for add to group double optin
3583 $config = CRM_Core_Config::singleton();
3584 if (in_array('CiviMail', $config->enableComponents)) {
3585 return Civi::settings()->get('profile_add_to_group_double_optin');
3586 }
3587 return FALSE;
3588 }
3589
3590 /**
3591 * Get profiles used for batch entry.
3592 *
3593 * @return array
3594 * profileIds profile ids
3595 */
3596 public static function getBatchProfiles() {
3597 $query = "SELECT id
3598 FROM civicrm_uf_group
3599 WHERE name IN ('contribution_batch_entry', 'membership_batch_entry')";
3600 $dao = CRM_Core_DAO::executeQuery($query);
3601 $profileIds = array();
3602 while ($dao->fetch()) {
3603 $profileIds[$dao->id] = $dao->id;
3604 }
3605 return $profileIds;
3606 }
3607
3608 /**
3609 * @todo what do I do?
3610 * @param $source
3611 * @param $destination
3612 * @param bool $returnMultiSummaryFields
3613 *
3614 * @return array|null
3615 */
3616 public static function shiftMultiRecordFields(&$source, &$destination, $returnMultiSummaryFields = FALSE) {
3617 $multiSummaryFields = $returnMultiSummaryFields ? array() : NULL;
3618 foreach ($source as $field => $properties) {
3619 if (!CRM_Core_BAO_CustomField::getKeyID($field)) {
3620 continue;
3621 }
3622 if (CRM_Core_BAO_CustomField::isMultiRecordField($field)) {
3623 $destination[$field] = $properties;
3624 if ($returnMultiSummaryFields) {
3625 if ($properties['is_multi_summary']) {
3626 $multiSummaryFields[$field] = $properties;
3627 }
3628 }
3629 unset($source[$field]);
3630 }
3631 }
3632 return $multiSummaryFields;
3633 }
3634
3635 /**
3636 * This is function is used to format pseudo fields.
3637 *
3638 * @param array $fields
3639 * Associated array of profile fields.
3640 *
3641 */
3642 public static function reformatProfileFields(&$fields) {
3643 //reformat fields array
3644 foreach ($fields as $name => $field) {
3645 //reformat phone and extension field
3646 if (substr($field['name'], 0, 13) == 'phone_and_ext') {
3647 $fieldSuffix = str_replace('phone_and_ext-', '', $field['name']);
3648
3649 // retain existing element properties and just update and replace key
3650 CRM_Utils_Array::crmReplaceKey($fields, $name, "phone-{$fieldSuffix}");
3651 $fields["phone-{$fieldSuffix}"]['name'] = "phone-{$fieldSuffix}";
3652 $fields["phone-{$fieldSuffix}"]['where'] = 'civicrm_phone.phone';
3653
3654 // add additional phone extension field
3655 $fields["phone_ext-{$fieldSuffix}"] = $field;
3656 $fields["phone_ext-{$fieldSuffix}"]['title'] = $field['title'] . ' - ' . ts('Ext.');
3657 $fields["phone_ext-{$fieldSuffix}"]['name'] = "phone_ext-{$fieldSuffix}";
3658 $fields["phone_ext-{$fieldSuffix}"]['where'] = 'civicrm_phone.phone_ext';
3659 $fields["phone_ext-{$fieldSuffix}"]['skipDisplay'] = 1;
3660 //ignore required for extension field
3661 $fields["phone_ext-{$fieldSuffix}"]['is_required'] = 0;
3662 }
3663 }
3664 }
3665
3666 }