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