3 +--------------------------------------------------------------------+
4 | Copyright CiviCRM LLC. All rights reserved. |
6 | This work is published under the GNU AGPLv3 license with some |
7 | permitted exceptions and without any warranty. For full license |
8 | and copyright information, see https://civicrm.org/licensing |
9 +--------------------------------------------------------------------+
15 * @copyright CiviCRM LLC https://civicrm.org/licensing
19 * Form to process actions on the field aspect of Custom.
21 class CRM_UF_Form_Field
extends CRM_Core_Form
{
24 * The uf group id saved to the session for an update.
31 * The field id, used when editing the field.
38 * The set of fields that we can view/edit in the user field framework
45 * The title for field.
52 * The set of fields sent to the select element.
56 protected $_selectFields;
59 * store fields with if locationtype exits status.
63 protected $_hasLocationTypes;
66 * Is this profile has searchable field.
67 * or is any field having in selector true.
71 protected $_hasSearchableORInSelector;
74 * Set variables up before form is built.
78 public function preProcess() {
79 $this->_gid
= CRM_Utils_Request
::retrieve('gid', 'Positive', $this);
80 $this->_id
= CRM_Utils_Request
::retrieve('id', 'Positive', $this);
82 $this->_title
= CRM_Core_DAO
::getFieldValue('CRM_Core_DAO_UFGroup', $this->_gid
, 'title');
84 $this->setPageTitle(ts('Profile Field'));
86 $url = CRM_Utils_System
::url('civicrm/admin/uf/group/field',
87 "reset=1&action=browse&gid={$this->_gid}"
90 $session = CRM_Core_Session
::singleton();
91 $session->pushUserContext($url);
94 'title' => ts('CiviCRM Profile Fields'),
98 CRM_Utils_System
::appendBreadCrumb($breadCrumb);
101 $showBestResult = CRM_Utils_Request
::retrieve('sbr', 'Positive', CRM_Core_DAO
::$_nullArray);
102 if ($showBestResult) {
103 $this->assign('showBestResult', $showBestResult);
106 $this->_fields
= CRM_Contact_BAO_Contact
::importableFields('All', TRUE, TRUE, TRUE, TRUE, TRUE);
107 $this->_fields
= array_merge(CRM_Activity_BAO_Activity
::exportableFields('Activity'), $this->_fields
);
109 //unset campaign related fields.
110 if (isset($this->_fields
['activity_campaign_id'])) {
111 $this->_fields
['activity_campaign_id']['title'] = ts('Campaign');
112 if (isset($this->_fields
['activity_campaign'])) {
113 unset($this->_fields
['activity_campaign']);
117 if (CRM_Core_Permission
::access('CiviContribute')) {
118 $this->_fields
= array_merge(CRM_Contribute_BAO_Contribution
::getContributionFields(FALSE), $this->_fields
);
119 $this->_fields
= array_merge(CRM_Core_BAO_UFField
::getContribBatchEntryFields(), $this->_fields
);
122 if (CRM_Core_Permission
::access('CiviMember')) {
123 $this->_fields
= array_merge(CRM_Member_BAO_Membership
::getMembershipFields(), $this->_fields
);
126 if (CRM_Core_Permission
::access('CiviEvent')) {
127 $this->_fields
= array_merge(CRM_Event_BAO_Query
::getParticipantFields(), $this->_fields
);
130 if (CRM_Core_Permission
::access('CiviCase')) {
131 $this->_fields
= array_merge(CRM_Case_BAO_Query
::getFields(), $this->_fields
);
134 $this->_fields
= array_merge($this->_fields
, CRM_Contact_BAO_Query_Hook
::singleton()->getFields());
136 $this->_selectFields
= [];
137 foreach ($this->_fields
as $name => $field) {
138 // lets skip note for now since we dont support it
139 if ($name == 'note') {
142 $this->_selectFields
[$name] = $field['title'];
143 $this->_hasLocationTypes
[$name] = $field['hasLocationType'] ??
NULL;
146 // lets add group, tag and current_employer to this list
147 $this->_selectFields
['group'] = ts('Group(s)');
148 $this->_selectFields
['tag'] = ts('Tag(s)');
149 $this->_selectFields
['current_employer'] = ts('Current Employer');
150 $this->_selectFields
['phone_and_ext'] = ts('Phone and Extension');
152 //CRM-4363 check for in selector or searchable fields.
153 $this->_hasSearchableORInSelector
= CRM_Core_BAO_UFField
::checkSearchableORInSelector($this->_gid
);
155 $this->assign('fieldId', $this->_id
);
157 $fieldTitle = CRM_Core_DAO
::getFieldValue('CRM_Core_DAO_UFField', $this->_id
, 'label');
158 $this->assign('fieldTitle', $fieldTitle);
163 * Build the form object.
167 public function buildQuickForm() {
168 if ($this->_action
& CRM_Core_Action
::DELETE
) {
172 'name' => ts('Delete Profile Field'),
173 'spacing' => ' ',
178 'name' => ts('Cancel'),
183 $addressCustomFields = array_keys(CRM_Core_BAO_CustomField
::getFieldsForImport('Address'));
185 if (isset($this->_id
)) {
186 $params = ['id' => $this->_id
];
187 CRM_Core_BAO_UFField
::retrieve($params, $defaults);
189 // set it to null if so (avoids crappy E_NOTICE errors below
190 $defaults['location_type_id'] = $defaults['location_type_id'] ??
NULL;
192 //CRM-20861 - Include custom fields defined for address to set its default location type to 0.
193 $specialFields = array_merge(CRM_Core_BAO_UFGroup
::getLocationFields(), $addressCustomFields);
194 if (!$defaults['location_type_id'] &&
195 $defaults["field_type"] != "Formatting" &&
196 in_array($defaults['field_name'], $specialFields)
198 $defaults['location_type_id'] = 0;
201 $defaults['field_name'] = [
202 $defaults['field_type'],
203 ($defaults['field_type'] == "Formatting" ?
"" : $defaults['field_name']),
204 ($defaults['field_name'] == "url") ?
$defaults['website_type_id'] : $defaults['location_type_id'],
205 CRM_Utils_Array
::value('phone_type_id', $defaults),
207 $this->_gid
= $defaults['uf_group_id'];
210 $defaults['is_active'] = 1;
213 $otherModules = array_values(CRM_Core_BAO_UFGroup
::getUFJoinRecord($this->_gid
));
214 $this->assign('otherModules', $otherModules);
216 if ($this->_action
& CRM_Core_Action
::ADD
) {
217 $fieldValues = ['uf_group_id' => $this->_gid
];
218 $defaults['weight'] = CRM_Utils_Weight
::getDefaultWeight('CRM_Core_DAO_UFField', $fieldValues);
221 // lets trim all the whitespace
222 $this->applyFilter('__ALL__', 'trim');
224 //hidden field to catch the group id in profile
225 $this->add('hidden', 'group_id', $this->_gid
);
227 //hidden field to catch the field id in profile
228 $this->add('hidden', 'field_id', $this->_id
);
230 $fields = CRM_Core_BAO_UFField
::getAvailableFields($this->_gid
, $defaults);
232 $noSearchable = $hasWebsiteTypes = [];
234 foreach ($fields as $key => $value) {
235 foreach ($value as $key1 => $value1) {
236 //CRM-2676, replacing the conflict for same custom field name from different custom group.
237 if ($customFieldId = CRM_Core_BAO_CustomField
::getKeyID($key1)) {
238 $customGroupId = CRM_Core_DAO
::getFieldValue('CRM_Core_DAO_CustomField', $customFieldId, 'custom_group_id');
239 $customGroupName = CRM_Core_DAO
::getFieldValue('CRM_Core_DAO_CustomGroup', $customGroupId, 'title');
240 $this->_mapperFields
[$key][$key1] = $value1['title'] . ' :: ' . $customGroupName;
241 if (in_array($key1, $addressCustomFields)) {
242 $noSearchable[] = $value1['title'] . ' :: ' . $customGroupName;
246 $this->_mapperFields
[$key][$key1] = $value1['title'];
248 $hasLocationTypes[$key][$key1] = $value1['hasLocationType'] ??
NULL;
249 $hasWebsiteTypes[$key][$key1] = $value1['hasWebsiteType'] ??
NULL;
250 // hide the 'is searchable' field for 'File' custom data
251 if (isset($value1['data_type']) &&
252 isset($value1['html_type']) &&
253 (($value1['data_type'] == 'File' && $value1['html_type'] == 'File')
254 ||
($value1['data_type'] == 'Link' && $value1['html_type'] == 'Link')
257 if (!in_array($value1['title'], $noSearchable)) {
258 $noSearchable[] = $value1['title'];
263 $this->assign('noSearchable', $noSearchable);
265 $this->_location_types
= CRM_Core_PseudoConstant
::get('CRM_Core_DAO_Address', 'location_type_id');
266 $defaultLocationType = CRM_Core_BAO_LocationType
::getDefault();
267 $this->_website_types
= CRM_Core_PseudoConstant
::get('CRM_Core_DAO_Website', 'website_type_id');
270 * FIXME: dirty hack to make the default option show up first. This
271 * avoids a mozilla browser bug with defaults on dynamically constructed
274 if ($defaultLocationType) {
275 $defaultLocation = $this->_location_types
[$defaultLocationType->id
];
276 unset($this->_location_types
[$defaultLocationType->id
]);
277 $this->_location_types
= [
278 $defaultLocationType->id
=> $defaultLocation,
279 ] +
$this->_location_types
;
282 $this->_location_types
= ['Primary'] +
$this->_location_types
;
284 // since we need a hierarchical list to display contact types & subtypes,
285 // this is what we going to display in first selector
286 $contactTypes = CRM_Contact_BAO_ContactType
::getSelectElements(FALSE, FALSE);
287 unset($contactTypes['']);
289 $contactTypes = !empty($contactTypes) ?
['Contact' => 'Contacts'] +
$contactTypes : [];
290 $sel1 = ['' => '- select -'] +
$contactTypes;
292 if (!empty($fields['Activity'])) {
293 $sel1['Activity'] = 'Activity';
296 if (CRM_Core_Permission
::access('CiviEvent')) {
297 $sel1['Participant'] = 'Participants';
300 if (!empty($fields['Contribution'])) {
301 $sel1['Contribution'] = 'Contributions';
304 if (!empty($fields['Membership'])) {
305 $sel1['Membership'] = 'Membership';
308 if (!empty($fields['Case'])) {
309 $sel1['Case'] = 'Case';
312 if (!empty($fields['Formatting'])) {
313 $sel1['Formatting'] = 'Formatting';
316 foreach ($sel1 as $key => $sel) {
318 $sel2[$key] = $this->_mapperFields
[$key];
322 $phoneTypes = CRM_Core_PseudoConstant
::get('CRM_Core_DAO_Phone', 'phone_type_id');
325 foreach ($sel1 as $k => $sel) {
327 foreach ($this->_location_types
as $key => $value) {
328 $sel4[$k]['phone'][$key] = &$phoneTypes;
329 $sel4[$k]['phone_and_ext'][$key] = &$phoneTypes;
334 foreach ($sel1 as $k => $sel) {
336 if (is_array($this->_mapperFields
[$k])) {
337 foreach ($this->_mapperFields
[$k] as $key => $value) {
338 if ($hasLocationTypes[$k][$key]) {
339 $sel3[$k][$key] = $this->_location_types
;
341 elseif ($hasWebsiteTypes[$k][$key]) {
342 $sel3[$k][$key] = $this->_website_types
;
352 $this->_defaults
= [];
353 $js = "<script type='text/javascript'>\n";
354 $formName = "document.{$this->_name}";
356 $alreadyMixProfile = FALSE;
357 if (CRM_Core_BAO_UFField
::checkProfileType($this->_gid
)) {
358 $alreadyMixProfile = TRUE;
360 $this->assign('alreadyMixProfile', $alreadyMixProfile);
362 $sel = &$this->addElement('hierselect', 'field_name', ts('Field Name'));
364 $formValues = $this->exportValues();
366 if (empty($formValues)) {
367 for ($k = 1; $k < 4; $k++
) {
368 if (!isset($defaults['field_name'][$k])) {
369 $js .= "{$formName}['field_name[$k]'].style.display = 'none';\n";
374 if (!empty($formValues['field_name'])) {
375 for ($key = 1; $key < 4; $key++
) {
376 if (!isset($formValues['field_name'][$key])) {
377 $js .= "{$formName}['field_name[$key]'].style.display = 'none';\n";
380 $js .= "{$formName}['field_name[$key]'].style.display = '';\n";
385 for ($k = 1; $k < 4; $k++
) {
386 if (!isset($defaults['field_name'][$k])) {
387 $js .= "{$formName}['field_name[$k]'].style.display = 'none';\n";
393 foreach ($sel2 as $k => $v) {
394 if (is_array($sel2[$k])) {
399 $sel->setOptions([$sel1, $sel2, $sel3, $sel4]);
401 // proper interpretation of spec in CRM-8732
402 if (!isset($this->_id
) && in_array('Search Profile', $otherModules)) {
403 $defaults['visibility'] = 'Public Pages and Listings';
406 $js .= "</script>\n";
407 $this->assign('initHideBoxes', $js);
412 CRM_Core_SelectValues
::ufVisibility(),
414 ['onChange' => "showHideSeletorSearch(this.value);"]
418 $js = ['onChange' => "mixProfile();"];
419 // should the field appear in selectors (as a column)?
420 $this->add('advcheckbox', 'in_selector', ts('Results Column?'), NULL, NULL, $js);
421 $this->add('advcheckbox', 'is_searchable', ts('Searchable?'), NULL, NULL, $js);
423 $attributes = CRM_Core_DAO
::getAttribute('CRM_Core_DAO_UFField');
426 $this->add('number', 'weight', ts('Order'), $attributes['weight'], TRUE);
427 $this->addRule('weight', ts('is a numeric field'), 'numeric');
429 $this->add('textarea', 'help_pre', ts('Field Pre Help'), $attributes['help_pre']);
430 $this->add('textarea', 'help_post', ts('Field Post Help'), $attributes['help_post']);
432 $this->add('advcheckbox', 'is_required', ts('Required?'));
434 $this->add('advcheckbox', 'is_multi_summary', ts('Include in multi-record listing?'));
435 $this->add('advcheckbox', 'is_active', ts('Active?'));
436 $this->add('advcheckbox', 'is_view', ts('View Only?'));
438 $this->add('text', 'label', ts('Field Label'), $attributes['label']);
441 if ($this->_hasSearchableORInSelector
) {
442 $js = ['onclick' => "return verify( );"];
449 'name' => ts('Save'),
455 'name' => ts('Save and New'),
461 'name' => ts('Cancel'),
465 $this->addFormRule(['CRM_UF_Form_Field', 'formRule'], $this);
467 // if view mode pls freeze it with the done button.
468 if ($this->_action
& CRM_Core_Action
::VIEW
) {
470 $this->addElement('button', 'done', ts('Done'),
471 ['onclick' => "location.href='civicrm/admin/uf/group/field?reset=1&action=browse&gid=" . $this->_gid
. "'"]
475 $this->setDefaults($defaults);
483 public function postProcess() {
485 if ($this->_action
& CRM_Core_Action
::DELETE
) {
486 $fieldValues = ['uf_group_id' => $this->_gid
];
487 CRM_Utils_Weight
::delWeight('CRM_Core_DAO_UFField', $this->_id
, $fieldValues);
488 $deleted = CRM_Core_BAO_UFField
::del($this->_id
);
490 //update group_type every time. CRM-3608
491 if ($this->_gid
&& $deleted) {
492 //get the profile type.
493 $fieldsType = CRM_Core_BAO_UFGroup
::calculateGroupType($this->_gid
, TRUE);
494 CRM_Core_BAO_UFGroup
::updateGroupTypes($this->_gid
, $fieldsType);
497 CRM_Core_Session
::setStatus(ts('Selected Profile Field has been deleted.'), ts('Profile Field Deleted'), 'success');
501 // store the submitted values in an array
502 $params = $this->controller
->exportValues('Field');
503 $params['uf_group_id'] = $this->_gid
;
504 if ($params['visibility'] == 'User and User Admin Only') {
505 $params['is_searchable'] = $params['in_selector'] = 0;
508 if ($this->_action
& CRM_Core_Action
::UPDATE
) {
509 $params['id'] = $this->_id
;
513 if (isset($params['field_name'][1]) && isset($this->_selectFields
[$params['field_name'][1]])) {
514 // we dont get a name for a html formatting element
515 $name = $this->_selectFields
[$params['field_name'][1]];
518 // If field_name is missing, it's formatting
519 $fieldName = CRM_Utils_Array
::value(1, $params['field_name'], 'formatting');
521 //check for duplicate fields
522 $apiFormattedParams = $params;
523 $apiFormattedParams['field_type'] = $params['field_name'][0];
524 $apiFormattedParams['field_name'] = $fieldName;
525 if (!empty($params['field_name'][2])) {
526 if ($fieldName === 'url') {
527 $apiFormattedParams['website_type_id'] = $params['field_name'][2];
530 $apiFormattedParams['location_type_id'] = $params['field_name'][2];
533 elseif ($params['field_name'][2] == 0) {
534 // 0 is Primary location type
535 $apiFormattedParams['location_type_id'] = '';
537 if (!empty($params['field_name'][3])) {
538 $apiFormattedParams['phone_type_id'] = $params['field_name'][3];
541 if ($apiFormattedParams['field_type'] != "Formatting" && CRM_Core_BAO_UFField
::duplicateField($apiFormattedParams)) {
542 CRM_Core_Error
::statusBounce(ts('The selected field already exists in this profile.'), NULL, ts('Field Not Added'));
545 $apiFormattedParams['weight'] = CRM_Core_BAO_UFField
::autoWeight($params);
546 civicrm_api3('UFField', 'create', $apiFormattedParams);
548 //reset other field is searchable and in selector settings, CRM-4363
549 if ($this->_hasSearchableORInSelector
&&
550 in_array($apiFormattedParams['field_type'], ['Participant', 'Contribution', 'Membership', 'Activity', 'Case'])
552 CRM_Core_BAO_UFField
::resetInSelectorANDSearchable($this->_gid
);
555 $this->setMessageIfCountryNotAboveState($fieldName, CRM_Utils_Array
::value('location_type_id', $apiFormattedParams), $apiFormattedParams['weight'], $apiFormattedParams['uf_group_id']);
557 CRM_Core_Session
::setStatus(ts('Your CiviCRM Profile Field \'%1\' has been saved to \'%2\'.',
558 [1 => $name, 2 => $this->_title
]
559 ), ts('Profile Field Saved'), 'success');
561 $buttonName = $this->controller
->getButtonName();
563 $session = CRM_Core_Session
::singleton();
564 if ($buttonName == $this->getButtonName('next', 'new')) {
565 $session->replaceUserContext(CRM_Utils_System
::url('civicrm/admin/uf/group/field/add',
566 "reset=1&action=add&gid={$this->_gid}"
570 $session->replaceUserContext(CRM_Utils_System
::url('civicrm/admin/uf/group/field',
571 "reset=1&action=browse&gid={$this->_gid}"
577 * Validation rule for subtype.
579 * @param string $fieldType
581 * @param array $groupType
582 * Contains all groupTypes.
583 * @param array $errors
584 * List of errors to be posted back to the form.
586 public static function formRuleSubType($fieldType, $groupType, &$errors) {
587 if (in_array($fieldType, [
593 $individualSubTypes = CRM_Contact_BAO_ContactType
::subTypes('Individual');
594 foreach ($groupType as $value) {
595 if (!in_array($value, $individualSubTypes) &&
606 $errors['field_name'] = ts('Cannot add or update profile field "%1" with combination of Household or Organization or any subtypes of Household or Organization.', [1 => $fieldType]);
612 $basicType = CRM_Contact_BAO_ContactType
::getBasicType($groupType);
614 if (!is_array($basicType)) {
615 $basicType = [$basicType];
617 if (!in_array($fieldType, $basicType) && $fieldType != 'Contact') {
618 $errors['field_name'] = ts('Cannot add or update profile field type "%1" with combination of subtype other than "%1".',
627 * Validation rule for custom data extends entity column values.
629 * @param Object $customField
633 * @param string $fieldType
634 * Group type of the field.
635 * @param array $errors
639 * list of errors to be posted back to the form
641 public static function formRuleCustomDataExtentColumnValue($customField, $gid, $fieldType, &$errors) {
642 // fix me : check object $customField
643 if (in_array($fieldType, [
650 $params = ['id' => $customField->custom_group_id
];
652 CRM_Core_BAO_CustomGroup
::retrieve($params, $customGroup);
653 if (($fieldType != CRM_Utils_Array
::value('extends', $customGroup)) ||
empty($customGroup['extends_entity_column_value'])) {
657 $extendsColumnValues = [];
658 foreach (explode(CRM_Core_DAO
::VALUE_SEPARATOR
, $customGroup['extends_entity_column_value']) as $val) {
660 $extendsColumnValues[] = $val;
664 if (empty($extendsColumnValues)) {
668 $fieldTypeValues = CRM_Core_BAO_UFGroup
::groupTypeValues($gid, $fieldType);
669 if (empty($fieldTypeValues[$fieldType])) {
673 $disallowedTypes = array_diff($extendsColumnValues, $fieldTypeValues[$fieldType]);
674 if (!empty($disallowedTypes)) {
675 $errors['field_name'] = ts('Profile is already having custom fields extending different group types, you can not add or update this custom field.');
681 * Validation rule to prevent multiple fields of primary location type within the same communication type.
683 * @param array $fields
685 * @param string $profileFieldName
687 * @param array $groupFields
688 * List of fields already in the group.
689 * @param array $errors
693 public static function formRulePrimaryCheck($fields, $profileFieldName, $groupFields, &$errors) {
694 //FIXME: This may need to also apply to website fields if they are refactored to allow more than one per profile
695 $checkPrimary = ['phone' => 'civicrm_phone.phone', 'phone_and_ext' => 'civicrm_phone.phone'];
697 $primaryOfSameTypeFound = NULL;
698 $fieldID = empty($fields['field_id']) ?
0 : $fields['field_id'];
699 // Is this a primary location type field of interest
700 if (array_key_exists($profileFieldName, $checkPrimary)) {
701 $whereCheck = $checkPrimary[$profileFieldName];
703 $potentialLocationType = $fields['field_name'][2] ??
NULL;
705 if ($whereCheck && $potentialLocationType == 0) {
706 $primaryOfSameTypeFound = '';
708 foreach ($groupFields as $groupField) {
710 if ($groupField['where'] == $whereCheck && is_null($groupField['location_type_id']) && $groupField['field_id'] != $fieldID) {
711 $primaryOfSameTypeFound = $groupField['title'];
715 if ($primaryOfSameTypeFound) {
716 $errors['field_name'] = ts('You have already added a primary location field of this type: %1', [1 => $primaryOfSameTypeFound]);
722 * Global validation rules for the form.
724 * @param array $fields
725 * Posted values of the form.
731 * list of errors to be posted back to the form
733 public static function formRule($fields, $files, $self) {
734 $is_required = CRM_Utils_Array
::value('is_required', $fields, FALSE);
735 $is_registration = CRM_Utils_Array
::value('is_registration', $fields, FALSE);
736 $is_view = CRM_Utils_Array
::value('is_view', $fields, FALSE);
737 $in_selector = CRM_Utils_Array
::value('in_selector', $fields, FALSE);
738 $is_active = CRM_Utils_Array
::value('is_active', $fields, FALSE);
741 if ($is_view && $is_registration) {
742 $errors['is_registration'] = ts('View Only cannot be selected if this field is to be included on the registration form');
744 if ($is_view && $is_required) {
745 $errors['is_view'] = ts('A View Only field cannot be required');
748 $entityName = $fields['field_name'][0];
750 $errors['field_name'] = ts('Please select a field name');
753 if ($in_selector && in_array($entityName, [
760 $errors['in_selector'] = ts("'Results Column' cannot be checked for %1 fields.", [1 => $entityName]);
763 $isCustomField = FALSE;
764 $profileFieldName = $fields['field_name'][1] ??
NULL;
765 if ($profileFieldName) {
766 //get custom field id
767 $customFieldId = explode('_', $profileFieldName);
768 if ($customFieldId[0] == 'custom') {
769 $customField = new CRM_Core_DAO_CustomField();
770 $customField->id
= $customFieldId[1];
771 $customField->find(TRUE);
772 $isCustomField = TRUE;
773 if (!empty($fields['field_id']) && !$customField->is_active
&& $is_active) {
774 $errors['field_name'] = ts('Cannot set this field "Active" since the selected custom field is disabled.');
777 //check if profile already has a different multi-record custom set field configured
778 $customGroupId = CRM_Core_BAO_CustomField
::isMultiRecordField($profileFieldName);
779 if ($customGroupId) {
780 if ($profileMultiRecordCustomGid = CRM_Core_BAO_UFField
::checkMultiRecordFieldExists($self->_gid
)) {
781 if ($customGroupId != $profileMultiRecordCustomGid) {
782 $errors['field_name'] = ts("You cannot configure multi-record custom fields belonging to different custom sets in one profile");
789 // Get list of fields already in the group
790 $groupFields = CRM_Core_BAO_UFGroup
::getFields($fields['group_id'], FALSE, NULL, NULL, NULL, TRUE, NULL, TRUE);
791 // Check if we already added a primary field of the same communication type
792 self
::formRulePrimaryCheck($fields, $profileFieldName, $groupFields, $errors);
794 //check profile is configured for double option process
795 //adding group field, email field should be present in the group
796 //fixed for issue CRM-2861 & CRM-4153
797 if (CRM_Core_BAO_UFGroup
::isProfileDoubleOptin()) {
798 if (CRM_Utils_Array
::value(1, $fields['field_name']) == 'group') {
799 $dao = new CRM_Core_BAO_UFField();
800 $dao->uf_group_id
= $fields['group_id'];
803 while ($dao->fetch()) {
804 //check email field is present in the group
805 if ($dao->field_name
== 'email') {
812 $disableSettingURL = CRM_Utils_System
::url(
813 'civicrm/admin/setting/preferences/mailing',
817 $errors['field_name'] = ts('Your site is currently configured to require double-opt in when users join (subscribe) to Group(s) via a Profile form. In this mode, you need to include an Email field in a Profile BEFORE you can add the Group(s) field. This ensures that an opt-in confirmation email can be sent. Your site administrator can disable double opt-in on the civimail admin settings: <em>%1</em>', [1 => $disableSettingURL]);
823 $fieldType = $fields['field_name'][0];
825 //get the group type.
826 $groupType = CRM_Core_BAO_UFGroup
::calculateGroupType($self->_gid
, FALSE, CRM_Utils_Array
::value('field_id', $fields));
828 switch ($fieldType) {
830 self
::formRuleSubType($fieldType, $groupType, $errors);
834 if (in_array('Activity', $groupType) ||
835 in_array('Household', $groupType) ||
836 in_array('Organization', $groupType)
839 //CRM-7603 - need to support activity + individual.
840 //$errors['field_name'] =
841 //ts( 'Cannot add or update profile field type Individual with combination of Household or Organization or Activity' );
842 if (in_array('Household', $groupType) ||
843 in_array('Organization', $groupType)
845 $errors['field_name'] = ts('Cannot add or update profile field type Individual with combination of Household or Organization');
849 self
::formRuleSubType($fieldType, $groupType, $errors);
854 if (in_array('Activity', $groupType) ||
in_array('Individual', $groupType) ||
in_array('Organization', $groupType)) {
855 $errors['field_name'] = ts('Cannot add or update profile field type Household with combination of Individual or Organization or Activity');
858 self
::formRuleSubType($fieldType, $groupType, $errors);
863 if (in_array('Activity', $groupType) ||
in_array('Household', $groupType) ||
in_array('Individual', $groupType)) {
864 $errors['field_name'] = ts('Cannot add or update profile field type Organization with combination of Household or Individual or Activity');
867 self
::formRuleSubType($fieldType, $groupType, $errors);
872 if (in_array('Individual', $groupType) ||
873 in_array('Membership', $groupType) ||
874 in_array('Contribution', $groupType) ||
875 in_array('Organization', $groupType) ||
876 in_array('Household', $groupType) ||
877 in_array('Participant', $groupType)
880 //CRM-7603 - need to support activity + contact type.
881 //$errors['field_name'] =
882 //ts( 'Cannot add or update profile field type Activity with combination Participant or Membership or Contribution or Household or Organization or Individual' );
883 if (in_array('Membership', $groupType) ||
884 in_array('Contribution', $groupType) ||
885 in_array('Participant', $groupType)
887 $errors['field_name'] = ts('Cannot add or update profile field type Activity with combination Participant or Membership or Contribution');
891 self
::formRuleSubType($fieldType, $groupType, $errors);
894 if ($isCustomField && !isset($errors['field_name'])) {
895 self
::formRuleCustomDataExtentColumnValue($customField, $self->_gid
, $fieldType, $errors);
900 if (in_array('Membership', $groupType) ||
in_array('Contribution', $groupType)
901 ||
in_array('Organization', $groupType) ||
in_array('Household', $groupType) ||
in_array('Activity', $groupType)
903 $errors['field_name'] = ts('Cannot add or update profile field type Participant with combination of Activity or Membership or Contribution or Household or Organization.');
906 self
::formRuleSubType($fieldType, $groupType, $errors);
911 //special case where in we allow contribution + oganization fields, for on behalf feature
912 $profileId = CRM_Core_DAO
::getFieldValue('CRM_Core_DAO_UFGroup',
913 'on_behalf_organization', 'id', 'name'
916 if (in_array('Participant', $groupType) ||
in_array('Membership', $groupType)
917 ||
($profileId != $self->_gid
&& in_array('Organization', $groupType)) ||
in_array('Household', $groupType) ||
in_array('Activity', $groupType)
919 $errors['field_name'] = ts('Cannot add or update profile field type Contribution with combination of Activity or Membership or Participant or Household or Organization');
922 self
::formRuleSubType($fieldType, $groupType, $errors);
927 //special case where in we allow contribution + oganization fields, for on behalf feature
928 $profileId = CRM_Core_DAO
::getFieldValue('CRM_Core_DAO_UFGroup',
929 'on_behalf_organization', 'id', 'name'
932 if (in_array('Participant', $groupType) ||
in_array('Contribution', $groupType)
933 ||
($profileId != $self->_gid
&& in_array('Organization', $groupType)) ||
in_array('Household', $groupType) ||
in_array('Activity', $groupType)
935 $errors['field_name'] = ts('Cannot add or update profile field type Membership with combination of Activity or Participant or Contribution or Household or Organization');
938 self
::formRuleSubType($fieldType, $groupType, $errors);
943 $profileType = CRM_Core_BAO_UFField
::getProfileType($fields['group_id'], TRUE, FALSE, TRUE);
944 if (CRM_Contact_BAO_ContactType
::isaSubType($fieldType)) {
945 if (CRM_Contact_BAO_ContactType
::isaSubType($profileType)) {
946 if ($fieldType != $profileType) {
947 $errors['field_name'] = ts('Cannot add or update profile field type "%1" with combination of "%2".', [
954 $basicType = CRM_Contact_BAO_ContactType
::getBasicType($fieldType);
956 $profileType != $basicType &&
957 $profileType != 'Contact'
959 $errors['field_name'] = ts('Cannot add or update profile field type "%1" with combination of "%2".', [
967 CRM_Utils_Array
::value(1, $fields['field_name']) == 'contact_sub_type' &&
968 !in_array($profileType, ['Individual', 'Household', 'Organization']) &&
969 !in_array($profileType, CRM_Contact_BAO_ContactType
::subTypes())
971 $errors['field_name'] = ts('Cannot add or update profile field Contact Subtype as profile type is not one of Individual, Household or Organization.');
974 return empty($errors) ?
TRUE : $errors;
978 * Set a message warning the user about putting country first to render states, if required.
980 * @param string $fieldName
981 * @param int $locationTypeID
983 * @param int $ufGroupID
985 protected function setMessageIfCountryNotAboveState($fieldName, $locationTypeID, $weight, $ufGroupID) {
986 $message = ts('For best results, the Country field should precede the State-Province field in your Profile form. You can use the up and down arrows on field listing page for this profile to change the order of these fields or manually edit weight for Country/State-Province Field.');
988 if (in_array($fieldName, [
991 ]) && count(CRM_Core_Config
::singleton()->countryLimit
) > 1
993 // get state or country field weight if exists
994 $ufFieldDAO = new CRM_Core_DAO_UFField();
995 $ufFieldDAO->field_name
= ($fieldName == 'state_province' ?
'country' : 'state_province');
996 $ufFieldDAO->location_type_id
= $locationTypeID;
997 $ufFieldDAO->uf_group_id
= $ufGroupID;
999 if ($ufFieldDAO->find(TRUE)) {
1000 if ($ufFieldDAO->field_name
== 'country' && $ufFieldDAO->weight
> $weight) {
1001 CRM_Core_Session
::setStatus($message);
1003 elseif ($ufFieldDAO->field_name
== 'state_province' && $ufFieldDAO->weight
< $weight) {
1004 CRM_Core_Session
::setStatus($message);