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