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