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