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