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('xbutton', 'done', ts('Done'),
473 'onclick' => "location.href='civicrm/admin/uf/group/field?reset=1&action=browse&gid=" . $this->_gid
. "'",
478 $this->setDefaults($defaults);
486 public function postProcess() {
488 if ($this->_action
& CRM_Core_Action
::DELETE
) {
489 $fieldValues = ['uf_group_id' => $this->_gid
];
490 CRM_Utils_Weight
::delWeight('CRM_Core_DAO_UFField', $this->_id
, $fieldValues);
491 $deleted = CRM_Core_BAO_UFField
::del($this->_id
);
493 //update group_type every time. CRM-3608
494 if ($this->_gid
&& $deleted) {
495 //get the profile type.
496 $fieldsType = CRM_Core_BAO_UFGroup
::calculateGroupType($this->_gid
, TRUE);
497 CRM_Core_BAO_UFGroup
::updateGroupTypes($this->_gid
, $fieldsType);
500 CRM_Core_Session
::setStatus(ts('Selected Profile Field has been deleted.'), ts('Profile Field Deleted'), 'success');
504 // store the submitted values in an array
505 $params = $this->controller
->exportValues('Field');
506 $params['uf_group_id'] = $this->_gid
;
507 if ($params['visibility'] == 'User and User Admin Only') {
508 $params['is_searchable'] = $params['in_selector'] = 0;
511 if ($this->_action
& CRM_Core_Action
::UPDATE
) {
512 $params['id'] = $this->_id
;
516 if (isset($params['field_name'][1]) && isset($this->_selectFields
[$params['field_name'][1]])) {
517 // we dont get a name for a html formatting element
518 $name = $this->_selectFields
[$params['field_name'][1]];
521 // If field_name is missing, it's formatting
522 $fieldName = CRM_Utils_Array
::value(1, $params['field_name'], 'formatting');
524 //check for duplicate fields
525 $apiFormattedParams = $params;
526 $apiFormattedParams['field_type'] = $params['field_name'][0];
527 $apiFormattedParams['field_name'] = $fieldName;
528 if (!empty($params['field_name'][2])) {
529 if ($fieldName === 'url') {
530 $apiFormattedParams['website_type_id'] = $params['field_name'][2];
533 $apiFormattedParams['location_type_id'] = $params['field_name'][2];
536 elseif (isset($params['field_name'][2]) && $params['field_name'][2] == 0) {
537 // 0 is Primary location type
538 $apiFormattedParams['location_type_id'] = '';
540 if (!empty($params['field_name'][3])) {
541 $apiFormattedParams['phone_type_id'] = $params['field_name'][3];
544 if ($apiFormattedParams['field_type'] != "Formatting" && CRM_Core_BAO_UFField
::duplicateField($apiFormattedParams)) {
545 CRM_Core_Error
::statusBounce(ts('The selected field already exists in this profile.'), NULL, ts('Field Not Added'));
548 $apiFormattedParams['weight'] = CRM_Core_BAO_UFField
::autoWeight($params);
549 civicrm_api3('UFField', 'create', $apiFormattedParams);
551 //reset other field is searchable and in selector settings, CRM-4363
552 if ($this->_hasSearchableORInSelector
&&
553 in_array($apiFormattedParams['field_type'], ['Participant', 'Contribution', 'Membership', 'Activity', 'Case'])
555 CRM_Core_BAO_UFField
::resetInSelectorANDSearchable($this->_gid
);
558 $this->setMessageIfCountryNotAboveState($fieldName, CRM_Utils_Array
::value('location_type_id', $apiFormattedParams), $apiFormattedParams['weight'], $apiFormattedParams['uf_group_id']);
560 CRM_Core_Session
::setStatus(ts('Your CiviCRM Profile Field \'%1\' has been saved to \'%2\'.',
561 [1 => $name, 2 => $this->_title
]
562 ), ts('Profile Field Saved'), 'success');
564 $buttonName = $this->controller
->getButtonName();
566 $session = CRM_Core_Session
::singleton();
567 if ($buttonName == $this->getButtonName('next', 'new')) {
568 $session->replaceUserContext(CRM_Utils_System
::url('civicrm/admin/uf/group/field/add',
569 "reset=1&action=add&gid={$this->_gid}"
573 $session->replaceUserContext(CRM_Utils_System
::url('civicrm/admin/uf/group/field',
574 "reset=1&action=browse&gid={$this->_gid}"
580 * Validation rule for subtype.
582 * @param string $fieldType
584 * @param array $groupType
585 * Contains all groupTypes.
586 * @param array $errors
587 * List of errors to be posted back to the form.
589 public static function formRuleSubType($fieldType, $groupType, &$errors) {
590 if (in_array($fieldType, [
596 $individualSubTypes = CRM_Contact_BAO_ContactType
::subTypes('Individual');
597 foreach ($groupType as $value) {
598 if (!in_array($value, $individualSubTypes) &&
609 $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]);
615 $basicType = CRM_Contact_BAO_ContactType
::getBasicType($groupType);
617 if (!is_array($basicType)) {
618 $basicType = [$basicType];
620 if (!in_array($fieldType, $basicType) && $fieldType != 'Contact') {
621 $errors['field_name'] = ts('Cannot add or update profile field type "%1" with combination of subtype other than "%1".',
630 * Validation rule for custom data extends entity column values.
632 * @param Object $customField
636 * @param string $fieldType
637 * Group type of the field.
638 * @param array $errors
642 * list of errors to be posted back to the form
644 public static function formRuleCustomDataExtentColumnValue($customField, $gid, $fieldType, &$errors) {
645 // fix me : check object $customField
646 if (in_array($fieldType, [
653 $params = ['id' => $customField->custom_group_id
];
655 CRM_Core_BAO_CustomGroup
::retrieve($params, $customGroup);
656 if (($fieldType != CRM_Utils_Array
::value('extends', $customGroup)) ||
empty($customGroup['extends_entity_column_value'])) {
660 $extendsColumnValues = [];
661 foreach (explode(CRM_Core_DAO
::VALUE_SEPARATOR
, $customGroup['extends_entity_column_value']) as $val) {
663 $extendsColumnValues[] = $val;
667 if (empty($extendsColumnValues)) {
671 $fieldTypeValues = CRM_Core_BAO_UFGroup
::groupTypeValues($gid, $fieldType);
672 if (empty($fieldTypeValues[$fieldType])) {
676 $disallowedTypes = array_diff($extendsColumnValues, $fieldTypeValues[$fieldType]);
677 if (!empty($disallowedTypes)) {
678 $errors['field_name'] = ts('Profile is already having custom fields extending different group types, you can not add or update this custom field.');
684 * Validation rule to prevent multiple fields of primary location type within the same communication type.
686 * @param array $fields
688 * @param string $profileFieldName
690 * @param array $groupFields
691 * List of fields already in the group.
692 * @param array $errors
696 public static function formRulePrimaryCheck($fields, $profileFieldName, $groupFields, &$errors) {
697 //FIXME: This may need to also apply to website fields if they are refactored to allow more than one per profile
698 $checkPrimary = ['phone' => 'civicrm_phone.phone', 'phone_and_ext' => 'civicrm_phone.phone'];
700 $primaryOfSameTypeFound = NULL;
701 $fieldID = empty($fields['field_id']) ?
0 : $fields['field_id'];
702 // Is this a primary location type field of interest
703 if (array_key_exists($profileFieldName, $checkPrimary)) {
704 $whereCheck = $checkPrimary[$profileFieldName];
706 $potentialLocationType = $fields['field_name'][2] ??
NULL;
708 if ($whereCheck && $potentialLocationType == 0) {
709 $primaryOfSameTypeFound = '';
711 foreach ($groupFields as $groupField) {
713 if ($groupField['where'] == $whereCheck && is_null($groupField['location_type_id']) && $groupField['field_id'] != $fieldID) {
714 $primaryOfSameTypeFound = $groupField['title'];
718 if ($primaryOfSameTypeFound) {
719 $errors['field_name'] = ts('You have already added a primary location field of this type: %1', [1 => $primaryOfSameTypeFound]);
725 * Global validation rules for the form.
727 * @param array $fields
728 * Posted values of the form.
734 * list of errors to be posted back to the form
736 public static function formRule($fields, $files, $self) {
737 $is_required = CRM_Utils_Array
::value('is_required', $fields, FALSE);
738 $is_registration = CRM_Utils_Array
::value('is_registration', $fields, FALSE);
739 $is_view = CRM_Utils_Array
::value('is_view', $fields, FALSE);
740 $in_selector = CRM_Utils_Array
::value('in_selector', $fields, FALSE);
741 $is_active = CRM_Utils_Array
::value('is_active', $fields, FALSE);
744 if ($is_view && $is_registration) {
745 $errors['is_registration'] = ts('View Only cannot be selected if this field is to be included on the registration form');
747 if ($is_view && $is_required) {
748 $errors['is_view'] = ts('A View Only field cannot be required');
751 $entityName = $fields['field_name'][0];
753 $errors['field_name'] = ts('Please select a field name');
756 if ($in_selector && in_array($entityName, [
763 $errors['in_selector'] = ts("'Results Column' cannot be checked for %1 fields.", [1 => $entityName]);
766 $isCustomField = FALSE;
767 $profileFieldName = $fields['field_name'][1] ??
NULL;
768 if ($profileFieldName) {
769 //get custom field id
770 $customFieldId = explode('_', $profileFieldName);
771 if ($customFieldId[0] == 'custom') {
772 $customField = new CRM_Core_DAO_CustomField();
773 $customField->id
= $customFieldId[1];
774 $customField->find(TRUE);
775 $isCustomField = TRUE;
776 if (!empty($fields['field_id']) && !$customField->is_active
&& $is_active) {
777 $errors['field_name'] = ts('Cannot set this field "Active" since the selected custom field is disabled.');
780 //check if profile already has a different multi-record custom set field configured
781 $customGroupId = CRM_Core_BAO_CustomField
::isMultiRecordField($profileFieldName);
782 if ($customGroupId) {
783 if ($profileMultiRecordCustomGid = CRM_Core_BAO_UFField
::checkMultiRecordFieldExists($self->_gid
)) {
784 if ($customGroupId != $profileMultiRecordCustomGid) {
785 $errors['field_name'] = ts("You cannot configure multi-record custom fields belonging to different custom sets in one profile");
792 // Get list of fields already in the group
793 $groupFields = CRM_Core_BAO_UFGroup
::getFields($fields['group_id'], FALSE, NULL, NULL, NULL, TRUE, NULL, TRUE);
794 // Check if we already added a primary field of the same communication type
795 self
::formRulePrimaryCheck($fields, $profileFieldName, $groupFields, $errors);
797 //check profile is configured for double option process
798 //adding group field, email field should be present in the group
799 //fixed for issue CRM-2861 & CRM-4153
800 if (CRM_Core_BAO_UFGroup
::isProfileDoubleOptin()) {
801 if (CRM_Utils_Array
::value(1, $fields['field_name']) == 'group') {
802 $dao = new CRM_Core_BAO_UFField();
803 $dao->uf_group_id
= $fields['group_id'];
806 while ($dao->fetch()) {
807 //check email field is present in the group
808 if ($dao->field_name
== 'email') {
815 $disableSettingURL = CRM_Utils_System
::url(
816 'civicrm/admin/setting/preferences/mailing',
820 $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]);
826 $fieldType = $fields['field_name'][0];
828 //get the group type.
829 $groupType = CRM_Core_BAO_UFGroup
::calculateGroupType($self->_gid
, FALSE, CRM_Utils_Array
::value('field_id', $fields));
831 switch ($fieldType) {
833 self
::formRuleSubType($fieldType, $groupType, $errors);
837 if (in_array('Activity', $groupType) ||
838 in_array('Household', $groupType) ||
839 in_array('Organization', $groupType)
842 //CRM-7603 - need to support activity + individual.
843 //$errors['field_name'] =
844 //ts( 'Cannot add or update profile field type Individual with combination of Household or Organization or Activity' );
845 if (in_array('Household', $groupType) ||
846 in_array('Organization', $groupType)
848 $errors['field_name'] = ts('Cannot add or update profile field type Individual with combination of Household or Organization');
852 self
::formRuleSubType($fieldType, $groupType, $errors);
857 if (in_array('Activity', $groupType) ||
in_array('Individual', $groupType) ||
in_array('Organization', $groupType)) {
858 $errors['field_name'] = ts('Cannot add or update profile field type Household with combination of Individual or Organization or Activity');
861 self
::formRuleSubType($fieldType, $groupType, $errors);
866 if (in_array('Activity', $groupType) ||
in_array('Household', $groupType) ||
in_array('Individual', $groupType)) {
867 $errors['field_name'] = ts('Cannot add or update profile field type Organization with combination of Household or Individual or Activity');
870 self
::formRuleSubType($fieldType, $groupType, $errors);
875 if (in_array('Individual', $groupType) ||
876 in_array('Membership', $groupType) ||
877 in_array('Contribution', $groupType) ||
878 in_array('Organization', $groupType) ||
879 in_array('Household', $groupType) ||
880 in_array('Participant', $groupType)
883 //CRM-7603 - need to support activity + contact type.
884 //$errors['field_name'] =
885 //ts( 'Cannot add or update profile field type Activity with combination Participant or Membership or Contribution or Household or Organization or Individual' );
886 if (in_array('Membership', $groupType) ||
887 in_array('Contribution', $groupType) ||
888 in_array('Participant', $groupType)
890 $errors['field_name'] = ts('Cannot add or update profile field type Activity with combination Participant or Membership or Contribution');
894 self
::formRuleSubType($fieldType, $groupType, $errors);
897 if ($isCustomField && !isset($errors['field_name'])) {
898 self
::formRuleCustomDataExtentColumnValue($customField, $self->_gid
, $fieldType, $errors);
903 if (in_array('Membership', $groupType) ||
in_array('Contribution', $groupType)
904 ||
in_array('Organization', $groupType) ||
in_array('Household', $groupType) ||
in_array('Activity', $groupType)
906 $errors['field_name'] = ts('Cannot add or update profile field type Participant with combination of Activity or Membership or Contribution or Household or Organization.');
909 self
::formRuleSubType($fieldType, $groupType, $errors);
914 //special case where in we allow contribution + oganization fields, for on behalf feature
915 $profileId = CRM_Core_DAO
::getFieldValue('CRM_Core_DAO_UFGroup',
916 'on_behalf_organization', 'id', 'name'
919 if (in_array('Participant', $groupType) ||
in_array('Membership', $groupType)
920 ||
($profileId != $self->_gid
&& in_array('Organization', $groupType)) ||
in_array('Household', $groupType) ||
in_array('Activity', $groupType)
922 $errors['field_name'] = ts('Cannot add or update profile field type Contribution with combination of Activity or Membership or Participant or Household or Organization');
925 self
::formRuleSubType($fieldType, $groupType, $errors);
930 //special case where in we allow contribution + oganization fields, for on behalf feature
931 $profileId = CRM_Core_DAO
::getFieldValue('CRM_Core_DAO_UFGroup',
932 'on_behalf_organization', 'id', 'name'
935 if (in_array('Participant', $groupType) ||
in_array('Contribution', $groupType)
936 ||
($profileId != $self->_gid
&& in_array('Organization', $groupType)) ||
in_array('Household', $groupType) ||
in_array('Activity', $groupType)
938 $errors['field_name'] = ts('Cannot add or update profile field type Membership with combination of Activity or Participant or Contribution or Household or Organization');
941 self
::formRuleSubType($fieldType, $groupType, $errors);
946 $profileType = CRM_Core_BAO_UFField
::getProfileType($fields['group_id'], TRUE, FALSE, TRUE);
947 if (CRM_Contact_BAO_ContactType
::isaSubType($fieldType)) {
948 if (CRM_Contact_BAO_ContactType
::isaSubType($profileType)) {
949 if ($fieldType != $profileType) {
950 $errors['field_name'] = ts('Cannot add or update profile field type "%1" with combination of "%2".', [
957 $basicType = CRM_Contact_BAO_ContactType
::getBasicType($fieldType);
959 $profileType != $basicType &&
960 $profileType != 'Contact'
962 $errors['field_name'] = ts('Cannot add or update profile field type "%1" with combination of "%2".', [
970 CRM_Utils_Array
::value(1, $fields['field_name']) == 'contact_sub_type' &&
971 !in_array($profileType, ['Individual', 'Household', 'Organization']) &&
972 !in_array($profileType, CRM_Contact_BAO_ContactType
::subTypes())
974 $errors['field_name'] = ts('Cannot add or update profile field Contact Subtype as profile type is not one of Individual, Household or Organization.');
977 return empty($errors) ?
TRUE : $errors;
981 * Set a message warning the user about putting country first to render states, if required.
983 * @param string $fieldName
984 * @param int $locationTypeID
986 * @param int $ufGroupID
988 protected function setMessageIfCountryNotAboveState($fieldName, $locationTypeID, $weight, $ufGroupID) {
989 $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.');
991 if (in_array($fieldName, [
994 ]) && count(CRM_Core_Config
::singleton()->countryLimit
) > 1
996 // get state or country field weight if exists
997 $ufFieldDAO = new CRM_Core_DAO_UFField();
998 $ufFieldDAO->field_name
= ($fieldName == 'state_province' ?
'country' : 'state_province');
999 $ufFieldDAO->location_type_id
= $locationTypeID;
1000 $ufFieldDAO->uf_group_id
= $ufGroupID;
1002 if ($ufFieldDAO->find(TRUE)) {
1003 if ($ufFieldDAO->field_name
== 'country' && $ufFieldDAO->weight
> $weight) {
1004 CRM_Core_Session
::setStatus($message);
1006 elseif ($ufFieldDAO->field_name
== 'state_province' && $ufFieldDAO->weight
< $weight) {
1007 CRM_Core_Session
::setStatus($message);