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