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