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