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