Merge pull request #4887 from pratikshad/broken-webtest
[civicrm-core.git] / CRM / Core / BAO / UFField.php
1 <?php
2 /*
3 +--------------------------------------------------------------------+
4 | CiviCRM version 4.6 |
5 +--------------------------------------------------------------------+
6 | Copyright CiviCRM LLC (c) 2004-2014 |
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-2014
32 * $Id$
33 *
34 */
35
36 /**
37 * This class contains function for UFField
38 *
39 */
40 class CRM_Core_BAO_UFField extends CRM_Core_DAO_UFField {
41
42 /**
43 * Batch entry fields
44 */
45 private static $_contriBatchEntryFields = NULL;
46 private static $_memberBatchEntryFields = NULL;
47
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 CRM_Core_BAO_UFField
58 * @static
59 */
60 public static function retrieve(&$params, &$defaults) {
61 return CRM_Core_DAO::commonRetrieve('CRM_Core_DAO_UFField', $params, $defaults);
62 }
63
64 /**
65 * Get the form title.
66 *
67 * @param int $id
68 * Id of uf_form.
69 *
70 * @return string
71 * title
72 *
73 * @static
74 */
75 public static function getTitle($id) {
76 return CRM_Core_DAO::getFieldValue('CRM_Core_DAO_UFField', $groupId, 'title');
77 }
78
79 /**
80 * Update the is_active flag in the db
81 *
82 * @param int $id
83 * Id of the database record.
84 * @param bool $is_active
85 * Value we want to set the is_active field.
86 *
87 * @return Object
88 * DAO object on sucess, null otherwise
89 * @static
90 */
91 public static function setIsActive($id, $is_active) {
92 //check if custom data profile field is disabled
93 if ($is_active) {
94 if (CRM_Core_BAO_UFField::checkUFStatus($id)) {
95 return CRM_Core_DAO::setFieldValue('CRM_Core_DAO_UFField', $id, 'is_active', $is_active);
96 }
97 else {
98 CRM_Core_Session::setStatus(ts('Cannot enable this UF field since the used custom field is disabled.'), ts('Check Custom Field'), 'error');
99 }
100 }
101 else {
102 return CRM_Core_DAO::setFieldValue('CRM_Core_DAO_UFField', $id, 'is_active', $is_active);
103 }
104 }
105
106 /**
107 * Delete the profile Field.
108 *
109 * @param int $id
110 * Field Id.
111 *
112 * @return boolean
113 *
114 * @static
115 */
116 public static function del($id) {
117 //delete field field
118 $field = new CRM_Core_DAO_UFField();
119 $field->id = $id;
120 $field->delete();
121 return TRUE;
122 }
123
124 /**
125 * Check duplicate for duplicate field in a group
126 *
127 * @param array $params
128 * An associative array with field and values.
129 * @param $ids
130 *
131 * @return mixed
132 * @ids array $ids array that containd ids
133 *
134 * @static
135 */
136 public static function duplicateField($params, $ids) {
137 $ufField = new CRM_Core_DAO_UFField();
138 $ufField->uf_group_id = CRM_Utils_Array::value('uf_group', $ids);
139 $ufField->field_type = $params['field_name'][0];
140 $ufField->field_name = $params['field_name'][1];
141 if ($params['field_name'][1] == 'url') {
142 $ufField->website_type_id = CRM_Utils_Array::value(2, $params['field_name'], NULL);
143 }
144 else {
145 $ufField->location_type_id = (CRM_Utils_Array::value(2, $params['field_name'])) ? $params['field_name'][2] : 'NULL';
146 }
147 $ufField->phone_type_id = CRM_Utils_Array::value(3, $params['field_name']);
148
149 if (!empty($ids['uf_field'])) {
150 $ufField->whereAdd("id <> " . CRM_Utils_Array::value('uf_field', $ids));
151 }
152
153 return $ufField->find(TRUE);
154 }
155
156 /**
157 * Does profile consists of a multi-record custom field
158 */
159 public static function checkMultiRecordFieldExists($gId) {
160 $queryString = "SELECT f.field_name
161 FROM civicrm_uf_field f, civicrm_uf_group g
162 WHERE f.uf_group_id = g.id
163 AND g.id = %1 AND f.field_name LIKE 'custom%'";
164 $p = array(1 => array($gId, 'Integer'));
165 $dao = CRM_Core_DAO::executeQuery($queryString, $p);
166 $customFieldIds = array();
167 $isMultiRecordFieldPresent = FALSE;
168 while ($dao->fetch()) {
169 if ($customId = CRM_Core_BAO_CustomField::getKeyID($dao->field_name)) {
170 if (is_numeric($customId)) {
171 $customFieldIds[] = $customId;
172 }
173 }
174 }
175
176 if (!empty($customFieldIds) && count($customFieldIds) == 1) {
177 $customFieldId = array_pop($customFieldIds);
178 $isMultiRecordFieldPresent = CRM_Core_BAO_CustomField::isMultiRecordField($customFieldId);
179 }
180 elseif (count($customFieldIds) > 1) {
181 $customFieldIds = implode(", ", $customFieldIds);
182 $queryString = "
183 SELECT cg.id as cgId
184 FROM civicrm_custom_group cg
185 INNER JOIN civicrm_custom_field cf
186 ON cg.id = cf.custom_group_id
187 WHERE cf.id IN (" . $customFieldIds . ") AND is_multiple = 1 LIMIT 0,1";
188
189 $dao = CRM_Core_DAO::executeQuery($queryString);
190 if ($dao->fetch()) {
191 $isMultiRecordFieldPresent = ($dao->cgId) ? $dao->cgId : FALSE;
192 }
193 }
194
195 return $isMultiRecordFieldPresent;
196 }
197
198 /**
199 * Add the UF Field
200 *
201 * @param array $params
202 * (reference) array containing the values submitted by the form.
203 * @param array $ids
204 * Array containing the id.
205 *
206 * @return CRM_Core_BAO_UFField
207 *
208 * @static
209 */
210 public static function add(&$params, $ids = array()) {
211 // set values for uf field properties and save
212 $ufField = new CRM_Core_DAO_UFField();
213 $ufField->field_type = $params['field_name'][0];
214 $ufField->field_name = $params['field_name'][1];
215
216 //should not set location type id for Primary
217 $locationTypeId = NULL;
218 if ($params['field_name'][1] == 'url') {
219 $ufField->website_type_id = CRM_Utils_Array::value(2, $params['field_name']);
220 }
221 else {
222 $locationTypeId = CRM_Utils_Array::value(2, $params['field_name']);
223 $ufField->website_type_id = NULL;
224 }
225 if ($locationTypeId) {
226 $ufField->location_type_id = $locationTypeId;
227 }
228 else {
229 $ufField->location_type_id = 'null';
230 }
231
232 $ufField->phone_type_id = CRM_Utils_Array::value(3, $params['field_name'], 'NULL');
233 $ufField->listings_title = CRM_Utils_Array::value('listings_title', $params);
234 $ufField->visibility = CRM_Utils_Array::value('visibility', $params);
235 $ufField->help_pre = CRM_Utils_Array::value('help_pre', $params);
236 $ufField->help_post = CRM_Utils_Array::value('help_post', $params);
237 $ufField->label = CRM_Utils_Array::value('label', $params);
238 $ufField->is_required = CRM_Utils_Array::value('is_required', $params, FALSE);
239 $ufField->is_active = CRM_Utils_Array::value('is_active', $params, FALSE);
240 $ufField->in_selector = CRM_Utils_Array::value('in_selector', $params, FALSE);
241 $ufField->is_view = CRM_Utils_Array::value('is_view', $params, FALSE);
242 $ufField->is_registration = CRM_Utils_Array::value('is_registration', $params, FALSE);
243 $ufField->is_match = CRM_Utils_Array::value('is_match', $params, FALSE);
244 $ufField->is_searchable = CRM_Utils_Array::value('is_searchable', $params, FALSE);
245 $ufField->is_multi_summary = CRM_Utils_Array::value('is_multi_summary', $params, FALSE);
246 $ufField->weight = CRM_Utils_Array::value('weight', $params, 0);
247
248 // need the FKEY - uf group id
249 $ufField->uf_group_id = CRM_Utils_Array::value('uf_group', $ids, FALSE);
250 $ufField->id = CRM_Utils_Array::value('uf_field', $ids, FALSE);
251
252 return $ufField->save();
253 }
254
255 /**
256 * Automatically determine one weight and modify others
257 *
258 * @param array $params
259 * UFField record, e.g. with 'weight', 'uf_group_id', and 'field_id'.
260 * @return int
261 */
262 public static function autoWeight($params) {
263 // fix for CRM-316
264 $oldWeight = NULL;
265
266 if (!empty($params['field_id'])) {
267 $oldWeight = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_UFField', $params['field_id'], 'weight', 'id');
268 }
269 $fieldValues = array('uf_group_id' => $params['group_id']);
270 return CRM_Utils_Weight::updateOtherWeights('CRM_Core_DAO_UFField', $oldWeight, CRM_Utils_Array::value('weight', $params, 0), $fieldValues);
271 }
272
273 /**
274 * Enable/disable profile field given a custom field id
275 *
276 * @param int $customFieldId
277 * Custom field id.
278 * @param bool $is_active
279 * Set the is_active field.
280 *
281 * @return void
282 * @static
283 */
284 public static function setUFField($customFieldId, $is_active) {
285 //find the profile id given custom field
286 $ufField = new CRM_Core_DAO_UFField();
287 $ufField->field_name = "custom_" . $customFieldId;
288
289 $ufField->find();
290 while ($ufField->fetch()) {
291 //enable/ disable profile
292 CRM_Core_BAO_UFField::setIsActive($ufField->id, $is_active);
293 }
294 }
295
296 /**
297 * Copy existing profile fields to
298 * new profile from the already built profile
299 *
300 * @param int $old_id
301 * From which we need to copy.
302 * @param bool $new_id
303 * In which to copy.
304 *
305 * @return void
306 * @static
307 */
308 public static function copy($old_id, $new_id) {
309 $ufField = new CRM_Core_DAO_UFField();
310 $ufField->uf_group_id = $old_id;
311 $ufField->find();
312 while ($ufField->fetch()) {
313 //copy the field records as it is on new ufgroup id
314 $ufField->uf_group_id = $new_id;
315 $ufField->id = NULL;
316 $ufField->save();
317 }
318 }
319
320 /**
321 * Delete profile field given a custom field
322 *
323 * @param int $customFieldId
324 * ID of the custom field to be deleted.
325 *
326 * @return void
327 *
328 * @static
329 */
330 public static function delUFField($customFieldId) {
331 //find the profile id given custom field id
332 $ufField = new CRM_Core_DAO_UFField();
333 $ufField->field_name = "custom_" . $customFieldId;
334
335 $ufField->find();
336 while ($ufField->fetch()) {
337 //enable/ disable profile
338 CRM_Core_BAO_UFField::del($ufField->id);
339 }
340 }
341
342 /**
343 * Enable/disable profile field given a custom group id
344 *
345 * @param int $customGroupId
346 * Custom group id.
347 * @param bool $is_active
348 * Value we want to set the is_active field.
349 *
350 * @return void
351 * @static
352 */
353 public static function setUFFieldStatus($customGroupId, $is_active) {
354 //find the profile id given custom group id
355 $queryString = "SELECT civicrm_custom_field.id as custom_field_id
356 FROM civicrm_custom_field, civicrm_custom_group
357 WHERE civicrm_custom_field.custom_group_id = civicrm_custom_group.id
358 AND civicrm_custom_group.id = %1";
359 $p = array(1 => array($customGroupId, 'Integer'));
360 $dao = CRM_Core_DAO::executeQuery($queryString, $p);
361
362 while ($dao->fetch()) {
363 //enable/ disable profile
364 CRM_Core_BAO_UFField::setUFField($dao->custom_field_id, $is_active);
365 }
366 }
367
368 /**
369 * Check the status of custom field used in uf fields
370 *
371 * @param int $UFFieldId
372 *
373 * @return boolean
374 * false if custom field are disabled else true
375 * @static
376 */
377 public static function checkUFStatus($UFFieldId) {
378 $fieldName = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_UFField', $UFFieldId, 'field_name');
379 // return if field is not a custom field
380 if (!$customFieldId = CRM_Core_BAO_CustomField::getKeyID($fieldName)) {
381 return TRUE;
382 }
383
384 $customField = new CRM_Core_DAO_CustomField();
385 $customField->id = $customFieldId;
386 // if uf field is custom field
387 if ($customField->find(TRUE)) {
388 if (!$customField->is_active) {
389 return FALSE;
390 }
391 else {
392 return TRUE;
393 }
394 }
395 }
396
397 /**
398 * Find out whether given profile group using Activity
399 * Profile fields with contact fields
400 */
401 public static function checkContactActivityProfileType($ufGroupId) {
402 $ufGroup = new CRM_Core_DAO_UFGroup();
403 $ufGroup->id = $ufGroupId;
404 $ufGroup->find(TRUE);
405
406 return self::checkContactActivityProfileTypeByGroupType($ufGroup->group_type);
407 }
408
409 /**
410 * FIXME say 10 ha
411 * @param $ufGroupType
412 * @return bool
413 */
414 public static function checkContactActivityProfileTypeByGroupType($ufGroupType) {
415 $profileTypes = array();
416 if ($ufGroupType) {
417 $typeParts = explode(CRM_Core_DAO::VALUE_SEPARATOR, $ufGroupType);
418 $profileTypes = explode(',', $typeParts[0]);
419 }
420
421 if (empty($profileTypes)) {
422 return FALSE;
423 }
424 $components = array('Contribution', 'Participant', 'Membership');
425 if (!in_array('Activity', $profileTypes)) {
426 return FALSE;
427 }
428 elseif (count($profileTypes) == 1) {
429 return FALSE;
430 }
431
432 if ($index = array_search('Contact', $profileTypes)) {
433 unset($profileTypes[$index]);
434 if (count($profileTypes) == 1) {
435 return TRUE;
436 }
437 }
438
439 $contactTypes = array('Individual', 'Household', 'Organization');
440 $subTypes = CRM_Contact_BAO_ContactType::subTypes();
441
442 $profileTypeComponent = array_intersect($components, $profileTypes);
443 if (!empty($profileTypeComponent) ||
444 count(array_intersect($contactTypes, $profileTypes)) > 1 ||
445 count(array_intersect($subTypes, $profileTypes)) > 1
446 ) {
447 return FALSE;
448 }
449
450 return TRUE;
451 }
452
453 /**
454 * Find out whether given profile group uses $required
455 * and/or $optional profile types
456 *
457 * @param int $ufGroupId
458 * Profile id.
459 * @param array $required
460 * Array of types those are required.
461 * @param array $optional
462 * Array of types those are optional.
463 *
464 * @return boolean
465 * @static
466 */
467 public static function checkValidProfileType($ufGroupId, $required, $optional = NULL) {
468 if (!is_array($required) || empty($required)) {
469 return;
470 }
471
472 $ufGroup = new CRM_Core_DAO_UFGroup();
473 $ufGroup->id = $ufGroupId;
474 $ufGroup->find(TRUE);
475
476 $profileTypes = array();
477 if ($ufGroup->group_type) {
478 $typeParts = explode(CRM_Core_DAO::VALUE_SEPARATOR, $ufGroup->group_type);
479 $profileTypes = explode(',', $typeParts[0]);
480 }
481
482 if (empty($profileTypes)) {
483 return FALSE;
484 }
485
486 $valid = TRUE;
487 foreach ($required as $key => $val) {
488 if (!in_array($val, $profileTypes)) {
489 $valid = FALSE;
490 break;
491 }
492 }
493
494 if ($valid && is_array($optional)) {
495 foreach ($optional as $key => $val) {
496 if (in_array($val, $profileTypes)) {
497 $valid = TRUE;
498 break;
499 }
500 }
501 }
502
503 return $valid;
504 }
505
506 /**
507 * Check for mix profile fields (eg: individual + other contact types)
508 *
509 * @param int $ufGroupId
510 *
511 * @return bool
512 * true for mix profile else false
513 * @static
514 */
515 public static function checkProfileType($ufGroupId) {
516 $ufGroup = new CRM_Core_DAO_UFGroup();
517 $ufGroup->id = $ufGroupId;
518 $ufGroup->find(TRUE);
519
520 $profileTypes = array();
521 if ($ufGroup->group_type) {
522 $typeParts = explode(CRM_Core_DAO::VALUE_SEPARATOR, $ufGroup->group_type);
523 $profileTypes = explode(',', $typeParts[0]);
524 }
525
526 //early return if new profile.
527 if (empty($profileTypes)) {
528 return FALSE;
529 }
530
531 //we need to unset Contact
532 if (count($profileTypes) > 1) {
533 $index = array_search('Contact', $profileTypes);
534 if ($index !== FALSE) {
535 unset($profileTypes[$index]);
536 }
537 }
538
539 // suppress any subtypes if present
540 CRM_Contact_BAO_ContactType::suppressSubTypes($profileTypes);
541
542 $contactTypes = array('Contact', 'Individual', 'Household', 'Organization');
543 $components = array('Contribution', 'Participant', 'Membership', 'Activity');
544 $fields = array();
545
546 // check for mix profile condition
547 if (count($profileTypes) > 1) {
548 //check the there are any components include in profile
549 foreach ($components as $value) {
550 if (in_array($value, $profileTypes)) {
551 return TRUE;
552 }
553 }
554 //check if there are more than one contact types included in profile
555 if (count($profileTypes) > 1) {
556 return TRUE;
557 }
558 }
559 elseif (count($profileTypes) == 1) {
560 // note for subtype case count would be zero
561 $profileTypes = array_values($profileTypes);
562 if (!in_array($profileTypes[0], $contactTypes)) {
563 return TRUE;
564 }
565 }
566
567 return FALSE;
568 }
569
570 /**
571 * Get the profile type (eg: individual/organization/household)
572 *
573 * @param int $ufGroupId
574 * Uf group id.
575 * @param bool $returnMixType
576 * This is true, then field type of mix profile field is returned.
577 * @param bool $onlyPure
578 * True if only pure profiles are required.
579 *
580 * @param bool $skipComponentType
581 *
582 * @return string
583 * profile group_type
584 * @static
585 *
586 * TODO Why is this function in this class? It seems to be about the UFGroup.
587 */
588 public static function getProfileType($ufGroupId, $returnMixType = TRUE, $onlyPure = FALSE, $skipComponentType = FALSE) {
589 $ufGroup = new CRM_Core_DAO_UFGroup();
590 $ufGroup->id = $ufGroupId;
591 $ufGroup->is_active = 1;
592
593 $ufGroup->find(TRUE);
594 return self::calculateProfileType($ufGroup->group_type, $returnMixType, $onlyPure, $skipComponentType);
595 }
596
597 /**
598 * Get the profile type (eg: individual/organization/household)
599 *
600 * @param string $ufGroupType
601 * @param bool $returnMixType
602 * This is true, then field type of mix profile field is returned.
603 * @param bool $onlyPure
604 * True if only pure profiles are required.
605 * @param bool $skipComponentType
606 *
607 * @return string
608 * profile group_type
609 * @static
610 *
611 * TODO Why is this function in this class? It seems to be about the UFGroup.
612 */
613 public static function calculateProfileType($ufGroupType, $returnMixType = TRUE, $onlyPure = FALSE, $skipComponentType = FALSE) {
614 // profile types
615 $contactTypes = array('Contact', 'Individual', 'Household', 'Organization');
616 $subTypes = CRM_Contact_BAO_ContactType::subTypes();
617 $components = array('Contribution', 'Participant', 'Membership', 'Activity');
618
619 $profileTypes = array();
620 if ($ufGroupType) {
621 $typeParts = explode(CRM_Core_DAO::VALUE_SEPARATOR, $ufGroupType);
622 $profileTypes = explode(',', $typeParts[0]);
623 }
624
625 if ($onlyPure) {
626 if (count($profileTypes) == 1) {
627 return $profileTypes[0];
628 }
629 else {
630 return NULL;
631 }
632 }
633
634 //we need to unset Contact
635 if (count($profileTypes) > 1) {
636 $index = array_search('Contact', $profileTypes);
637 if ($index !== FALSE) {
638 unset($profileTypes[$index]);
639 }
640 }
641
642 $profileType = $mixProfileType = NULL;
643
644 // this case handles pure profile
645 if (count($profileTypes) == 1) {
646 $profileType = array_pop($profileTypes);
647 }
648 else {
649 //check the there are any components include in profile
650 $componentCount = array();
651 foreach ($components as $value) {
652 if (in_array($value, $profileTypes)) {
653 $componentCount[] = $value;
654 }
655 }
656
657 //check contact type included in profile
658 $contactTypeCount = array();
659 foreach ($contactTypes as $value) {
660 if (in_array($value, $profileTypes)) {
661 $contactTypeCount[] = $value;
662 }
663 }
664 // subtype counter
665 $subTypeCount = array();
666 foreach ($subTypes as $value) {
667 if (in_array($value, $profileTypes)) {
668 $subTypeCount[] = $value;
669 }
670 }
671 if (!$skipComponentType && count($componentCount) == 1) {
672 $profileType = $componentCount[0];
673 }
674 elseif (count($componentCount) > 1) {
675 $mixProfileType = $componentCount[1];
676 }
677 elseif (count($subTypeCount) == 1) {
678 $profileType = $subTypeCount[0];
679 }
680 elseif (count($contactTypeCount) == 1) {
681 $profileType = $contactTypeCount[0];
682 }
683 elseif (count($subTypeCount) > 1) {
684 // this is mix subtype profiles
685 $mixProfileType = $subTypeCount[1];
686 }
687 elseif (count($contactTypeCount) > 1) {
688 // this is mix contact profiles
689 $mixProfileType = $contactTypeCount[1];
690 }
691 }
692
693 if ($mixProfileType) {
694 if ($returnMixType) {
695 return $mixProfileType;
696 }
697 else {
698 return 'Mixed';
699 }
700 }
701 else {
702 return $profileType;
703 }
704 }
705
706 /**
707 * Check for mix profiles groups (eg: individual + other contact types)
708 *
709 * @param $ctype
710 *
711 * @return bool
712 * true for mix profile group else false
713 * @static
714 */
715 public static function checkProfileGroupType($ctype) {
716 $ufGroup = new CRM_Core_DAO_UFGroup();
717
718 $query = "
719 SELECT ufg.id as id
720 FROM civicrm_uf_group as ufg, civicrm_uf_join as ufj
721 WHERE ufg.id = ufj.uf_group_id
722 AND ufj.module = 'User Registration'
723 AND ufg.is_active = 1 ";
724
725 $ufGroup = CRM_Core_DAO::executeQuery($query);
726
727 $fields = array();
728 $validProfiles = array('Individual', 'Organization', 'Household', 'Contribution');
729 while ($ufGroup->fetch()) {
730 $profileType = self::getProfileType($ufGroup->id);
731 if (in_array($profileType, $validProfiles)) {
732 continue;
733 }
734 elseif ($profileType) {
735 return FALSE;
736 }
737 }
738
739 return TRUE;
740 }
741
742 /**
743 * Check for searchable or in selector field for given profile.
744 *
745 * @param int $profileID
746 *
747 * @return boolean
748 */
749 public static function checkSearchableORInSelector($profileID) {
750 $result = FALSE;
751 if (!$profileID) {
752 return $result;
753 }
754
755 $query = "
756 SELECT id
757 From civicrm_uf_field
758 WHERE (in_selector = 1 OR is_searchable = 1)
759 AND uf_group_id = {$profileID}";
760
761 $ufFields = CRM_Core_DAO::executeQuery($query);
762 while ($ufFields->fetch()) {
763 $result = TRUE;
764 break;
765 }
766
767 return $result;
768 }
769
770 /**
771 * Reset In selector and is searchable values for given $profileID.
772 *
773 * @param int $profileID
774 *
775 * @return void
776 */
777 public function resetInSelectorANDSearchable($profileID) {
778 if (!$profileID) {
779 return;
780 }
781 $query = "UPDATE civicrm_uf_field SET in_selector = 0, is_searchable = 0 WHERE uf_group_id = {$profileID}";
782 CRM_Core_DAO::executeQuery($query);
783 }
784
785 /**
786 * Add fields to $profileAddressFields as appropriate.
787 * profileAddressFields is assigned to the template to tell it
788 * what fields are in the profile address
789 * that potentially should be copied to the Billing fields
790 * we want to give precedence to
791 * 1) Billing &
792 * 2) then Primary designated as 'Primary
793 * 3) location_type is primary
794 * 4) if none of these apply then it just uses the first one
795 *
796 * as this will be used to
797 * transfer profile address data to billing fields
798 * http://issues.civicrm.org/jira/browse/CRM-5869
799 *
800 * @param string $key
801 * Field key - e.g. street_address-Primary, first_name.
802 * @param array $profileAddressFields
803 * Array of profile fields that relate to address fields.
804 * @param array $profileFilter
805 * Filter to apply to profile fields - expected usage is to only fill based on.
806 * the bottom profile per CRM-13726
807 *
808 * @return bool
809 * Can the address block be hidden safe in the knowledge all fields are elsewhere collected (see CRM-15118)
810 */
811 public static function assignAddressField($key, &$profileAddressFields, $profileFilter) {
812 $billing_id = CRM_Core_BAO_LocationType::getBilling();
813 list($prefixName, $index) = CRM_Utils_System::explode('-', $key, 2);
814
815 $profileFields = civicrm_api3('uf_field', 'get', array_merge($profileFilter,
816 array(
817 'is_active' => 1,
818 'return' => 'field_name, is_required',
819 'options' => array(
820 'limit' => 0,
821 )
822 )
823 ));
824 //check for valid fields ( fields that are present in billing block )
825 $validBillingFields = array(
826 'first_name',
827 'middle_name',
828 'last_name',
829 'street_address',
830 'supplemental_address_1',
831 'city',
832 'state_province',
833 'postal_code',
834 'country',
835 );
836 $requiredBillingFields = array_diff($validBillingFields, array('middle_name', 'supplemental_address_1'));
837 $validProfileFields = array();
838 $requiredProfileFields = array();
839
840 foreach ($profileFields['values'] as $field) {
841 if (in_array($field['field_name'], $validBillingFields)) {
842 $validProfileFields[] = $field['field_name'];
843 }
844 if ($field['is_required']) {
845 $requiredProfileFields[] = $field['field_name'];
846 }
847 }
848
849 if (!in_array($prefixName, $validProfileFields)) {
850 return;
851 }
852
853 if (!empty($index) && (
854 // it's empty so we set it OR
855 !CRM_Utils_array::value($prefixName, $profileAddressFields)
856 //we are dealing with billing id (precedence)
857 || $index == $billing_id
858 // we are dealing with primary & billing not set
859 || ($index == 'Primary' && $profileAddressFields[$prefixName] != $billing_id)
860 || ($index == CRM_Core_BAO_LocationType::getDefault()->id
861 && $profileAddressFields[$prefixName] != $billing_id
862 && $profileAddressFields[$prefixName] != 'Primary'
863 )
864 )
865 ) {
866 $profileAddressFields[$prefixName] = $index;
867 }
868
869 $potentiallyMissingRequiredFields = array_diff($requiredBillingFields, $requiredProfileFields);
870 CRM_Core_Resources::singleton()
871 ->addSetting(array('billing' => array('billingProfileIsHideable' => empty($potentiallyMissingRequiredFields))));
872 }
873
874 /**
875 * Get a list of fields which can be added to profiles
876 *
877 * @param int $gid : UF group ID
878 * @param array $defaults : Form defaults
879 * @return array, multidimensional; e.g. $result['FieldGroup']['field_name']['label']
880 * @static
881 */
882 public static function getAvailableFields($gid = NULL, $defaults = array()) {
883 $fields = array(
884 'Contact' => array(),
885 'Individual' => CRM_Contact_BAO_Contact::importableFields('Individual', FALSE, FALSE, TRUE, TRUE, TRUE),
886 'Household' => CRM_Contact_BAO_Contact::importableFields('Household', FALSE, FALSE, TRUE, TRUE, TRUE),
887 'Organization' => CRM_Contact_BAO_Contact::importableFields('Organization', FALSE, FALSE, TRUE, TRUE, TRUE),
888 );
889
890 // include hook injected fields
891 $fields['Contact'] = array_merge($fields['Contact'], CRM_Contact_BAO_Query_Hook::singleton()->getFields());
892
893 // add current employer for individuals
894 $fields['Individual']['current_employer'] = array(
895 'name' => 'organization_name',
896 'title' => ts('Current Employer'),
897 );
898
899 $addressOptions = CRM_Core_BAO_Setting::valueOptions(CRM_Core_BAO_Setting::SYSTEM_PREFERENCES_NAME,
900 'address_options', TRUE, NULL, TRUE
901 );
902
903 if (!$addressOptions['county']) {
904 unset($fields['Individual']['county'], $fields['Household']['county'], $fields['Organization']['county']);
905 }
906
907 // break out common contact fields array CRM-3037.
908 // from a UI perspective this makes very little sense
909 foreach ($fields['Individual'] as $key => $value) {
910 if (!empty($fields['Household'][$key]) && !empty($fields['Organization'][$key])) {
911 $fields['Contact'][$key] = $value;
912 unset($fields['Individual'][$key], $fields['Household'][$key], $fields['Organization'][$key]);
913 }
914 }
915
916 // Internal field not exposed to forms
917 unset($fields['Contact']['contact_type']);
918 unset($fields['Contact']['master_id']);
919
920 // convert phone extension in to psedo-field phone + phone extension
921 //unset extension
922 unset($fields['Contact']['phone_ext']);
923 //add psedo field
924 $fields['Contact']['phone_and_ext'] = array(
925 'name' => 'phone_and_ext',
926 'title' => ts('Phone and Extension'),
927 'hasLocationType' => 1,
928 );
929
930 // include Subtypes For Profile
931 $subTypes = CRM_Contact_BAO_ContactType::subTypeInfo();
932 foreach ($subTypes as $name => $val) {
933 //custom fields for sub type
934 $subTypeFields = CRM_Core_BAO_CustomField::getFieldsForImport($name, FALSE, FALSE, FALSE, TRUE, TRUE);
935 if (array_key_exists($val['parent'], $fields)) {
936 $fields[$name] = $fields[$val['parent']] + $subTypeFields;
937 }
938 else {
939 $fields[$name] = $subTypeFields;
940 }
941 }
942
943 if (CRM_Core_Permission::access('CiviContribute')) {
944 $contribFields = CRM_Contribute_BAO_Contribution::getContributionFields(FALSE);
945 if (!empty($contribFields)) {
946 unset($contribFields['is_test']);
947 unset($contribFields['is_pay_later']);
948 unset($contribFields['contribution_id']);
949 $contribFields['contribution_note'] = array(
950 'name' => 'contribution_note',
951 'title' => ts('Contribution Note'),
952 );
953 $fields['Contribution'] = array_merge($contribFields, self::getContribBatchEntryFields());
954 }
955 }
956
957 if (CRM_Core_Permission::access('CiviEvent')) {
958 $participantFields = CRM_Event_BAO_Query::getParticipantFields();
959 if ($participantFields) {
960 // Remove fields not supported by profiles
961 CRM_Utils_Array::remove($participantFields,
962 'external_identifier',
963 'event_id',
964 'participant_contact_id',
965 'participant_role_id',
966 'participant_status_id',
967 'participant_is_test',
968 'participant_fee_level',
969 'participant_id',
970 'participant_is_pay_later',
971 'participant_campaign'
972 );
973 if (isset($participantFields['participant_campaign_id'])) {
974 $participantFields['participant_campaign_id']['title'] = ts('Campaign');
975 }
976 $fields['Participant'] = $participantFields;
977 }
978 }
979
980 if (CRM_Core_Permission::access('CiviMember')) {
981 $membershipFields = CRM_Member_BAO_Membership::getMembershipFields();
982 // Remove fields not supported by profiles
983 CRM_Utils_Array::remove($membershipFields,
984 'membership_id',
985 'membership_type_id',
986 'member_is_test',
987 'is_override',
988 'status_id',
989 'member_is_pay_later'
990 );
991 if ($gid && CRM_Core_DAO::getFieldValue('CRM_Core_DAO_UFGroup', $gid, 'name') == 'membership_batch_entry') {
992 $fields['Membership'] = array_merge($membershipFields, self::getMemberBatchEntryFields());
993 }
994 else {
995 $fields['Membership'] = $membershipFields;
996 }
997 }
998
999 if (CRM_Core_Permission::access('CiviCase')) {
1000 $caseFields = CRM_Case_BAO_Query::getFields(TRUE);
1001 $caseFields = array_merge($caseFields, CRM_Core_BAO_CustomField::getFieldsForImport('Case'));
1002 if ($caseFields) {
1003 // Remove fields not supported by profiles
1004 CRM_Utils_Array::remove($caseFields,
1005 'case_id',
1006 'case_type',
1007 'case_start_date',
1008 'case_end_date',
1009 'case_role',
1010 'case_status',
1011 'case_deleted'
1012 );
1013 }
1014 $fields['Case'] = $caseFields;
1015 }
1016
1017 $activityFields = CRM_Activity_BAO_Activity::getProfileFields();
1018 if ($activityFields) {
1019 // campaign related fields.
1020 if (isset($activityFields['activity_campaign_id'])) {
1021 $activityFields['activity_campaign_id']['title'] = ts('Campaign');
1022 }
1023 $fields['Activity'] = $activityFields;
1024 }
1025
1026 $fields['Formatting']['format_free_html_' . rand(1000, 9999)] = array(
1027 'name' => 'free_html',
1028 'import' => FALSE,
1029 'export' => FALSE,
1030 'title' => 'Free HTML',
1031 );
1032
1033 // Sort by title
1034 foreach ($fields as &$values) {
1035 $values = CRM_Utils_Array::crmArraySortByField($values, 'title');
1036 }
1037
1038 //group selected and unwanted fields list
1039 $ufFields = $gid ? CRM_Core_BAO_UFGroup::getFields($gid, FALSE, NULL, NULL, NULL, TRUE, NULL, TRUE) : array();
1040 $groupFieldList = array_merge($ufFields, array(
1041 'note',
1042 'email_greeting_custom',
1043 'postal_greeting_custom',
1044 'addressee_custom',
1045 'id',
1046 ));
1047 //unset selected fields
1048 foreach ($groupFieldList as $key => $value) {
1049 if (is_integer($key)) {
1050 unset($fields['Individual'][$value], $fields['Household'][$value], $fields['Organization'][$value]);
1051 continue;
1052 }
1053 if (!empty($defaults['field_name'])
1054 && $defaults['field_name']['0'] == $value['field_type']
1055 && $defaults['field_name']['1'] == $key
1056 ) {
1057 continue;
1058 }
1059 unset($fields[$value['field_type']][$key]);
1060 }
1061
1062 return $fields;
1063 }
1064
1065 /**
1066 * Get a list of fields which can be added to profiles
1067 *
1068 * @param bool $force
1069 *
1070 * @return array, multidimensional; e.g. $result['field_name']['label']
1071 * @static
1072 */
1073 public static function getAvailableFieldsFlat($force = FALSE) {
1074 // FIXME reset when data model changes
1075 static $result = NULL;
1076 if ($result === NULL || $force) {
1077 $fieldTree = self::getAvailableFields();
1078 $result = array();
1079 foreach ($fieldTree as $field_type => $fields) {
1080 foreach ($fields as $field_name => $field) {
1081 if (!isset($result[$field_name])) {
1082 $field['field_type'] = $field_type;
1083 $result[$field_name] = $field;
1084 }
1085 }
1086 }
1087 }
1088 return $result;
1089 }
1090
1091 /**
1092 * Determine whether the given field_name is valid
1093 *
1094 * @param string $fieldName
1095 * @return bool
1096 */
1097 public static function isValidFieldName($fieldName) {
1098 $availableFields = CRM_Core_BAO_UFField::getAvailableFieldsFlat();
1099 return isset($availableFields[$fieldName]);
1100 }
1101
1102 /**
1103 * @return array|null
1104 */
1105 public static function getContribBatchEntryFields() {
1106 if (self::$_contriBatchEntryFields === NULL) {
1107 self::$_contriBatchEntryFields = array(
1108 'send_receipt' => array(
1109 'name' => 'send_receipt',
1110 'title' => ts('Send Receipt'),
1111 ),
1112 'soft_credit' => array(
1113 'name' => 'soft_credit',
1114 'title' => ts('Soft Credit'),
1115 ),
1116 'soft_credit_type' => array(
1117 'name' => 'soft_credit_type',
1118 'title' => ts('Soft Credit Type'),
1119 ),
1120 'product_name' => array(
1121 'name' => 'product_name',
1122 'title' => ts('Premiums'),
1123 ),
1124 'contribution_note' => array(
1125 'name' => 'contribution_note',
1126 'title' => ts('Contribution Note'),
1127 ),
1128 );
1129 }
1130 return self::$_contriBatchEntryFields;
1131 }
1132
1133 /**
1134 * @return array|null
1135 */
1136 public static function getMemberBatchEntryFields() {
1137 if (self::$_memberBatchEntryFields === NULL) {
1138 self::$_memberBatchEntryFields = array(
1139 'send_receipt' => array(
1140 'name' => 'send_receipt',
1141 'title' => ts('Send Receipt'),
1142 ),
1143 'soft_credit' => array(
1144 'name' => 'soft_credit',
1145 'title' => ts('Soft Credit'),
1146 ),
1147 'product_name' => array(
1148 'name' => 'product_name',
1149 'title' => ts('Premiums'),
1150 ),
1151 'financial_type' => array(
1152 'name' => 'financial_type',
1153 'title' => ts('Financial Type'),
1154 ),
1155 'total_amount' => array(
1156 'name' => 'total_amount',
1157 'title' => ts('Total Amount'),
1158 ),
1159 'receive_date' => array(
1160 'name' => 'receive_date',
1161 'title' => ts('Receive Date'),
1162 ),
1163 'payment_instrument' => array(
1164 'name' => 'payment_instrument',
1165 'title' => ts('Payment Instrument'),
1166 ),
1167 'contribution_status_id' => array(
1168 'name' => 'contribution_status_id',
1169 'title' => ts('Contribution Status'),
1170 ),
1171 );
1172 }
1173 return self::$_memberBatchEntryFields;
1174 }
1175 }