Merge pull request #3208 from eileenmcnaughton/comments
[civicrm-core.git] / CRM / Custom / Form / Field.php
CommitLineData
6a488035
TO
1<?php
2/*
3 +--------------------------------------------------------------------+
06b69b18 4 | CiviCRM version 4.5 |
6a488035 5 +--------------------------------------------------------------------+
06b69b18 6 | Copyright CiviCRM LLC (c) 2004-2014 |
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 +--------------------------------------------------------------------+
26*/
27
28/**
29 *
30 * @package CRM
06b69b18 31 * @copyright CiviCRM LLC (c) 2004-2014
6a488035
TO
32 * $Id$
33 *
34 */
35
36/**
37 * form to process actions on the field aspect of Custom
38 */
39class CRM_Custom_Form_Field extends CRM_Core_Form {
40
41 /**
42 * Constants for number of options for data types of multiple option.
43 */
44 CONST NUM_OPTION = 11;
45
46 /**
47 * the custom group id saved to the session for an update
48 *
49 * @var int
50 * @access protected
51 */
52 protected $_gid;
53
54 /**
55 * The field id, used when editing the field
56 *
57 * @var int
58 * @access protected
59 */
60 protected $_id;
61
62 /**
63 * The default custom data/input types, when editing the field
64 *
65 * @var array
66 * @access protected
67 */
68 protected $_defaultDataType;
69
70 /**
71 * array of custom field values if update mode
72 */
73 protected $_values;
74
75 /**
76 * Array for valid combinations of data_type & html_type
77 *
78 * @var array
79 * @static
80 */
81 private static $_dataTypeValues = NULL;
82 private static $_dataTypeKeys = NULL;
83
84 private static $_dataToHTML = NULL;
85
86 private static $_dataToLabels = NULL;
87
88 /**
89 * Function to set variables up before form is built
90 *
91 * @param null
92 *
93 * @return void
94 * @access public
95 */
96 public function preProcess() {
97 if (!(self::$_dataTypeKeys)) {
98 self::$_dataTypeKeys = array_keys(CRM_Core_BAO_CustomField::dataType());
99 self::$_dataTypeValues = array_values(CRM_Core_BAO_CustomField::dataType());
100 }
101
102 if (!self::$_dataToHTML) {
103 self::$_dataToHTML = CRM_Core_BAO_CustomField::dataToHtml();
104 }
105
2b83aa0d
CW
106 //custom field id
107 $this->_id = CRM_Utils_Request::retrieve('id', 'Positive', $this);
108
109 $this->_values = array();
110 //get the values form db if update.
111 if ($this->_id) {
112 $params = array('id' => $this->_id);
113 CRM_Core_BAO_CustomField::retrieve($params, $this->_values);
114 // note_length is an alias for the text_length field
115 $this->_values['note_length'] = CRM_Utils_Array::value('text_length', $this->_values);
116 // custom group id
117 $this->_gid = $this->_values['custom_group_id'];
118 }
119 else {
120 // custom group id
121 $this->_gid = CRM_Utils_Request::retrieve('gid', 'Positive', $this);
122 }
6a488035 123
d06700a7 124 if ($isReserved = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_CustomGroup', $this->_gid, 'is_reserved', 'id')) {
e89941dc 125 CRM_Core_Error::fatal("You cannot add or edit fields in a reserved custom field-set.");
d06700a7
RN
126 }
127
6a488035
TO
128 if ($this->_gid) {
129 $url = CRM_Utils_System::url('civicrm/admin/custom/group/field',
130 "reset=1&action=browse&gid={$this->_gid}"
131 );
132
133 $session = CRM_Core_Session::singleton();
134 $session->pushUserContext($url);
135 }
136
6a488035
TO
137 if (self::$_dataToLabels == NULL) {
138 self::$_dataToLabels = array(
139 array('Text' => ts('Text'), 'Select' => ts('Select'),
140 'Radio' => ts('Radio'), 'CheckBox' => ts('CheckBox'), 'Multi-Select' => ts('Multi-Select'),
141 'AdvMulti-Select' => ts('Advanced Multi-Select'),
142 'Autocomplete-Select' => ts('Autocomplete Select'),
143 ),
144 array('Text' => ts('Text'), 'Select' => ts('Select'),
145 'Radio' => ts('Radio'),
146 ),
147 array('Text' => ts('Text'), 'Select' => ts('Select'),
148 'Radio' => ts('Radio'),
149 ),
150 array('Text' => ts('Text'), 'Select' => ts('Select'),
151 'Radio' => ts('Radio'),
152 ),
153 array('TextArea' => ts('TextArea'), 'RichTextEditor' => 'RichTextEditor'),
154 array('Date' => ts('Select Date')),
155 array('Radio' => ts('Radio')),
156 array('StateProvince' => ts('Select State/Province'), 'Multi-Select' => ts('Multi-Select State/Province')),
157 array('Country' => ts('Select Country'), 'Multi-Select' => ts('Multi-Select Country ')),
158 array('File' => ts('Select File')),
159 array('Link' => ts('Link')),
160 array('ContactReference' => ts('Autocomplete Select')),
161 );
162 }
163 }
164
165 /**
166 * This function sets the default values for the form. Note that in edit/view mode
167 * the default values are retrieved from the database
168 *
169 * @param null
170 *
171 * @return array array of default values
172 * @access public
173 */
174 function setDefaultValues() {
175 $defaults = $this->_values;
176
177 if ($this->_id) {
178 $this->assign('id', $this->_id);
179 $this->_gid = $defaults['custom_group_id'];
180
181 //get the value for state or country
182 if ($defaults['data_type'] == 'StateProvince' &&
183 $stateId = CRM_Utils_Array::value('default_value', $defaults)
184 ) {
185 $defaults['default_value'] = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_StateProvince', $stateId);
186 }
187 elseif ($defaults['data_type'] == 'Country' &&
188 $countryId = CRM_Utils_Array::value('default_value', $defaults)
189 ) {
190 $defaults['default_value'] = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_Country', $countryId);
191 }
192
8cc574cf 193 if ($defaults['data_type'] == 'ContactReference' && !empty($defaults['filter'])) {
6a488035
TO
194 $contactRefFilter = 'Advance';
195 if (strpos($defaults['filter'], 'action=lookup') !== FALSE &&
196 strpos($defaults['filter'], 'group=') !== FALSE
197 ) {
198 $filterParts = explode('&', $defaults['filter']);
199
200 if (count($filterParts) == 2) {
201 $contactRefFilter = 'Group';
202 foreach ($filterParts as $part) {
203 if (strpos($part, 'group=') === FALSE) {
204 continue;
205 }
206 $groups = substr($part, strpos($part, '=') + 1);
207 foreach (explode(',', $groups) as $grp) {
208 if (CRM_Utils_Rule::positiveInteger($grp)) {
209 $defaults['group_id'][] = $grp;
210 }
211 }
212 }
213 }
214 }
215 $defaults['filter_selected'] = $contactRefFilter;
216 }
217
a7488080 218 if (!empty($defaults['data_type'])) {
6a488035
TO
219 $defaultDataType = array_search($defaults['data_type'],
220 self::$_dataTypeKeys
221 );
222 $defaultHTMLType = array_search($defaults['html_type'],
223 self::$_dataToHTML[$defaultDataType]
224 );
225 $defaults['data_type'] = array(
226 '0' => $defaultDataType,
227 '1' => $defaultHTMLType,
228 );
229 $this->_defaultDataType = $defaults['data_type'];
230 }
231
232 $defaults['option_type'] = 2;
233
234 $this->assign('changeFieldType', CRM_Custom_Form_ChangeFieldType::fieldTypeTransitions($this->_values['data_type'], $this->_values['html_type']));
235 }
236 else {
237 $defaults['is_active'] = 1;
238 $defaults['option_type'] = 1;
239 }
240
241 // set defaults for weight.
242 for ($i = 1; $i <= self::NUM_OPTION; $i++) {
243 $defaults['option_status[' . $i . ']'] = 1;
244 $defaults['option_weight[' . $i . ']'] = $i;
245 }
246
247 if ($this->_action & CRM_Core_Action::ADD) {
248 $fieldValues = array('custom_group_id' => $this->_gid);
249 $defaults['weight'] = CRM_Utils_Weight::getDefaultWeight('CRM_Core_DAO_CustomField', $fieldValues);
250
251 $defaults['text_length'] = 255;
252 $defaults['note_columns'] = 60;
253 $defaults['note_rows'] = 4;
254 $defaults['is_view'] = 0;
255 }
256
a7488080 257 if (!empty($defaults['html_type'])) {
6a488035
TO
258 $dontShowLink = substr($defaults['html_type'], -14) == 'State/Province' || substr($defaults['html_type'], -7) == 'Country' ? 1 : 0;
259 }
260
261 if (isset($dontShowLink)) {
262 $this->assign('dontShowLink', $dontShowLink);
263 }
e41f4660
PJ
264 if ($this->_action & CRM_Core_Action::ADD &&
265 CRM_Core_DAO::getFieldValue('CRM_Core_DAO_CustomGroup', $this->_gid, 'is_multiple', 'id')) {
5a205b89
PJ
266 $defaults['in_selector'] = 1;
267 }
268
6a488035
TO
269 return $defaults;
270 }
271
272 /**
273 * Function to actually build the form
274 *
275 * @param null
276 *
277 * @return void
278 * @access public
279 */
280 public function buildQuickForm() {
281 if ($this->_gid) {
282 $this->_title = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_CustomGroup', $this->_gid, 'title');
f84151fd 283 CRM_Utils_System::setTitle($this->_title . ' - ' . ($this->_id ? ts('Edit Field') : ts('Add Field')));
fa3a5fe2 284 $this->assign('gid', $this->_gid);
6a488035
TO
285 }
286
287 // lets trim all the whitespace
288 $this->applyFilter('__ALL__', 'trim');
289
290 $attributes = CRM_Core_DAO::getAttribute('CRM_Core_DAO_CustomField');
291
292 // label
293 $this->add('text',
294 'label',
295 ts('Field Label'),
296 $attributes['label'],
297 TRUE
298 );
299
300 $dt = &self::$_dataTypeValues;
301 $it = array();
302 foreach ($dt as $key => $value) {
303 $it[$key] = self::$_dataToLabels[$key];
304 }
305 $sel = &$this->addElement('hierselect',
306 'data_type',
307 ts('Data and Input Field Type'),
308 'onclick="clearSearchBoxes();custom_option_html_type(this.form)"; onBlur="custom_option_html_type(this.form)";',
309 '&nbsp;&nbsp;&nbsp;'
310 );
311 $sel->setOptions(array($dt, $it));
5a205b89
PJ
312
313 if (CRM_Core_DAO::getFieldValue('CRM_Core_DAO_CustomGroup', $this->_gid, 'is_multiple')) {
314 $this->add('checkbox', 'in_selector', ts('Display in Table?'));
315 }
316
6a488035
TO
317 if ($this->_action == CRM_Core_Action::UPDATE) {
318 $this->freeze('data_type');
319 }
320 $includeFieldIds = NULL;
321 if ($this->_action == CRM_Core_Action::UPDATE) {
322 $includeFieldIds = $this->_values['id'];
323 }
324 $optionGroups = CRM_Core_BAO_CustomField::customOptionGroup($includeFieldIds);
325 $emptyOptGroup = FALSE;
326 if (empty($optionGroups)) {
327 $emptyOptGroup = TRUE;
328 $optionTypes = array('1' => ts('Create a new set of options'));
329 }
330 else {
331 $optionTypes = array('1' => ts('Create a new set of options'),
332 '2' => ts('Reuse an existing set'),
333 );
334
335 $this->add('select',
336 'option_group_id',
337 ts('Multiple Choice Option Sets'),
338 array(
339 '' => ts('- select -')) + $optionGroups
340 );
341 }
342
343 $element = &$this->addRadio('option_type',
344 ts('Option Type'),
345 $optionTypes,
346 array(
347 'onclick' => "showOptionSelect();"), '<br/>'
348 );
349
350
351 $contactGroups = CRM_Core_PseudoConstant::group();
352 asort($contactGroups);
353
354 $this->add('select',
355 'group_id',
356 ts('Limit List to Group'),
357 $contactGroups,
358 FALSE,
359 array('multiple' => 'multiple')
360 );
361
362 $this->add('text',
363 'filter',
364 ts('Advanced Filter'),
365 $attributes['filter']
366 );
367
368 $this->add('hidden', 'filter_selected', 'Group', array('id' => 'filter_selected'));
369
370 //if empty option group freeze the option type.
371 if ($emptyOptGroup) {
372 $element->freeze();
373 }
374
375 // form fields of Custom Option rows
376 $defaultOption = array();
377 $_showHide = new CRM_Core_ShowHideBlocks('', '');
378 for ($i = 1; $i <= self::NUM_OPTION; $i++) {
379
380 //the show hide blocks
381 $showBlocks = 'optionField_' . $i;
382 if ($i > 2) {
383 $_showHide->addHide($showBlocks);
384 if ($i == self::NUM_OPTION) {
385 $_showHide->addHide('additionalOption');
386 }
387 }
388 else {
389 $_showHide->addShow($showBlocks);
390 }
391
392 $optionAttributes = CRM_Core_DAO::getAttribute('CRM_Core_DAO_OptionValue');
393 // label
394 $this->add('text', 'option_label[' . $i . ']', ts('Label'),
395 $optionAttributes['label']
396 );
397
398 // value
399 $this->add('text', 'option_value[' . $i . ']', ts('Value'),
400 $optionAttributes['value']
401 );
402
403 // weight
404 $this->add('text', "option_weight[$i]", ts('Order'),
405 $optionAttributes['weight']
406 );
407
408 // is active ?
409 $this->add('checkbox', "option_status[$i]", ts('Active?'));
410
411 $defaultOption[$i] = $this->createElement('radio', NULL, NULL, NULL, $i);
412
413 //for checkbox handling of default option
414 $this->add('checkbox', "default_checkbox_option[$i]", NULL);
415 }
416
417 //default option selection
418 $this->addGroup($defaultOption, 'default_option');
419
420 $_showHide->addToTemplate();
421
422 // text length for alpha numeric data types
423 $this->add('text',
424 'text_length',
425 ts('Database field length'),
426 $attributes['text_length'],
427 FALSE
428 );
429 $this->addRule('text_length', ts('Value should be a positive number'), 'integer');
430
431 $this->add('text',
432 'start_date_years',
433 ts('Dates may be up to'),
434 $attributes['start_date_years'],
435 FALSE
436 );
437 $this->add('text',
438 'end_date_years',
439 ts('Dates may be up to'),
440 $attributes['end_date_years'],
441 FALSE
442 );
443
444 $this->addRule('start_date_years', ts('Value should be a positive number'), 'integer');
445 $this->addRule('end_date_years', ts('Value should be a positive number'), 'integer');
446
447 $this->add('select', 'date_format', ts('Date Format'),
448 array('' => ts('- select -')) + CRM_Core_SelectValues::getDatePluginInputFormats()
449 );
450
451 $this->add('select', 'time_format', ts('Time'),
452 array('' => ts('- none -')) + CRM_Core_SelectValues::getTimeFormats()
453 );
454
455 // for Note field
456 $this->add('text',
457 'note_columns',
458 ts('Width (columns)') . ' ',
459 $attributes['note_columns'],
460 FALSE
461 );
462 $this->add('text',
463 'note_rows',
464 ts('Height (rows)') . ' ',
465 $attributes['note_rows'],
466 FALSE
467 );
2f940a36
NG
468 $this->add('text',
469 'note_length',
470 ts('Maximum length') . ' ',
471 $attributes['text_length'], // note_length is an alias for the text-length field
472 FALSE
473 );
6a488035
TO
474
475 $this->addRule('note_columns', ts('Value should be a positive number'), 'positiveInteger');
476 $this->addRule('note_rows', ts('Value should be a positive number'), 'positiveInteger');
2f940a36 477 $this->addRule('note_length', ts('Value should be a positive number'), 'positiveInteger');
6a488035
TO
478
479 // weight
480 $this->add('text', 'weight', ts('Order'),
481 $attributes['weight'],
482 TRUE
483 );
484 $this->addRule('weight', ts('is a numeric field'), 'numeric');
485
486 // is required ?
487 $this->add('checkbox', 'is_required', ts('Required?'));
488
489 // checkbox / radio options per line
490 $this->add('text', 'options_per_line', ts('Options Per Line'));
491 $this->addRule('options_per_line', ts('must be a numeric value'), 'numeric');
492
493 // default value, help pre, help post, mask, attributes, javascript ?
494 $this->add('text', 'default_value', ts('Default Value'),
495 $attributes['default_value']
496 );
497 $this->add('textarea', 'help_pre', ts('Field Pre Help'),
498 $attributes['help_pre']
499 );
500 $this->add('textarea', 'help_post', ts('Field Post Help'),
501 $attributes['help_post']
502 );
503 $this->add('text', 'mask', ts('Mask'),
504 $attributes['mask']
505 );
506
507 // is active ?
508 $this->add('checkbox', 'is_active', ts('Active?'));
509
510 // is active ?
511 $this->add('checkbox', 'is_view', ts('View Only?'));
512
513 // is searchable ?
514 $this->addElement('checkbox',
515 'is_searchable',
516 ts('Is this Field Searchable?'),
517 NULL, array('onclick' => "showSearchRange(this)")
518 );
519
520 // is searchable by range?
521 $searchRange = array();
522 $searchRange[] = $this->createElement('radio', NULL, NULL, ts('Yes'), '1');
523 $searchRange[] = $this->createElement('radio', NULL, NULL, ts('No'), '0');
524
525 $this->addGroup($searchRange, 'is_search_range', ts('Search by Range?'));
526
527 // add buttons
528 $this->addButtons(array(
529 array(
530 'type' => 'next',
531 'name' => ts('Save'),
532 'isDefault' => TRUE,
533 ),
534 array(
535 'type' => 'next',
536 'name' => ts('Save and New'),
537 'subName' => 'new',
538 ),
539 array(
540 'type' => 'cancel',
541 'name' => ts('Cancel'),
542 ),
543 )
544 );
545
546 // add a form rule to check default value
547 $this->addFormRule(array('CRM_Custom_Form_Field', 'formRule'), $this);
548
549 // if view mode pls freeze it with the done button.
550 if ($this->_action & CRM_Core_Action::VIEW) {
551 $this->freeze();
552 $url = CRM_Utils_System::url('civicrm/admin/custom/group/field', 'reset=1&action=browse&gid=' . $this->_gid);
553 $this->addElement('button',
554 'done',
555 ts('Done'),
556 array('onclick' => "location.href='$url'")
557 );
558 }
559 }
560
561 /**
562 * global validation rules for the form
563 *
564 * @param array $fields (referance) posted values of the form
565 *
566 * @return array if errors then list of errors to be posted back to the form,
567 * true otherwise
568 * @static
569 * @access public
570 */
571 static function formRule($fields, $files, $self) {
572 $default = CRM_Utils_Array::value('default_value', $fields);
573
574 $errors = array();
575
576 //validate field label as well as name.
577 $title = $fields['label'];
578 $name = CRM_Utils_String::munge($title, '_', 64);
e1069955 579 $gId = $self->_gid; // CRM-7564
8ef12e64 580 $query = 'select count(*) from civicrm_custom_field where ( name like %1 OR label like %2 ) and id != %3 and custom_group_id = %4';
6a488035
TO
581 $fldCnt = CRM_Core_DAO::singleValueQuery($query, array(1 => array($name, 'String'),
582 2 => array($title, 'String'),
583 3 => array((int)$self->_id, 'Integer'),
e1069955 584 4 => array($gId, 'Integer'),
6a488035
TO
585 ));
586 if ($fldCnt) {
587 $errors['label'] = ts('Custom field \'%1\' already exists in Database.', array(1 => $title));
588 }
589
590 //checks the given custom field name doesnot start with digit
591 if (!empty($title)) {
592 // gives the ascii value
593 $asciiValue = ord($title{0});
594 if ($asciiValue >= 48 && $asciiValue <= 57) {
595 $errors['label'] = ts("Field's Name should not start with digit");
596 }
597 }
598
599 // ensure that the label is not 'id'
600 if (strtolower($title) == 'id') {
601 $errors['label'] = ts("You cannot use 'id' as a field label.");
602 }
603
604 if (!isset($fields['data_type'][0]) || !isset($fields['data_type'][1])) {
605 $errors['_qf_default'] = ts('Please enter valid - Data and Input Field Type.');
606 }
607
608 $dataType = self::$_dataTypeKeys[$fields['data_type'][0]];
609
610 if ($default || $dataType == 'ContactReference') {
611 switch ($dataType) {
612 case 'Int':
613 if (!CRM_Utils_Rule::integer($default)) {
614 $errors['default_value'] = ts('Please enter a valid integer as default value.');
615 }
616 break;
617
618 case 'Float':
619 if (!CRM_Utils_Rule::numeric($default)) {
620 $errors['default_value'] = ts('Please enter a valid number as default value.');
621 }
622 break;
623
624 case 'Money':
625 if (!CRM_Utils_Rule::money($default)) {
626 $errors['default_value'] = ts('Please enter a valid number value.');
627 }
628 break;
629
630 case 'Link':
631 if (!CRM_Utils_Rule::url($default)) {
632 $errors['default_value'] = ts('Please enter a valid link.');
633 }
634 break;
635
636 case 'Date':
637 if (!CRM_Utils_Rule::date($default)) {
638 $errors['default_value'] = ts('Please enter a valid date as default value using YYYY-MM-DD format. Example: 2004-12-31.');
639 }
640 break;
641
642 case 'Boolean':
643 if ($default != '1' && $default != '0') {
644 $errors['default_value'] = ts('Please enter 1 (for Yes) or 0 (for No) if you want to set a default value.');
645 }
646 break;
647
648 case 'Country':
649 if (!empty($default)) {
650 $query = "SELECT count(*) FROM civicrm_country WHERE name = %1 OR iso_code = %1";
651 $params = array(1 => array($fields['default_value'], 'String'));
652 if (CRM_Core_DAO::singleValueQuery($query, $params) <= 0) {
653 $errors['default_value'] = ts('Invalid default value for country.');
654 }
655 }
656 break;
657
658 case 'StateProvince':
659 if (!empty($default)) {
660 $query = "
8ef12e64 661SELECT count(*)
6a488035
TO
662 FROM civicrm_state_province
663 WHERE name = %1
664 OR abbreviation = %1";
665 $params = array(1 => array($fields['default_value'], 'String'));
666 if (CRM_Core_DAO::singleValueQuery($query, $params) <= 0) {
667 $errors['default_value'] = ts('The invalid default value for State/Province data type');
668 }
669 }
670 break;
671
672 case 'ContactReference':
8cc574cf 673 if ($fields['filter_selected'] == 'Advance' && !empty($fields['filter'])) {
6a488035
TO
674 if (strpos($fields['filter'], 'entity=') !== FALSE) {
675 $errors['filter'] = ts("Please do not include entity parameter (entity is always 'contact')");
676 }
06508628
CW
677 elseif (strpos($fields['filter'], 'action=get') === FALSE) {
678 $errors['filter'] = ts("Only 'get' action is supported.");
6a488035
TO
679 }
680 }
681 $self->setDefaults(array('filter_selected', $fields['filter_selected']));
682 break;
683 }
684 }
685
686 if (self::$_dataTypeKeys[$fields['data_type'][0]] == 'Date') {
687 if (!$fields['date_format']) {
688 $errors['date_format'] = ts('Please select a date format.');
689 }
690 }
691
692 /** Check the option values entered
693 * Appropriate values are required for the selected datatype
694 * Incomplete row checking is also required.
695 */
696 $_flagOption = $_rowError = 0;
697 $_showHide = new CRM_Core_ShowHideBlocks('', '');
698 $dataType = self::$_dataTypeKeys[$fields['data_type'][0]];
699 if (isset($fields['data_type'][1])) {
700 $dataField = $fields['data_type'][1];
701 }
702 $optionFields = array('Select', 'Multi-Select', 'CheckBox', 'Radio', 'AdvMulti-Select');
703
36d1ff7f 704 if (isset($fields['option_type']) && $fields['option_type'] == 1) {
6a488035
TO
705 //capture duplicate Custom option values
706 if (!empty($fields['option_value'])) {
707 $countValue = count($fields['option_value']);
708 $uniqueCount = count(array_unique($fields['option_value']));
709
710 if ($countValue > $uniqueCount) {
711
712 $start = 1;
713 while ($start < self::NUM_OPTION) {
714 $nextIndex = $start + 1;
715 while ($nextIndex <= self::NUM_OPTION) {
716 if ($fields['option_value'][$start] == $fields['option_value'][$nextIndex] &&
717 !empty($fields['option_value'][$nextIndex])
718 ) {
719 $errors['option_value[' . $start . ']'] = ts('Duplicate Option values');
720 $errors['option_value[' . $nextIndex . ']'] = ts('Duplicate Option values');
721 $_flagOption = 1;
722 }
723 $nextIndex++;
724 }
725 $start++;
726 }
727 }
728 }
729
730 //capture duplicate Custom Option label
731 if (!empty($fields['option_label'])) {
732 $countValue = count($fields['option_label']);
733 $uniqueCount = count(array_unique($fields['option_label']));
734
735 if ($countValue > $uniqueCount) {
736 $start = 1;
737 while ($start < self::NUM_OPTION) {
738 $nextIndex = $start + 1;
739 while ($nextIndex <= self::NUM_OPTION) {
740 if ($fields['option_label'][$start] == $fields['option_label'][$nextIndex] &&
741 !empty($fields['option_label'][$nextIndex])
742 ) {
743 $errors['option_label[' . $start . ']'] = ts('Duplicate Option label');
744 $errors['option_label[' . $nextIndex . ']'] = ts('Duplicate Option label');
745 $_flagOption = 1;
746 }
747 $nextIndex++;
748 }
749 $start++;
750 }
751 }
752 }
753
754 for ($i = 1; $i <= self::NUM_OPTION; $i++) {
755 if (!$fields['option_label'][$i]) {
756 if ($fields['option_value'][$i]) {
757 $errors['option_label[' . $i . ']'] = ts('Option label cannot be empty');
758 $_flagOption = 1;
759 }
760 else {
761 $_emptyRow = 1;
762 }
763 }
764 else {
765 if (!strlen(trim($fields['option_value'][$i]))) {
766 if (!$fields['option_value'][$i]) {
767 $errors['option_value[' . $i . ']'] = ts('Option value cannot be empty');
768 $_flagOption = 1;
769 }
770 }
771 }
772
773 if ($fields['option_value'][$i] && $dataType != 'String') {
774 if ($dataType == 'Int') {
775 if (!CRM_Utils_Rule::integer($fields['option_value'][$i])) {
776 $_flagOption = 1;
777 $errors['option_value[' . $i . ']'] = ts('Please enter a valid integer.');
778 }
779 }
780 elseif ($dataType == 'Money') {
781 if (!CRM_Utils_Rule::money($fields['option_value'][$i])) {
782 $_flagOption = 1;
783 $errors['option_value[' . $i . ']'] = ts('Please enter a valid money value.');
784 }
785 }
786 else {
787 if (!CRM_Utils_Rule::numeric($fields['option_value'][$i])) {
788 $_flagOption = 1;
789 $errors['option_value[' . $i . ']'] = ts('Please enter a valid number.');
790 }
791 }
792 }
793
794 $showBlocks = 'optionField_' . $i;
795 if ($_flagOption) {
796 $_showHide->addShow($showBlocks);
797 $_rowError = 1;
798 }
799
800 if (!empty($_emptyRow)) {
801 $_showHide->addHide($showBlocks);
802 }
803 else {
804 $_showHide->addShow($showBlocks);
805 }
806 if ($i == self::NUM_OPTION) {
807 $hideBlock = 'additionalOption';
808 $_showHide->addHide($hideBlock);
809 }
810
811 $_flagOption = $_emptyRow = 0;
812 }
813 }
814 elseif (isset($dataField) &&
815 in_array($dataField, $optionFields) &&
816 !in_array($dataType, array('Boolean', 'Country', 'StateProvince'))
817 ) {
818 if (!$fields['option_group_id']) {
819 $errors['option_group_id'] = ts('You must select a Multiple Choice Option set if you chose Reuse an existing set.');
820 }
821 else {
822 $query = "
823SELECT count(*)
824FROM civicrm_custom_field
825WHERE data_type != %1
826AND option_group_id = %2";
827 $params = array(
828 1 => array(self::$_dataTypeKeys[$fields['data_type'][0]],
829 'String',
830 ),
831 2 => array($fields['option_group_id'], 'Integer'),
832 );
833 $count = CRM_Core_DAO::singleValueQuery($query, $params);
834 if ($count > 0) {
835 $errors['option_group_id'] = ts('The data type of the multiple choice option set you\'ve selected does not match the data type assigned to this field.');
836 }
837 }
838 }
839
840 $assignError = new CRM_Core_Page();
841 if ($_rowError) {
842 $_showHide->addToTemplate();
843 $assignError->assign('optionRowError', $_rowError);
844 }
845 else {
846 if (isset($fields['data_type'][1])) {
847 switch (self::$_dataToHTML[$fields['data_type'][0]][$fields['data_type'][1]]) {
848 case 'Radio':
849 $_fieldError = 1;
850 $assignError->assign('fieldError', $_fieldError);
851 break;
852
853 case 'Checkbox':
854 $_fieldError = 1;
855 $assignError->assign('fieldError', $_fieldError);
856 break;
857
858 case 'Select':
859 $_fieldError = 1;
860 $assignError->assign('fieldError', $_fieldError);
861 break;
862
863 default:
864 $_fieldError = 0;
865 $assignError->assign('fieldError', $_fieldError);
866 }
867 }
868
869 for ($idx = 1; $idx <= self::NUM_OPTION; $idx++) {
870 $showBlocks = 'optionField_' . $idx;
871 if (!empty($fields['option_label'][$idx])) {
872 $_showHide->addShow($showBlocks);
873 }
874 else {
875 $_showHide->addHide($showBlocks);
876 }
877 }
878 $_showHide->addToTemplate();
879 }
880
881 // we can not set require and view at the same time.
8cc574cf 882 if (!empty($fields['is_required']) && !empty($fields['is_view'])) {
6a488035
TO
883 $errors['is_view'] = ts('Can not set this field Required and View Only at the same time.');
884 }
885
886 return empty($errors) ? TRUE : $errors;
887 }
888
889 /**
890 * Process the form
891 *
892 * @param null
893 *
894 * @return void
895 * @access public
896 */
897 public function postProcess() {
898 // store the submitted values in an array
899 $params = $this->controller->exportValues($this->_name);
900 if ($this->_action == CRM_Core_Action::UPDATE) {
901 $dataTypeKey = $this->_defaultDataType[0];
902 $params['data_type'] = self::$_dataTypeKeys[$this->_defaultDataType[0]];
903 $params['html_type'] = self::$_dataToHTML[$this->_defaultDataType[0]][$this->_defaultDataType[1]];
904 }
905 else {
906 $dataTypeKey = $params['data_type'][0];
907 $params['html_type'] = self::$_dataToHTML[$params['data_type'][0]][$params['data_type'][1]];
908 $params['data_type'] = self::$_dataTypeKeys[$params['data_type'][0]];
909 }
910
911 //fix for 'is_search_range' field.
912 if (in_array($dataTypeKey, array(
913 1, 2, 3, 5))) {
a7488080 914 if (empty($params['is_searchable'])) {
6a488035
TO
915 $params['is_search_range'] = 0;
916 }
917 }
918 else {
919 $params['is_search_range'] = 0;
920 }
921
922 $filter = 'null';
8cc574cf 923 if ($dataTypeKey == 11 && !empty($params['filter_selected'])) {
6a488035
TO
924 if ($params['filter_selected'] == 'Advance' && trim(CRM_Utils_Array::value('filter', $params))) {
925 $filter = trim($params['filter']);
926 }
8cc574cf 927 elseif ($params['filter_selected'] == 'Group' && !empty($params['group_id'])) {
6a488035
TO
928
929 $filter = 'action=lookup&group=' . implode(',', $params['group_id']);
930 }
931 }
932 $params['filter'] = $filter;
933
934 // fix for CRM-316
935 $oldWeight = NULL;
936 if ($this->_action & (CRM_Core_Action::UPDATE | CRM_Core_Action::ADD)) {
937 $fieldValues = array('custom_group_id' => $this->_gid);
938 if ($this->_id) {
939 $oldWeight = $this->_values['weight'];
940 }
941 $params['weight'] = CRM_Utils_Weight::updateOtherWeights('CRM_Core_DAO_CustomField', $oldWeight, $params['weight'], $fieldValues);
942 }
943
944 $strtolower = function_exists('mb_strtolower') ? 'mb_strtolower' : 'strtolower';
945
946 //store the primary key for State/Province or Country as default value.
947 if (strlen(trim($params['default_value']))) {
948 switch ($params['data_type']) {
949 case 'StateProvince':
950 $fieldStateProvince = $strtolower($params['default_value']);
951 $query = "
952SELECT id
8ef12e64 953 FROM civicrm_state_province
954 WHERE LOWER(name) = '$fieldStateProvince'
6a488035
TO
955 OR abbreviation = '$fieldStateProvince'";
956 $dao = CRM_Core_DAO::executeQuery($query, CRM_Core_DAO::$_nullArray);
957 if ($dao->fetch()) {
958 $params['default_value'] = $dao->id;
959 }
960 break;
961
962 case 'Country':
963 $fieldCountry = $strtolower($params['default_value']);
964 $query = "
965SELECT id
966 FROM civicrm_country
8ef12e64 967 WHERE LOWER(name) = '$fieldCountry'
6a488035
TO
968 OR iso_code = '$fieldCountry'";
969 $dao = CRM_Core_DAO::executeQuery($query, CRM_Core_DAO::$_nullArray);
970 if ($dao->fetch()) {
971 $params['default_value'] = $dao->id;
972 }
973 break;
974 }
975 }
976
2f940a36
NG
977 // The text_length attribute for Memo fields is in a different input as there
978 // are different label, help text and default value than for other type fields
979 if ($params['data_type'] == "Memo") {
980 $params['text_length'] = $params['note_length'];
981 }
982
6a488035
TO
983 // need the FKEY - custom group id
984 $params['custom_group_id'] = $this->_gid;
985
986 if ($this->_action & CRM_Core_Action::UPDATE) {
987 $params['id'] = $this->_id;
988 }
6a488035 989 $customField = CRM_Core_BAO_CustomField::create($params);
f84151fd 990 $this->_id = $customField->id;
6a488035
TO
991
992 // reset the cache
993 CRM_Core_BAO_Cache::deleteGroup('contact fields');
994
0b1bae4a 995 $msg = '<p>' . ts("Custom field '%1' has been saved.", array(1 => $customField->label)) . '</p>';
6a488035
TO
996
997 $buttonName = $this->controller->getButtonName();
998 $session = CRM_Core_Session::singleton();
999 if ($buttonName == $this->getButtonName('next', 'new')) {
0b1bae4a 1000 $msg += '<p>' . ts("Ready to add another.") . '</p>';
6a488035
TO
1001 $session->replaceUserContext(CRM_Utils_System::url('civicrm/admin/custom/group/field/add',
1002 'reset=1&action=add&gid=' . $this->_gid
1003 ));
1004 }
1005 else {
1006 $session->replaceUserContext(CRM_Utils_System::url('civicrm/admin/custom/group/field',
1007 'reset=1&action=browse&gid=' . $this->_gid
1008 ));
1009 }
0b1bae4a
CW
1010 $session->setStatus($msg, ts('Saved'), 'success');
1011
1012 // Add data when in ajax contect
1013 $this->ajaxResponse['customField'] = $customField->toArray();
6a488035
TO
1014 }
1015}
1016