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