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