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