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