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