Merge pull request #3112 from freeform/CRM-14568
[civicrm-core.git] / CRM / Custom / Form / Option.php
1 <?php
2 /*
3 +--------------------------------------------------------------------+
4 | CiviCRM version 4.5 |
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_Option extends CRM_Core_Form {
40
41 /**
42 * the custom field id saved to the session for an update
43 *
44 * @var int
45 * @access protected
46 */
47 protected $_fid;
48
49 /**
50 * the custom group id saved to the session for an update
51 *
52 * @var int
53 * @access protected
54 */
55 protected $_gid;
56
57 /**
58 * The option group ID
59 */
60 protected $_optionGroupID = NULL;
61
62 /**
63 * The Option id, used when editing the Option
64 *
65 * @var int
66 * @access protected
67 */
68 protected $_id;
69
70 /**
71 * Function to set variables up before form is built
72 *
73 * @param null
74 *
75 * @return void
76 * @access public
77 */
78 public function preProcess() {
79 $this->_fid = CRM_Utils_Request::retrieve('fid', 'Positive', $this);
80
81 $this->_gid = CRM_Utils_Request::retrieve('gid', 'Positive', $this);
82
83 if (!isset($this->_gid) && $this->_fid) {
84 $this->_gid = CRM_Core_DAO::getFieldValue(
85 'CRM_Core_DAO_CustomField',
86 $this->_fid,
87 'custom_group_id'
88 );
89 }
90
91 if ($this->_fid) {
92 $this->_optionGroupID = CRM_Core_DAO::getFieldValue(
93 'CRM_Core_DAO_CustomField',
94 $this->_fid,
95 'option_group_id'
96 );
97 }
98
99 if ($isReserved = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_CustomGroup', $this->_gid, 'is_reserved', 'id')) {
100 CRM_Core_Error::fatal("You cannot add or edit muliple choice options in a reserved custom field-set.");
101 }
102
103 $this->_id = CRM_Utils_Request::retrieve('id', 'Positive', $this);
104 }
105
106 /**
107 * This function sets the default values for the form. Note that in edit/view mode
108 * the default values are retrieved from the database
109 *
110 * @param null
111 *
112 * @return array array of default values
113 * @access public
114 */
115 function setDefaultValues() {
116 $defaults = $fieldDefaults = array();
117 if (isset($this->_id)) {
118 $params = array('id' => $this->_id);
119 CRM_Core_BAO_CustomOption::retrieve($params, $defaults);
120
121 $paramsField = array('id' => $this->_fid);
122 CRM_Core_BAO_CustomField::retrieve($paramsField, $fieldDefaults);
123
124 if ($fieldDefaults['html_type'] == 'CheckBox'
125 || $fieldDefaults['html_type'] == 'Multi-Select'
126 || $fieldDefaults['html_type'] == 'AdvMulti-Select'
127 ) {
128 if (!empty($fieldDefaults['default_value'])) {
129 $defaultCheckValues = explode(CRM_Core_DAO::VALUE_SEPARATOR,
130 substr($fieldDefaults['default_value'], 1, -1)
131 );
132 if (in_array($defaults['value'], $defaultCheckValues)) {
133 $defaults['default_value'] = 1;
134 }
135 }
136 }
137 else {
138 if (CRM_Utils_Array::value('default_value', $fieldDefaults) == CRM_Utils_Array::value('value', $defaults)) {
139 $defaults['default_value'] = 1;
140 }
141 }
142 }
143 else {
144 $defaults['is_active'] = 1;
145 }
146
147 if ($this->_action & CRM_Core_Action::ADD) {
148 $fieldValues = array('option_group_id' => $this->_optionGroupID);
149 $defaults['weight'] = CRM_Utils_Weight::getDefaultWeight('CRM_Core_DAO_OptionValue', $fieldValues);
150 }
151
152 return $defaults;
153 }
154
155 /**
156 * Function to actually build the form
157 *
158 * @param null
159 *
160 * @return void
161 * @access public
162 */
163 public function buildQuickForm() {
164 if ($this->_action == CRM_Core_Action::DELETE) {
165 $option = civicrm_api3('option_value', 'getsingle', array('id' => $this->_id));
166 $this->assign('label', $option['label']);
167 $this->addButtons(array(
168 array(
169 'type' => 'next',
170 'name' => ts('Delete'),
171 'isDefault' => TRUE,
172 ),
173 array(
174 'type' => 'cancel',
175 'name' => ts('Cancel'),
176 ),
177 )
178 );
179 }
180 else {
181 // lets trim all the whitespace
182 $this->applyFilter('__ALL__', 'trim');
183
184 // hidden Option Id for validation use
185 $this->add('hidden', 'optionId', $this->_id);
186
187 //hidden field ID for validation use
188 $this->add('hidden', 'fieldId', $this->_fid);
189
190 // label
191 $this->add('text', 'label', ts('Option Label'), CRM_Core_DAO::getAttribute('CRM_Core_DAO_OptionValue', 'label'), TRUE);
192
193 $this->add('text', 'value', ts('Option Value'), CRM_Core_DAO::getAttribute('CRM_Core_DAO_OptionValue', 'value'), TRUE);
194
195 // weight
196 $this->add('text', 'weight', ts('Order'), CRM_Core_DAO::getAttribute('CRM_Core_DAO_OptionValue', 'weight'), TRUE);
197 $this->addRule('weight', ts('is a numeric field'), 'numeric');
198
199 // is active ?
200 $this->add('checkbox', 'is_active', ts('Active?'));
201
202 // Set the default value for Custom Field
203 $this->add('checkbox', 'default_value', ts('Default'));
204
205 // add a custom form rule
206 $this->addFormRule(array('CRM_Custom_Form_Option', 'formRule'), $this);
207
208 // add buttons
209 $this->addButtons(array(
210 array(
211 'type' => 'next',
212 'name' => ts('Save'),
213 'isDefault' => TRUE,
214 ),
215 array(
216 'type' => 'next',
217 'name' => ts('Save and New'),
218 'subName' => 'new',
219 ),
220 array(
221 'type' => 'cancel',
222 'name' => ts('Cancel'),
223 ),
224 )
225 );
226
227
228 // if view mode pls freeze it with the done button.
229 if ($this->_action & CRM_Core_Action::VIEW) {
230 $this->freeze();
231 $url = CRM_Utils_System::url('civicrm/admin/custom/group/field/option',
232 'reset=1&action=browse&fid=' . $this->_fid . '&gid=' . $this->_gid,
233 TRUE, NULL, FALSE
234 );
235 $this->addElement('button',
236 'done',
237 ts('Done'),
238 array('onclick' => "location.href='$url'", 'class' => 'form-submit')
239 );
240 }
241 }
242 $this->assign('id', $this->_id);
243 }
244
245 /**
246 * global validation rules for the form
247 *
248 * @param array $fields posted values of the form
249 *
250 * @param $files
251 * @param $form
252 *
253 * @return array list of errors to be posted back to the form
254 * @static
255 * @access public
256 */
257 static function formRule($fields, $files, $form) {
258 $optionLabel = $fields['label'];
259 $optionValue = $fields['value'];
260 $fieldId = $form->_fid;
261 $optionGroupId = $form->_optionGroupID;
262
263 $temp = array();
264 if (empty($form->_id)) {
265 $query = "
266 SELECT count(*)
267 FROM civicrm_option_value
268 WHERE option_group_id = %1
269 AND label = %2";
270 $params = array(
271 1 => array($optionGroupId, 'Integer'),
272 2 => array($optionLabel, 'String'),
273 );
274 if (CRM_Core_DAO::singleValueQuery($query, $params) > 0) {
275 $errors['label'] = ts('There is an entry with the same label.');
276 }
277
278 $query = "
279 SELECT count(*)
280 FROM civicrm_option_value
281 WHERE option_group_id = %1
282 AND value = %2";
283 $params = array(
284 1 => array($optionGroupId, 'Integer'),
285 2 => array($optionValue, 'String'),
286 );
287 if (CRM_Core_DAO::singleValueQuery($query, $params) > 0) {
288 $errors['value'] = ts('There is an entry with the same value.');
289 }
290 }
291 else {
292 //capture duplicate entries while updating Custom Options
293 $optionId = CRM_Utils_Type::escape($fields['optionId'], 'Integer');
294
295 //check label duplicates within a custom field
296 $query = "
297 SELECT count(*)
298 FROM civicrm_option_value
299 WHERE option_group_id = %1
300 AND id != %2
301 AND label = %3";
302 $params = array(
303 1 => array($optionGroupId, 'Integer'),
304 2 => array($optionId, 'Integer'),
305 3 => array($optionLabel, 'String'),
306 );
307 if (CRM_Core_DAO::singleValueQuery($query, $params) > 0) {
308 $errors['label'] = ts('There is an entry with the same label.');
309 }
310
311 //check value duplicates within a custom field
312 $query = "
313 SELECT count(*)
314 FROM civicrm_option_value
315 WHERE option_group_id = %1
316 AND id != %2
317 AND value = %3";
318 $params = array(
319 1 => array($optionGroupId, 'Integer'),
320 2 => array($optionId, 'Integer'),
321 3 => array($optionValue, 'String'),
322 );
323 if (CRM_Core_DAO::singleValueQuery($query, $params) > 0) {
324 $errors['value'] = ts('There is an entry with the same value.');
325 }
326 }
327
328 $query = "
329 SELECT data_type
330 FROM civicrm_custom_field
331 WHERE id = %1";
332 $params = array(1 => array($fieldId, 'Integer'));
333 $dao = CRM_Core_DAO::executeQuery($query, $params);
334 if ($dao->fetch()) {
335 switch ($dao->data_type) {
336 case 'Int':
337 if (!CRM_Utils_Rule::integer($fields["value"])) {
338 $errors['value'] = ts('Please enter a valid integer value.');
339 }
340 break;
341
342 case 'Float':
343 // case 'Money':
344 if (!CRM_Utils_Rule::numeric($fields["value"])) {
345 $errors['value'] = ts('Please enter a valid number value.');
346 }
347 break;
348
349 case 'Money':
350 if (!CRM_Utils_Rule::money($fields["value"])) {
351 $errors['value'] = ts('Please enter a valid value.');
352 }
353 break;
354
355 case 'Date':
356 if (!CRM_Utils_Rule::date($fields["value"])) {
357 $errors['value'] = ts('Please enter a valid date using YYYY-MM-DD format. Example: 2004-12-31.');
358 }
359 break;
360
361 case 'Boolean':
362 if (!CRM_Utils_Rule::integer($fields["value"]) &&
363 ($fields["value"] != '1' || $fields["value"] != '0')
364 ) {
365 $errors['value'] = ts('Please enter 1 or 0 as value.');
366 }
367 break;
368
369 case 'Country':
370 if (!empty($fields["value"])) {
371 $params = array(1 => array($fields['value'], 'String'));
372 $query = "SELECT count(*) FROM civicrm_country WHERE name = %1 OR iso_code = %1";
373 if (CRM_Core_DAO::singleValueQuery($query, $params) <= 0) {
374 $errors['value'] = ts('Invalid default value for country.');
375 }
376 }
377 break;
378
379 case 'StateProvince':
380 if (!empty($fields["value"])) {
381 $params = array(1 => array($fields['value'], 'String'));
382 $query = "
383 SELECT count(*)
384 FROM civicrm_state_province
385 WHERE name = %1
386 OR abbreviation = %1";
387 if (CRM_Core_DAO::singleValueQuery($query, $params) <= 0) {
388 $errors['value'] = ts('The invalid value for State/Province data type');
389 }
390 }
391 break;
392 }
393 }
394
395 return empty($errors) ? TRUE : $errors;
396 }
397
398 /**
399 * Process the form
400 *
401 * @param null
402 *
403 * @return void
404 * @access public
405 */
406 public function postProcess() {
407 // store the submitted values in an array
408 $params = $this->controller->exportValues('Option');
409
410 if ($this->_action == CRM_Core_Action::DELETE) {
411 $option = civicrm_api3('option_value', 'getsingle', array('id' => $this->_id));
412 $fieldValues = array('option_group_id' => $this->_optionGroupID);
413 CRM_Utils_Weight::delWeight('CRM_Core_DAO_OptionValue', $this->_id, $fieldValues);
414 CRM_Core_BAO_CustomOption::del($this->_id);
415 CRM_Core_Session::setStatus(ts('Option "%1" has been deleted.', array(1 => $option['label'])), ts('Deleted'), 'success');
416 return;
417 }
418
419 // set values for custom field properties and save
420 $customOption = new CRM_Core_DAO_OptionValue();
421 $customOption->label = $params['label'];
422 $customOption->name = CRM_Utils_String::titleToVar($params['label']);
423 $customOption->weight = $params['weight'];
424 $customOption->value = $params['value'];
425 $customOption->is_active = CRM_Utils_Array::value('is_active', $params, FALSE);
426
427 $oldWeight = NULL;
428 if ($this->_id) {
429 $customOption->id = $this->_id;
430 CRM_Core_BAO_CustomOption::updateCustomValues($params);
431 $oldWeight = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_OptionValue', $this->_id, 'weight', 'id');
432 }
433
434 $fieldValues = array('option_group_id' => $this->_optionGroupID);
435 $customOption->weight =
436 CRM_Utils_Weight::updateOtherWeights(
437 'CRM_Core_DAO_OptionValue',
438 $oldWeight,
439 $params['weight'],
440 $fieldValues);
441
442 $customOption->option_group_id = $this->_optionGroupID;
443
444 $customField = new CRM_Core_DAO_CustomField();
445 $customField->id = $this->_fid;
446 if (
447 $customField->find(TRUE) &&
448 (
449 $customField->html_type == 'CheckBox' ||
450 $customField->html_type == 'AdvMulti-Select' ||
451 $customField->html_type == 'Multi-Select'
452 )
453 ) {
454 $defVal = explode(
455 CRM_Core_DAO::VALUE_SEPARATOR,
456 substr($customField->default_value, 1, -1)
457 );
458 if (!empty($params['default_value'])) {
459 if (!in_array($customOption->value, $defVal)) {
460 if (empty($defVal[0])) {
461 $defVal = array($customOption->value);
462 }
463 else {
464 $defVal[] = $customOption->value;
465 }
466 $customField->default_value =
467 CRM_Core_DAO::VALUE_SEPARATOR .
468 implode(CRM_Core_DAO::VALUE_SEPARATOR, $defVal) .
469 CRM_Core_DAO::VALUE_SEPARATOR;
470 $customField->save();
471 }
472 }
473 elseif (in_array($customOption->value, $defVal)) {
474 $tempVal = array();
475 foreach ($defVal as $v) {
476 if ($v != $customOption->value) {
477 $tempVal[] = $v;
478 }
479 }
480
481 $customField->default_value =
482 CRM_Core_DAO::VALUE_SEPARATOR .
483 implode(CRM_Core_DAO::VALUE_SEPARATOR, $tempVal) .
484 CRM_Core_DAO::VALUE_SEPARATOR;
485 $customField->save();
486 }
487 }
488 else {
489 switch ($customField->data_type) {
490 case 'Money':
491 $customOption->value = CRM_Utils_Rule::cleanMoney($customOption->value);
492 break;
493
494 case 'Int':
495 $customOption->value = intval($customOption->value);
496 break;
497
498 case 'Float':
499 $customOption->value = floatval($customOption->value);
500 break;
501 }
502
503 if (!empty($params['default_value'])) {
504 $customField->default_value = $customOption->value;
505 $customField->save();
506 }
507 elseif ($customField->find(TRUE) && $customField->default_value == $customOption->value) {
508 // this is the case where this option is the current default value and we have been reset
509 $customField->default_value = 'null';
510 $customField->save();
511 }
512 }
513
514 $customOption->save();
515
516 $msg = ts('Your multiple choice option \'%1\' has been saved', array(1 => $customOption->label));
517 CRM_Core_Session::setStatus($msg, '', 'success');
518 $buttonName = $this->controller->getButtonName();
519 $session = CRM_Core_Session::singleton();
520 if ($buttonName == $this->getButtonName('next', 'new')) {
521 CRM_Core_Session::setStatus(ts('You can add another option.'), '', 'info');
522 $session->replaceUserContext(
523 CRM_Utils_System::url(
524 'civicrm/admin/custom/group/field/option',
525 'reset=1&action=add&fid=' . $this->_fid . '&gid=' . $this->_gid
526 )
527 );
528 }
529 }
530 }
531