Merge pull request #13967 from eileenmcnaughton/activity_token
[civicrm-core.git] / CRM / UF / Form / Field.php
CommitLineData
6a488035
TO
1<?php
2/*
3 +--------------------------------------------------------------------+
fee14197 4 | CiviCRM version 5 |
6a488035 5 +--------------------------------------------------------------------+
6b83d5bd 6 | Copyright CiviCRM LLC (c) 2004-2019 |
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
6b83d5bd 31 * @copyright CiviCRM LLC (c) 2004-2019
6a488035
TO
32 */
33
34/**
78d7cb6d 35 * Form to process actions on the field aspect of Custom.
6a488035
TO
36 */
37class CRM_UF_Form_Field extends CRM_Core_Form {
38
39 /**
fe482240 40 * The uf group id saved to the session for an update.
6a488035
TO
41 *
42 * @var int
6a488035
TO
43 */
44 protected $_gid;
45
46 /**
78d7cb6d 47 * The field id, used when editing the field.
6a488035
TO
48 *
49 * @var int
6a488035
TO
50 */
51 protected $_id;
52
53 /**
54 * The set of fields that we can view/edit in the user field framework
55 *
56 * @var array
6a488035
TO
57 */
58 protected $_fields;
59
60 /**
66f9e52b 61 * The title for field.
6a488035
TO
62 *
63 * @var int
6a488035
TO
64 */
65 protected $_title;
66
67 /**
66f9e52b 68 * The set of fields sent to the select element.
6a488035
TO
69 *
70 * @var array
6a488035
TO
71 */
72 protected $_selectFields;
73
74 /**
66f9e52b 75 * store fields with if locationtype exits status.
6a488035
TO
76 *
77 * @var array
6a488035
TO
78 */
79 protected $_hasLocationTypes;
80
81 /**
fe482240 82 * Is this profile has searchable field.
6a488035
TO
83 * or is any field having in selector true.
84 *
85 * @var boolean.
6a488035
TO
86 */
87 protected $_hasSearchableORInSelector;
88
89 /**
fe482240 90 * Set variables up before form is built.
6a488035
TO
91 *
92 * @return void
6a488035
TO
93 */
94 public function preProcess() {
95 $this->_gid = CRM_Utils_Request::retrieve('gid', 'Positive', $this);
96 $this->_id = CRM_Utils_Request::retrieve('id', 'Positive', $this);
97 if ($this->_gid) {
98 $this->_title = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_UFGroup', $this->_gid, 'title');
e2046b33
CW
99
100 $this->setPageTitle(ts('Profile Field'));
6a488035
TO
101
102 $url = CRM_Utils_System::url('civicrm/admin/uf/group/field',
103 "reset=1&action=browse&gid={$this->_gid}"
104 );
105
106 $session = CRM_Core_Session::singleton();
107 $session->pushUserContext($url);
353ffa53
TO
108 $breadCrumb = array(
109 array(
110 'title' => ts('CiviCRM Profile Fields'),
6a488035 111 'url' => $url,
af9b09df 112 ),
353ffa53 113 );
6a488035
TO
114 CRM_Utils_System::appendBreadCrumb($breadCrumb);
115 }
116
117 $showBestResult = CRM_Utils_Request::retrieve('sbr', 'Positive', CRM_Core_DAO::$_nullArray);
118 if ($showBestResult) {
119 $this->assign('showBestResult', $showBestResult);
120 }
121
122 $this->_fields = CRM_Contact_BAO_Contact::importableFields('All', TRUE, TRUE, TRUE, TRUE, TRUE);
123 $this->_fields = array_merge(CRM_Activity_BAO_Activity::exportableFields('Activity'), $this->_fields);
124
125 //unset campaign related fields.
126 if (isset($this->_fields['activity_campaign_id'])) {
127 $this->_fields['activity_campaign_id']['title'] = ts('Campaign');
128 if (isset($this->_fields['activity_campaign'])) {
129 unset($this->_fields['activity_campaign']);
130 }
131 }
132
133 if (CRM_Core_Permission::access('CiviContribute')) {
134 $this->_fields = array_merge(CRM_Contribute_BAO_Contribution::getContributionFields(FALSE), $this->_fields);
135 $this->_fields = array_merge(CRM_Core_BAO_UFField::getContribBatchEntryFields(), $this->_fields);
136 }
137
138 if (CRM_Core_Permission::access('CiviMember')) {
139 $this->_fields = array_merge(CRM_Member_BAO_Membership::getMembershipFields(), $this->_fields);
140 }
141
142 if (CRM_Core_Permission::access('CiviEvent')) {
143 $this->_fields = array_merge(CRM_Event_BAO_Query::getParticipantFields(), $this->_fields);
144 }
145
1cb28d5d 146 if (CRM_Core_Permission::access('CiviCase')) {
147 $this->_fields = array_merge(CRM_Case_BAO_Query::getFields(), $this->_fields);
148 }
149
61750d67
DS
150 $this->_fields = array_merge($this->_fields, CRM_Contact_BAO_Query_Hook::singleton()->getFields());
151
6a488035
TO
152 $this->_selectFields = array();
153 foreach ($this->_fields as $name => $field) {
154 // lets skip note for now since we dont support it
155 if ($name == 'note') {
156 continue;
157 }
158 $this->_selectFields[$name] = $field['title'];
159 $this->_hasLocationTypes[$name] = CRM_Utils_Array::value('hasLocationType', $field);
160 }
161
162 // lets add group, tag and current_employer to this list
163 $this->_selectFields['group'] = ts('Group(s)');
164 $this->_selectFields['tag'] = ts('Tag(s)');
165 $this->_selectFields['current_employer'] = ts('Current Employer');
166 $this->_selectFields['phone_and_ext'] = ts('Phone and Extension');
167
168 //CRM-4363 check for in selector or searchable fields.
169 $this->_hasSearchableORInSelector = CRM_Core_BAO_UFField::checkSearchableORInSelector($this->_gid);
170
171 $this->assign('fieldId', $this->_id);
172 if ($this->_id) {
173 $fieldTitle = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_UFField', $this->_id, 'label');
174 $this->assign('fieldTitle', $fieldTitle);
175 }
176 }
177
178 /**
fe482240 179 * Build the form object.
6a488035
TO
180 *
181 * @return void
6a488035
TO
182 */
183 public function buildQuickForm() {
184 if ($this->_action & CRM_Core_Action::DELETE) {
185 $this->addButtons(array(
c5c263ca
AH
186 array(
187 'type' => 'next',
188 'name' => ts('Delete Profile Field'),
189 'spacing' => '&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;',
190 'isDefault' => TRUE,
191 ),
192 array(
193 'type' => 'cancel',
194 'name' => ts('Cancel'),
195 ),
196 ));
6a488035
TO
197 return;
198 }
ce56006d 199 $addressCustomFields = array_keys(CRM_Core_BAO_CustomField::getFieldsForImport('Address'));
6a488035
TO
200
201 if (isset($this->_id)) {
202 $params = array('id' => $this->_id);
203 CRM_Core_BAO_UFField::retrieve($params, $defaults);
204
205 // set it to null if so (avoids crappy E_NOTICE errors below
206 $defaults['location_type_id'] = CRM_Utils_Array::value('location_type_id', $defaults);
207
30cc1b7d 208 //CRM-20861 - Include custom fields defined for address to set its default location type to 0.
ce56006d 209 $specialFields = array_merge(CRM_Core_BAO_UFGroup::getLocationFields(), $addressCustomFields);
6a488035
TO
210 if (!$defaults['location_type_id'] &&
211 $defaults["field_type"] != "Formatting" &&
212 in_array($defaults['field_name'], $specialFields)
213 ) {
214 $defaults['location_type_id'] = 0;
215 }
216
217 $defaults['field_name'] = array(
218 $defaults['field_type'],
219 ($defaults['field_type'] == "Formatting" ? "" : $defaults['field_name']),
887e764d 220 ($defaults['field_name'] == "url") ? $defaults['website_type_id'] : $defaults['location_type_id'],
6a488035
TO
221 CRM_Utils_Array::value('phone_type_id', $defaults),
222 );
223 $this->_gid = $defaults['uf_group_id'];
224 }
225 else {
226 $defaults['is_active'] = 1;
227 }
228
229 $otherModules = array_values(CRM_Core_BAO_UFGroup::getUFJoinRecord($this->_gid));
230 $this->assign('otherModules', $otherModules);
231
232 if ($this->_action & CRM_Core_Action::ADD) {
233 $fieldValues = array('uf_group_id' => $this->_gid);
234 $defaults['weight'] = CRM_Utils_Weight::getDefaultWeight('CRM_Core_DAO_UFField', $fieldValues);
235 }
236
237 // lets trim all the whitespace
238 $this->applyFilter('__ALL__', 'trim');
239
240 //hidden field to catch the group id in profile
241 $this->add('hidden', 'group_id', $this->_gid);
242
243 //hidden field to catch the field id in profile
244 $this->add('hidden', 'field_id', $this->_id);
245
246 $fields = CRM_Core_BAO_UFField::getAvailableFields($this->_gid, $defaults);
247
887e764d 248 $noSearchable = $hasWebsiteTypes = array();
6a488035
TO
249
250 foreach ($fields as $key => $value) {
251 foreach ($value as $key1 => $value1) {
252 //CRM-2676, replacing the conflict for same custom field name from different custom group.
253 if ($customFieldId = CRM_Core_BAO_CustomField::getKeyID($key1)) {
254 $customGroupId = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_CustomField', $customFieldId, 'custom_group_id');
255 $customGroupName = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_CustomGroup', $customGroupId, 'title');
256 $this->_mapperFields[$key][$key1] = $value1['title'] . ' :: ' . $customGroupName;
257 if (in_array($key1, $addressCustomFields)) {
258 $noSearchable[] = $value1['title'] . ' :: ' . $customGroupName;
259 }
260 }
261 else {
262 $this->_mapperFields[$key][$key1] = $value1['title'];
263 }
264 $hasLocationTypes[$key][$key1] = CRM_Utils_Array::value('hasLocationType', $value1);
887e764d 265 $hasWebsiteTypes[$key][$key1] = CRM_Utils_Array::value('hasWebsiteType', $value1);
6a488035
TO
266 // hide the 'is searchable' field for 'File' custom data
267 if (isset($value1['data_type']) &&
268 isset($value1['html_type']) &&
269 (($value1['data_type'] == 'File' && $value1['html_type'] == 'File')
270 || ($value1['data_type'] == 'Link' && $value1['html_type'] == 'Link')
271 )
272 ) {
273 if (!in_array($value1['title'], $noSearchable)) {
274 $noSearchable[] = $value1['title'];
275 }
276 }
277 }
278 }
279 $this->assign('noSearchable', $noSearchable);
280
b2b0530a 281 $this->_location_types = CRM_Core_PseudoConstant::get('CRM_Core_DAO_Address', 'location_type_id');
6a488035 282 $defaultLocationType = CRM_Core_BAO_LocationType::getDefault();
887e764d 283 $this->_website_types = CRM_Core_PseudoConstant::get('CRM_Core_DAO_Website', 'website_type_id');
77b97be7 284
6a488035
TO
285 /**
286 * FIXME: dirty hack to make the default option show up first. This
287 * avoids a mozilla browser bug with defaults on dynamically constructed
288 * selector widgets.
289 */
290 if ($defaultLocationType) {
291 $defaultLocation = $this->_location_types[$defaultLocationType->id];
292 unset($this->_location_types[$defaultLocationType->id]);
293 $this->_location_types = array(
af9b09df
TO
294 $defaultLocationType->id => $defaultLocation,
295 ) + $this->_location_types;
6a488035
TO
296 }
297
298 $this->_location_types = array('Primary') + $this->_location_types;
299
300 // since we need a hierarchical list to display contact types & subtypes,
301 // this is what we going to display in first selector
302 $contactTypes = CRM_Contact_BAO_ContactType::getSelectElements(FALSE, FALSE);
303 unset($contactTypes['']);
304
305 $contactTypes = !empty($contactTypes) ? array('Contact' => 'Contacts') + $contactTypes : array();
306 $sel1 = array('' => '- select -') + $contactTypes;
307
308 if (!empty($fields['Activity'])) {
309 $sel1['Activity'] = 'Activity';
310 }
311
312 if (CRM_Core_Permission::access('CiviEvent')) {
313 $sel1['Participant'] = 'Participants';
314 }
315
316 if (!empty($fields['Contribution'])) {
317 $sel1['Contribution'] = 'Contributions';
318 }
319
320 if (!empty($fields['Membership'])) {
321 $sel1['Membership'] = 'Membership';
322 }
323
1cb28d5d 324 if (!empty($fields['Case'])) {
325 $sel1['Case'] = 'Case';
326 }
327
6a488035
TO
328 if (!empty($fields['Formatting'])) {
329 $sel1['Formatting'] = 'Formatting';
330 }
331
332 foreach ($sel1 as $key => $sel) {
333 if ($key) {
334 $sel2[$key] = $this->_mapperFields[$key];
335 }
336 }
337 $sel3[''] = NULL;
b4f964d9 338 $phoneTypes = CRM_Core_PseudoConstant::get('CRM_Core_DAO_Phone', 'phone_type_id');
6a488035
TO
339 ksort($phoneTypes);
340
341 foreach ($sel1 as $k => $sel) {
342 if ($k) {
343 foreach ($this->_location_types as $key => $value) {
344 $sel4[$k]['phone'][$key] = &$phoneTypes;
345 $sel4[$k]['phone_and_ext'][$key] = &$phoneTypes;
346 }
347 }
348 }
349
350 foreach ($sel1 as $k => $sel) {
351 if ($k) {
352 if (is_array($this->_mapperFields[$k])) {
353 foreach ($this->_mapperFields[$k] as $key => $value) {
354 if ($hasLocationTypes[$k][$key]) {
355 $sel3[$k][$key] = $this->_location_types;
356 }
887e764d
PN
357 elseif ($hasWebsiteTypes[$k][$key]) {
358 $sel3[$k][$key] = $this->_website_types;
359 }
6a488035
TO
360 else {
361 $sel3[$key] = NULL;
362 }
363 }
364 }
365 }
366 }
367
368 $this->_defaults = array();
353ffa53
TO
369 $js = "<script type='text/javascript'>\n";
370 $formName = "document.{$this->_name}";
6a488035
TO
371
372 $alreadyMixProfile = FALSE;
373 if (CRM_Core_BAO_UFField::checkProfileType($this->_gid)) {
374 $alreadyMixProfile = TRUE;
375 }
376 $this->assign('alreadyMixProfile', $alreadyMixProfile);
377
378 $sel = &$this->addElement('hierselect', 'field_name', ts('Field Name'));
379
380 $formValues = $this->exportValues();
381
382 if (empty($formValues)) {
383 for ($k = 1; $k < 4; $k++) {
52e7a51a 384 if (!isset($defaults['field_name'][$k])) {
6a488035
TO
385 $js .= "{$formName}['field_name[$k]'].style.display = 'none';\n";
386 }
387 }
388 }
389 else {
390 if (!empty($formValues['field_name'])) {
52e7a51a
LS
391 for ($key = 1; $key < 4; $key++) {
392 if (!isset($formValues['field_name'][$key])) {
393 $js .= "{$formName}['field_name[$key]'].style.display = 'none';\n";
394 }
395 else {
396 $js .= "{$formName}['field_name[$key]'].style.display = '';\n";
6a488035
TO
397 }
398 }
399 }
400 else {
401 for ($k = 1; $k < 4; $k++) {
402 if (!isset($defaults['field_name'][$k])) {
403 $js .= "{$formName}['field_name[$k]'].style.display = 'none';\n";
404 }
405 }
406 }
407 }
408
409 foreach ($sel2 as $k => $v) {
410 if (is_array($sel2[$k])) {
411 asort($sel2[$k]);
412 }
413 }
414
415 $sel->setOptions(array($sel1, $sel2, $sel3, $sel4));
416
417 // proper interpretation of spec in CRM-8732
418 if (!isset($this->_id) && in_array('Search Profile', $otherModules)) {
419 $defaults['visibility'] = 'Public Pages and Listings';
420 }
421
422 $js .= "</script>\n";
423 $this->assign('initHideBoxes', $js);
424
425 $this->add('select',
426 'visibility',
427 ts('Visibility'),
428 CRM_Core_SelectValues::ufVisibility(),
429 TRUE,
430 array('onChange' => "showHideSeletorSearch(this.value);")
431 );
432
433 //CRM-4363
434 $js = array('onChange' => "mixProfile();");
435 // should the field appear in selectors (as a column)?
c5de80f1
CW
436 $this->add('advcheckbox', 'in_selector', ts('Results Column?'), NULL, NULL, $js);
437 $this->add('advcheckbox', 'is_searchable', ts('Searchable?'), NULL, NULL, $js);
6a488035
TO
438
439 $attributes = CRM_Core_DAO::getAttribute('CRM_Core_DAO_UFField');
440
441 // weight
f20d2b0d 442 $this->add('number', 'weight', ts('Order'), $attributes['weight'], TRUE);
6a488035
TO
443 $this->addRule('weight', ts('is a numeric field'), 'numeric');
444
445 $this->add('textarea', 'help_pre', ts('Field Pre Help'), $attributes['help_pre']);
446 $this->add('textarea', 'help_post', ts('Field Post Help'), $attributes['help_post']);
447
c5de80f1 448 $this->add('advcheckbox', 'is_required', ts('Required?'));
6a488035 449
c5de80f1
CW
450 $this->add('advcheckbox', 'is_multi_summary', ts('Include in multi-record listing?'));
451 $this->add('advcheckbox', 'is_active', ts('Active?'));
452 $this->add('advcheckbox', 'is_view', ts('View Only?'));
6a488035
TO
453
454 $this->add('text', 'label', ts('Field Label'), $attributes['label']);
455
456 $js = NULL;
457 if ($this->_hasSearchableORInSelector) {
458 $js = array('onclick' => "return verify( );");
459 }
460
461 // add buttons
462 $this->addButtons(array(
c5c263ca
AH
463 array(
464 'type' => 'next',
465 'name' => ts('Save'),
466 'isDefault' => TRUE,
467 'js' => $js,
468 ),
469 array(
470 'type' => 'next',
471 'name' => ts('Save and New'),
472 'subName' => 'new',
473 'js' => $js,
474 ),
475 array(
476 'type' => 'cancel',
477 'name' => ts('Cancel'),
478 ),
479 ));
6a488035
TO
480
481 $this->addFormRule(array('CRM_UF_Form_Field', 'formRule'), $this);
482
483 // if view mode pls freeze it with the done button.
484 if ($this->_action & CRM_Core_Action::VIEW) {
485 $this->freeze();
486 $this->addElement('button', 'done', ts('Done'),
487 array('onclick' => "location.href='civicrm/admin/uf/group/field?reset=1&action=browse&gid=" . $this->_gid . "'")
488 );
489 }
490
6a488035
TO
491 $this->setDefaults($defaults);
492 }
493
494 /**
fe482240 495 * Process the form.
6a488035
TO
496 *
497 * @return void
6a488035
TO
498 */
499 public function postProcess() {
78d7cb6d 500
6a488035
TO
501 if ($this->_action & CRM_Core_Action::DELETE) {
502 $fieldValues = array('uf_group_id' => $this->_gid);
503 CRM_Utils_Weight::delWeight('CRM_Core_DAO_UFField', $this->_id, $fieldValues);
353ffa53 504 $deleted = CRM_Core_BAO_UFField::del($this->_id);
6a488035
TO
505
506 //update group_type every time. CRM-3608
507 if ($this->_gid && $deleted) {
508 //get the profile type.
509 $fieldsType = CRM_Core_BAO_UFGroup::calculateGroupType($this->_gid, TRUE);
510 CRM_Core_BAO_UFGroup::updateGroupTypes($this->_gid, $fieldsType);
511 }
512
513 CRM_Core_Session::setStatus(ts('Selected Profile Field has been deleted.'), ts('Profile Field Deleted'), 'success');
514 return;
515 }
516
517 // store the submitted values in an array
518 $params = $this->controller->exportValues('Field');
78d7cb6d 519 $params['uf_group_id'] = $this->_gid;
6a488035
TO
520 if ($params['visibility'] == 'User and User Admin Only') {
521 $params['is_searchable'] = $params['in_selector'] = 0;
522 }
523
524 if ($this->_action & CRM_Core_Action::UPDATE) {
78d7cb6d 525 $params['id'] = $this->_id;
6a488035
TO
526 }
527
6a488035 528 $name = NULL;
f06c4974 529 if (isset($params['field_name'][1]) && isset($this->_selectFields[$params['field_name'][1]])) {
6a488035
TO
530 // we dont get a name for a html formatting element
531 $name = $this->_selectFields[$params['field_name'][1]];
532 }
533
534 //Hack for Formatting Field Name
535 if ($params['field_name'][0] == 'Formatting') {
78580003
SB
536 $fieldName = 'formatting_' . rand(1000, 9999);
537 }
538 else {
539 $fieldName = $params['field_name'][1];
6a488035
TO
540 }
541
6a488035 542 //check for duplicate fields
b99bd217
ASB
543 $apiFormattedParams = $params;
544 $apiFormattedParams['field_type'] = $params['field_name'][0];
78580003 545 $apiFormattedParams['field_name'] = $fieldName;
b99bd217 546 if (!empty($params['field_name'][2])) {
78580003 547 if ($fieldName === 'url') {
b99bd217
ASB
548 $apiFormattedParams['website_type_id'] = $params['field_name'][2];
549 }
550 else {
551 $apiFormattedParams['location_type_id'] = $params['field_name'][2];
552 }
553 }
2e74ff55
SP
554 elseif ($params['field_name'][2] == 0) {
555 // 0 is Primary location type
556 $apiFormattedParams['location_type_id'] = NULL;
557 }
b99bd217
ASB
558 if (!empty($params['field_name'][3])) {
559 $apiFormattedParams['phone_type_id'] = $params['field_name'][3];
560 }
561
562 if ($apiFormattedParams['field_type'] != "Formatting" && CRM_Core_BAO_UFField::duplicateField($apiFormattedParams)) {
563 CRM_Core_Error::statusBounce(ts('The selected field already exists in this profile.'), NULL, ts('Field Not Added'));
6a488035
TO
564 }
565 else {
78580003
SB
566 $apiFormattedParams['weight'] = CRM_Core_BAO_UFField::autoWeight($params);
567 civicrm_api3('UFField', 'create', $apiFormattedParams);
6a488035
TO
568
569 //reset other field is searchable and in selector settings, CRM-4363
570 if ($this->_hasSearchableORInSelector &&
78580003 571 in_array($apiFormattedParams['field_type'], array('Participant', 'Contribution', 'Membership', 'Activity', 'Case'))
6a488035
TO
572 ) {
573 CRM_Core_BAO_UFField::resetInSelectorANDSearchable($this->_gid);
574 }
575
78580003 576 $this->setMessageIfCountryNotAboveState($fieldName, CRM_Utils_Array::value('location_type_id', $apiFormattedParams), $apiFormattedParams['weight'], $apiFormattedParams['uf_group_id']);
6a488035 577
6a488035 578 CRM_Core_Session::setStatus(ts('Your CiviCRM Profile Field \'%1\' has been saved to \'%2\'.',
353ffa53
TO
579 array(1 => $name, 2 => $this->_title)
580 ), ts('Profile Field Saved'), 'success');
6a488035
TO
581 }
582 $buttonName = $this->controller->getButtonName();
583
584 $session = CRM_Core_Session::singleton();
585 if ($buttonName == $this->getButtonName('next', 'new')) {
6a488035 586 $session->replaceUserContext(CRM_Utils_System::url('civicrm/admin/uf/group/field/add',
78580003 587 "reset=1&action=add&gid={$this->_gid}"
353ffa53 588 ));
6a488035
TO
589 }
590 else {
591 $session->replaceUserContext(CRM_Utils_System::url('civicrm/admin/uf/group/field',
353ffa53
TO
592 "reset=1&action=browse&gid={$this->_gid}"
593 ));
6a488035
TO
594 }
595 }
596
597 /**
100fef9d 598 * Validation rule for subtype.
6a488035 599 *
5ce1712d
TO
600 * @param string $fieldType
601 * Type of field.
a1a2a83d
TO
602 * @param array $groupType
603 * Contains all groupTypes.
6a488035 604 * @param array $errors
a1a2a83d 605 * List of errors to be posted back to the form.
6a488035 606 */
a1a2a83d 607 public static function formRuleSubType($fieldType, $groupType, &$errors) {
6a488035 608 if (in_array($fieldType, array(
353ffa53
TO
609 'Participant',
610 'Contribution',
611 'Membership',
a130e045 612 'Activity',
353ffa53 613 ))) {
6a488035
TO
614 $individualSubTypes = CRM_Contact_BAO_ContactType::subTypes('Individual');
615 foreach ($groupType as $value) {
616 if (!in_array($value, $individualSubTypes) &&
617 !in_array($value, array(
353ffa53
TO
618 'Participant',
619 'Contribution',
620 'Membership',
621 'Individual',
622 'Contact',
623 'Activity',
8d172516 624 'Formatting',
353ffa53 625 ))
6a488035 626 ) {
8d172516 627 $errors['field_name'] = ts('Cannot add or update profile field "%1" with combination of Household or Organization or any subtypes of Household or Organization.', array(1 => $fieldType));
6a488035
TO
628 break;
629 }
630 }
631 }
632 else {
633 $basicType = CRM_Contact_BAO_ContactType::getBasicType($groupType);
634 if ($basicType) {
635 if (!is_array($basicType)) {
636 $basicType = array($basicType);
637 }
1be099c7 638 if (!in_array($fieldType, $basicType) && $fieldType != 'Contact') {
6a488035
TO
639 $errors['field_name'] = ts('Cannot add or update profile field type "%1" with combination of subtype other than "%1".',
640 array(1 => $fieldType)
641 );
642 }
643 }
644 }
645 }
646
647 /**
100fef9d 648 * Validation rule for custom data extends entity column values.
6a488035 649 *
5ce1712d
TO
650 * @param Object $customField
651 * Custom field.
652 * @param int $gid
653 * Group Id.
654 * @param string $fieldType
655 * Group type of the field.
656 * @param array $errors
657 * Collect errors.
6a488035 658 *
a130e045 659 * @return array
a6c01b45 660 * list of errors to be posted back to the form
6a488035 661 */
00be9182 662 public static function formRuleCustomDataExtentColumnValue($customField, $gid, $fieldType, &$errors) {
6a488035
TO
663 // fix me : check object $customField
664 if (in_array($fieldType, array(
353ffa53
TO
665 'Participant',
666 'Contribution',
667 'Membership',
668 'Activity',
a130e045 669 'Case',
353ffa53 670 ))) {
6a488035
TO
671 $params = array('id' => $customField->custom_group_id);
672 $customGroup = array();
673 CRM_Core_BAO_CustomGroup::retrieve($params, $customGroup);
8cc574cf 674 if (($fieldType != CRM_Utils_Array::value('extends', $customGroup)) || empty($customGroup['extends_entity_column_value'])) {
6a488035
TO
675 return $errors;
676 }
677
678 $extendsColumnValues = array();
679 foreach (explode(CRM_Core_DAO::VALUE_SEPARATOR, $customGroup['extends_entity_column_value']) as $val) {
680 if ($val) {
681 $extendsColumnValues[] = $val;
682 }
683 }
684
685 if (empty($extendsColumnValues)) {
686 return $errors;
687 }
688
689 $fieldTypeValues = CRM_Core_BAO_UFGroup::groupTypeValues($gid, $fieldType);
a7488080 690 if (empty($fieldTypeValues[$fieldType])) {
6a488035
TO
691 return;
692 }
693
694 $disallowedTypes = array_diff($extendsColumnValues, $fieldTypeValues[$fieldType]);
695 if (!empty($disallowedTypes)) {
696 $errors['field_name'] = ts('Profile is already having custom fields extending different group types, you can not add or update this custom field.');
697 }
698 }
699 }
700
b29a9e66 701 /**
fdcc5d07 702 * Validation rule to prevent multiple fields of primary location type within the same communication type.
b29a9e66 703 *
5ce1712d
TO
704 * @param array $fields
705 * Submitted fields.
706 * @param string $profileFieldName
707 * Group Id.
708 * @param array $groupFields
709 * List of fields already in the group.
710 * @param array $errors
711 * Collect errors.
b29a9e66 712 *
b29a9e66 713 */
00be9182 714 public static function formRulePrimaryCheck($fields, $profileFieldName, $groupFields, &$errors) {
b29a9e66
LS
715 //FIXME: This may need to also apply to website fields if they are refactored to allow more than one per profile
716 $checkPrimary = array('phone' => 'civicrm_phone.phone', 'phone_and_ext' => 'civicrm_phone.phone');
717 $whereCheck = NULL;
718 $primaryOfSameTypeFound = NULL;
fdcc5d07 719 $fieldID = empty($fields['field_id']) ? 0 : $fields['field_id'];
b29a9e66
LS
720 // Is this a primary location type field of interest
721 if (array_key_exists($profileFieldName, $checkPrimary)) {
722 $whereCheck = $checkPrimary[$profileFieldName];
723 }
724 $potentialLocationType = CRM_Utils_Array::value(2, $fields['field_name']);
725
726 if ($whereCheck && $potentialLocationType == 0) {
727 $primaryOfSameTypeFound = '';
728
729 foreach ($groupFields as $groupField) {
730 // if it is a phone
9147c186 731 if ($groupField['where'] == $whereCheck && is_null($groupField['location_type_id']) && $groupField['field_id'] != $fieldID) {
b29a9e66 732 $primaryOfSameTypeFound = $groupField['title'];
fdcc5d07 733 break;
b29a9e66
LS
734 }
735 }
736 if ($primaryOfSameTypeFound) {
e7af4e09 737 $errors['field_name'] = ts('You have already added a primary location field of this type: %1', array(1 => $primaryOfSameTypeFound));
b29a9e66
LS
738 }
739 }
740 }
741
6a488035 742 /**
fe482240 743 * Global validation rules for the form.
6a488035 744 *
5ce1712d
TO
745 * @param array $fields
746 * Posted values of the form.
6a488035 747 *
77b97be7
EM
748 * @param $files
749 * @param $self
750 *
a6c01b45
CW
751 * @return array
752 * list of errors to be posted back to the form
6a488035 753 */
00be9182 754 public static function formRule($fields, $files, $self) {
353ffa53 755 $is_required = CRM_Utils_Array::value('is_required', $fields, FALSE);
6a488035 756 $is_registration = CRM_Utils_Array::value('is_registration', $fields, FALSE);
353ffa53
TO
757 $is_view = CRM_Utils_Array::value('is_view', $fields, FALSE);
758 $in_selector = CRM_Utils_Array::value('in_selector', $fields, FALSE);
759 $is_active = CRM_Utils_Array::value('is_active', $fields, FALSE);
6a488035
TO
760
761 $errors = array();
762 if ($is_view && $is_registration) {
763 $errors['is_registration'] = ts('View Only cannot be selected if this field is to be included on the registration form');
764 }
765 if ($is_view && $is_required) {
766 $errors['is_view'] = ts('A View Only field cannot be required');
767 }
768
b29a9e66
LS
769 $entityName = $fields['field_name'][0];
770 if (!$entityName) {
6a488035
TO
771 $errors['field_name'] = ts('Please select a field name');
772 }
773
b29a9e66 774 if ($in_selector && in_array($entityName, array(
c5c263ca
AH
775 'Contribution',
776 'Participant',
777 'Membership',
778 'Activity',
779 ))
353ffa53 780 ) {
ee7ef8b2 781 $errors['in_selector'] = ts("'Results Column' cannot be checked for %1 fields.", array(1 => $entityName));
6a488035
TO
782 }
783
784 $isCustomField = FALSE;
785 $profileFieldName = CRM_Utils_Array::value(1, $fields['field_name']);
786 if ($profileFieldName) {
787 //get custom field id
788 $customFieldId = explode('_', $profileFieldName);
789 if ($customFieldId[0] == 'custom') {
790 $customField = new CRM_Core_DAO_CustomField();
791 $customField->id = $customFieldId[1];
792 $customField->find(TRUE);
793 $isCustomField = TRUE;
794 if (!empty($fields['field_id']) && !$customField->is_active && $is_active) {
795 $errors['field_name'] = ts('Cannot set this field "Active" since the selected custom field is disabled.');
796 }
797
798 //check if profile already has a different multi-record custom set field configured
799 $customGroupId = CRM_Core_BAO_CustomField::isMultiRecordField($profileFieldName);
800 if ($customGroupId) {
801 if ($profileMultiRecordCustomGid = CRM_Core_BAO_UFField::checkMultiRecordFieldExists($self->_gid)) {
802 if ($customGroupId != $profileMultiRecordCustomGid) {
803 $errors['field_name'] = ts("You cannot configure multi-record custom fields belonging to different custom sets in one profile");
804 }
805 }
806 }
807 }
808 }
809
b29a9e66
LS
810 // Get list of fields already in the group
811 $groupFields = CRM_Core_BAO_UFGroup::getFields($fields['group_id'], FALSE, NULL, NULL, NULL, TRUE, NULL, TRUE);
812 // Check if we already added a primary field of the same communication type
fdcc5d07 813 self::formRulePrimaryCheck($fields, $profileFieldName, $groupFields, $errors);
b29a9e66 814
6a488035
TO
815 //check profile is configured for double option process
816 //adding group field, email field should be present in the group
817 //fixed for issue CRM-2861 & CRM-4153
818 if (CRM_Core_BAO_UFGroup::isProfileDoubleOptin()) {
50c3e74b 819 if (CRM_Utils_Array::value(1, $fields['field_name']) == 'group') {
6a488035
TO
820 $dao = new CRM_Core_BAO_UFField();
821 $dao->uf_group_id = $fields['group_id'];
822 $dao->find();
823 $emailField = FALSE;
824 while ($dao->fetch()) {
825 //check email field is present in the group
826 if ($dao->field_name == 'email') {
827 $emailField = TRUE;
828 break;
829 }
830 }
831
832 if (!$emailField) {
833 $disableSettingURL = CRM_Utils_System::url(
834 'civicrm/admin/setting/preferences/mailing',
835 'reset=1'
836 );
837
838 $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>', array(1 => $disableSettingURL));
839 }
840 }
841 }
842
843 //fix for CRM-3037
844 $fieldType = $fields['field_name'][0];
845
846 //get the group type.
847 $groupType = CRM_Core_BAO_UFGroup::calculateGroupType($self->_gid, FALSE, CRM_Utils_Array::value('field_id', $fields));
848
849 switch ($fieldType) {
850 case 'Contact':
851 self::formRuleSubType($fieldType, $groupType, $errors);
852 break;
853
854 case 'Individual':
855 if (in_array('Activity', $groupType) ||
856 in_array('Household', $groupType) ||
857 in_array('Organization', $groupType)
858 ) {
859
860 //CRM-7603 - need to support activity + individual.
861 //$errors['field_name'] =
862 //ts( 'Cannot add or update profile field type Individual with combination of Household or Organization or Activity' );
863 if (in_array('Household', $groupType) ||
864 in_array('Organization', $groupType)
865 ) {
866 $errors['field_name'] = ts('Cannot add or update profile field type Individual with combination of Household or Organization');
867 }
868 }
869 else {
870 self::formRuleSubType($fieldType, $groupType, $errors);
871 }
872 break;
873
874 case 'Household':
875 if (in_array('Activity', $groupType) || in_array('Individual', $groupType) || in_array('Organization', $groupType)) {
876 $errors['field_name'] = ts('Cannot add or update profile field type Household with combination of Individual or Organization or Activity');
877 }
878 else {
879 self::formRuleSubType($fieldType, $groupType, $errors);
880 }
881 break;
882
883 case 'Organization':
884 if (in_array('Activity', $groupType) || in_array('Household', $groupType) || in_array('Individual', $groupType)) {
885 $errors['field_name'] = ts('Cannot add or update profile field type Organization with combination of Household or Individual or Activity');
886 }
887 else {
888 self::formRuleSubType($fieldType, $groupType, $errors);
889 }
890 break;
891
892 case 'Activity':
893 if (in_array('Individual', $groupType) ||
894 in_array('Membership', $groupType) ||
895 in_array('Contribution', $groupType) ||
896 in_array('Organization', $groupType) ||
897 in_array('Household', $groupType) ||
898 in_array('Participant', $groupType)
899 ) {
900
901 //CRM-7603 - need to support activity + contact type.
902 //$errors['field_name'] =
903 //ts( 'Cannot add or update profile field type Activity with combination Participant or Membership or Contribution or Household or Organization or Individual' );
904 if (in_array('Membership', $groupType) ||
905 in_array('Contribution', $groupType) ||
906 in_array('Participant', $groupType)
907 ) {
908 $errors['field_name'] = ts('Cannot add or update profile field type Activity with combination Participant or Membership or Contribution');
909 }
910 }
911 else {
912 self::formRuleSubType($fieldType, $groupType, $errors);
913 }
914
915 if ($isCustomField && !isset($errors['field_name'])) {
916 self::formRuleCustomDataExtentColumnValue($customField, $self->_gid, $fieldType, $errors);
917 }
918 break;
919
920 case 'Participant':
921 if (in_array('Membership', $groupType) || in_array('Contribution', $groupType)
922 || in_array('Organization', $groupType) || in_array('Household', $groupType) || in_array('Activity', $groupType)
923 ) {
7132ac1f 924 $errors['field_name'] = ts('Cannot add or update profile field type Participant with combination of Activity or Membership or Contribution or Household or Organization.');
6a488035
TO
925 }
926 else {
927 self::formRuleSubType($fieldType, $groupType, $errors);
928 }
929 break;
930
931 case 'Contribution':
932 //special case where in we allow contribution + oganization fields, for on behalf feature
933 $profileId = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_UFGroup',
934 'on_behalf_organization', 'id', 'name'
935 );
936
937 if (in_array('Participant', $groupType) || in_array('Membership', $groupType)
938 || ($profileId != $self->_gid && in_array('Organization', $groupType)) || in_array('Household', $groupType) || in_array('Activity', $groupType)
939 ) {
940 $errors['field_name'] = ts('Cannot add or update profile field type Contribution with combination of Activity or Membership or Participant or Household or Organization');
941 }
942 else {
943 self::formRuleSubType($fieldType, $groupType, $errors);
944 }
945 break;
946
947 case 'Membership':
948 //special case where in we allow contribution + oganization fields, for on behalf feature
949 $profileId = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_UFGroup',
950 'on_behalf_organization', 'id', 'name'
951 );
952
953 if (in_array('Participant', $groupType) || in_array('Contribution', $groupType)
954 || ($profileId != $self->_gid && in_array('Organization', $groupType)) || in_array('Household', $groupType) || in_array('Activity', $groupType)
955 ) {
956 $errors['field_name'] = ts('Cannot add or update profile field type Membership with combination of Activity or Participant or Contribution or Household or Organization');
957 }
958 else {
959 self::formRuleSubType($fieldType, $groupType, $errors);
960 }
961 break;
962
963 default:
964 $profileType = CRM_Core_BAO_UFField::getProfileType($fields['group_id'], TRUE, FALSE, TRUE);
965 if (CRM_Contact_BAO_ContactType::isaSubType($fieldType)) {
966 if (CRM_Contact_BAO_ContactType::isaSubType($profileType)) {
967 if ($fieldType != $profileType) {
353ffa53 968 $errors['field_name'] = ts('Cannot add or update profile field type "%1" with combination of "%2".', array(
c5c263ca
AH
969 1 => $fieldType,
970 2 => $profileType,
971 ));
6a488035
TO
972 }
973 }
974 else {
975 $basicType = CRM_Contact_BAO_ContactType::getBasicType($fieldType);
976 if ($profileType &&
977 $profileType != $basicType &&
978 $profileType != 'Contact'
979 ) {
353ffa53 980 $errors['field_name'] = ts('Cannot add or update profile field type "%1" with combination of "%2".', array(
c5c263ca
AH
981 1 => $fieldType,
982 2 => $profileType,
983 ));
6a488035
TO
984 }
985 }
986 }
50c3e74b
DL
987 elseif (
988 CRM_Utils_Array::value(1, $fields['field_name']) == 'contact_sub_type' &&
989 !in_array($profileType, array('Individual', 'Household', 'Organization')) &&
6a488035
TO
990 !in_array($profileType, CRM_Contact_BAO_ContactType::subTypes())
991 ) {
992 $errors['field_name'] = ts('Cannot add or update profile field Contact Subtype as profile type is not one of Individual, Household or Organization.');
993 }
994 }
995 return empty($errors) ? TRUE : $errors;
996 }
96025800 997
78580003
SB
998 /**
999 * Set a message warning the user about putting country first to render states, if required.
1000 *
1001 * @param string $fieldName
1002 * @param int $locationTypeID
1003 * @param int $weight
1004 * @param int $ufGroupID
1005 */
1006 protected function setMessageIfCountryNotAboveState($fieldName, $locationTypeID, $weight, $ufGroupID) {
1007 $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.');
1008
1009 if (in_array($fieldName, array(
1010 'country',
1011 'state_province',
1012 )) && count(CRM_Core_Config::singleton()->countryLimit) > 1
1013 ) {
1014 // get state or country field weight if exists
1015 $ufFieldDAO = new CRM_Core_DAO_UFField();
1016 $ufFieldDAO->field_name = ($fieldName == 'state_province' ? 'country' : 'state_province');
1017 $ufFieldDAO->location_type_id = $locationTypeID;
1018 $ufFieldDAO->uf_group_id = $ufGroupID;
1019
1020 if ($ufFieldDAO->find(TRUE)) {
1021 if ($ufFieldDAO->field_name == 'country' && $ufFieldDAO->weight > $weight) {
1022 CRM_Core_Session::setStatus($message);
1023 }
1024 elseif ($ufFieldDAO->field_name == 'state_province' && $ufFieldDAO->weight < $weight) {
1025 CRM_Core_Session::setStatus($message);
1026 }
1027 }
1028 }
1029 }
1030
6a488035 1031}