ILIAS  release_8 Revision v8.24
class.assFormulaQuestionGUI.php
Go to the documentation of this file.
1<?php
2
19include_once "./Modules/Test/classes/inc.AssessmentConstants.php";
20
31{
32 protected const HAS_SPECIAL_QUESTION_COMMANDS = true;
33
40 public function __construct($id = -1)
41 {
43 $this->object = new assFormulaQuestion();
44 if ($id >= 0) {
45 $this->object->loadFromDb($id);
46 }
47 }
48
49 protected function setQuestionSpecificTabs(ilTabsGUI $ilTabs): void
50 {
51 $ilTabs->addTarget('units', $this->ctrl->getLinkTargetByClass('ilLocalUnitConfigurationGUI', ''), '', 'illocalunitconfigurationgui');
52 }
53
54 protected function callSpecialQuestionCommands(string $cmd): void
55 {
56 if (preg_match('/suggestrange_(\$r\d+)/', $cmd, $matches)) {
58 $this->suggestRange($matches[1]);
59 }
60 }
61
62 public function suggestRange(string $suggest_range_for_result): void
63 {
64 if ($this->writePostData()) {
65 $this->tpl->setOnScreenMessage('info', $this->getErrorMessage());
66 }
67 $this->editQuestion(false, $suggest_range_for_result);
68 }
69
73 protected function writePostData(bool $always = false): int
74 {
75 $hasErrors = (!$always) ? $this->editQuestion(true) : false;
76 $checked = true;
77 if (!$hasErrors) {
78 $this->object->setTitle($_POST["title"]);
79 $this->object->setAuthor($_POST["author"]);
80 $this->object->setComment($_POST["comment"]);
81 include_once "./Services/AdvancedEditing/classes/class.ilObjAdvancedEditing.php";
82 $questiontext = ilUtil::stripOnlySlashes($_POST["question"]);
83 $this->object->setQuestion($questiontext);
84
85 $this->object->parseQuestionText();
86 $found_vars = array();
87 $found_results = array();
88
89 foreach ($this->request->getParsedBody() as $key => $value) {
90 if (preg_match("/^unit_(\\\$v\d+)$/", $key, $matches)) {
91 array_push($found_vars, $matches[1]);
92 }
93 if (preg_match("/^unit_(\\\$r\d+)$/", $key, $matches)) {
94 array_push($found_results, $matches[1]);
95 }
96 }
97
98 try {
99 $lifecycle = ilAssQuestionLifecycle::getInstance($_POST['lifecycle']);
100 $this->object->setLifecycle($lifecycle);
102 }
103
104 if (!$this->object->checkForDuplicateResults()) {
105 $this->addErrorMessage($this->lng->txt("err_duplicate_results"));
106 $checked = false;
107 }
108
109 foreach ($found_vars as $variable) {
110 if ($this->object->getVariable($variable) != null) {
111 $varObj = new assFormulaQuestionVariable(
112 $variable,
113 $_POST["range_min_$variable"],
114 $_POST["range_max_$variable"],
115 isset($_POST["unit_$variable"]) ? $this->object->getUnitrepository()->getUnit(
116 $_POST["unit_$variable"]
117 ) : null,
118 $_POST["precision_$variable"],
119 $_POST["intprecision_$variable"]
120 );
121 $varObj->setRangeMinTxt($_POST["range_min_$variable"]);
122 $varObj->setRangeMaxTxt($_POST["range_max_$variable"]);
123 $this->object->addVariable($varObj);
124 }
125 }
126
127 $tmp_form_vars = array();
128 $tmp_quest_vars = array();
129 foreach ($found_results as $result) {
130 $tmp_res_match = preg_match_all("/([$][v][0-9]*)/", $_POST["formula_$result"], $form_vars);
131 $tmp_form_vars = array_merge($tmp_form_vars, $form_vars[0]);
132
133 $tmp_que_match = preg_match_all("/([$][v][0-9]*)/", $_POST['question'], $quest_vars);
134 $tmp_quest_vars = array_merge($tmp_quest_vars, $quest_vars[0]);
135 }
136 $result_has_undefined_vars = array_diff($tmp_form_vars, $found_vars);
137 $question_has_unused_vars = array_diff($tmp_quest_vars, $tmp_form_vars);
138
139 if (count($result_has_undefined_vars) > 0 || count($question_has_unused_vars) > 0) {
140 $error_message = '';
141 if (count($result_has_undefined_vars) > 0) {
142 $error_message .= $this->lng->txt("res_contains_undef_var") . '<br>';
143 }
144 if (count($question_has_unused_vars) > 0) {
145 $error_message .= $this->lng->txt("que_contains_unused_var");
146 }
147 $checked = false;
148 if ($this->isSaveCommand()) {
149 $this->tpl->setOnScreenMessage('failure', $error_message);
150 }
151 }
152 foreach ($found_results as $result) {
153 if (is_object($this->object->getUnitrepository()->getUnit($_POST["unit_$result"]))) {
154 $tmp_result_unit = $this->object->getUnitrepository()->getUnit($_POST["unit_$result"]);
155 } else {
156 $tmp_result_unit = null;
157 }
158
159 if ($this->object->getResult($result) != null) {
160 $use_simple_rating = $this->request->int("rating_advanced_$result") !== 1;
161 $resObj = new assFormulaQuestionResult(
162 $result,
163 $_POST["range_min_$result"],
164 $_POST["range_max_$result"],
165 str_replace(',', '.', $_POST["tolerance_$result"]),
166 $tmp_result_unit,
167 $_POST["formula_$result"],
168 $_POST["points_$result"],
169 $_POST["precision_$result"],
170 $use_simple_rating,
171 $this->request->int("rating_advanced_$result") === 1 ? $_POST["rating_sign_$result"] : "",
172 $this->request->int("rating_advanced_$result") === 1 ? $_POST["rating_value_$result"] : "",
173 $this->request->int("rating_advanced_$result") === 1 ? $_POST["rating_unit_$result"] : "",
174 $this->request->int("result_type_$result")
175 );
176 $resObj->setRangeMinTxt($_POST["range_min_$result"]);
177 $resObj->setRangeMaxTxt($_POST["range_max_$result"]);
178 $this->object->addResult($resObj);
179 if (isset($_POST["units_$result"]) && is_array($_POST["units_$result"])) {
180 $this->object->addResultUnits($resObj, $_POST["units_$result"]);
181 }
182 }
183 }
184 if ($checked == false) {
185 return 1;
186 } else {
188 return 0;
189 }
190 } else {
191 return 1;
192 }
193 }
194
195 public function resetSavedPreviewSession(): void
196 {
197 global $DIC;
198 $ilUser = $DIC['ilUser'];
199 $user_id = $ilUser->getId();
200 $question_id = $this->object->getId();
201 require_once 'Modules/TestQuestionPool/classes/class.ilAssQuestionPreviewSession.php';
202 $ilAssQuestionPreviewSession = new ilAssQuestionPreviewSession($user_id, $question_id);
203 $ilAssQuestionPreviewSession->setParticipantsSolution(array());
204 }
205
206 public function isSaveCommand(): bool
207 {
208 return in_array($this->ctrl->getCmd(), array('saveFQ', 'saveEdit', 'saveReturnFQ'));
209 }
210
214 public function editQuestion($checkonly = false, string $suggest_range_for_result = ''): bool
215 {
216 $save = $this->isSaveCommand();
217
218 $this->getQuestionTemplate();
219
220 $form = new ilPropertyFormGUI();
221 $this->editForm = $form;
222
223 $form->setFormAction($this->ctrl->getFormAction($this));
224 $form->setTitle($this->outQuestionType());
225 $form->setMultipart(false);
226 $form->setTableWidth('100%');
227 $form->setId('assformulaquestion');
228
229 $this->addBasicQuestionFormProperties($form);
230
231 // Add info text
232 $question = $form->getItemByPostVar('question');
233 $question->setInfo($this->lng->txt('fq_question_desc'));
234
235 $variables = $this->object->getVariables();
236 $categorized_units = $this->object->getUnitrepository()->getCategorizedUnits();
237 $result_units = $this->object->getAllResultUnits();
238
239 $unit_options = array();
240 $category_name = '';
241 $new_category = false;
242 foreach ($categorized_units as $item) {
246 if ($item instanceof assFormulaQuestionUnitCategory) {
247 if ($category_name != $item->getDisplayString()) {
248 $new_category = true;
249 $category_name = $item->getDisplayString();
250 }
251 continue;
252 }
253 $unit_options[$item->getId()] = $item->getDisplayString() . ($new_category ? ' (' . $category_name . ')' : '');
254 $new_category = false;
255 }
256
257 if (count($variables)) {
258 uasort($variables, function (assFormulaQuestionVariable $v1, assFormulaQuestionVariable $v2) {
259 $num_v1 = (int) substr($v1->getVariable(), 2);
260 $num_v2 = (int) substr($v2->getVariable(), 2);
261 if ($num_v1 > $num_v2) {
262 return 1;
263 } elseif ($num_v1 < $num_v2) {
264 return -1;
265 }
266
267 return 0;
268 });
269
270 foreach ($variables as $variable) {
274 $variable_header = new ilFormSectionHeaderGUI();
275 $variable_header->setTitle(sprintf($this->lng->txt('variable_x'), $variable->getVariable()));
276
277 $range_min = new ilNumberInputGUI($this->lng->txt('range_min'), 'range_min_' . $variable->getVariable());
278 $range_min->allowDecimals(true);
279 $range_min->setSize(3);
280 $range_min->setRequired(true);
281 $range_min->setValue($variable->getRangeMin());
282
283 $range_max = new ilNumberInputGUI($this->lng->txt('range_max'), 'range_max_' . $variable->getVariable());
284 $range_max->allowDecimals(true);
285 $range_max->setSize(3);
286 $range_max->setRequired(true);
287 $range_max->setValue($variable->getRangeMax());
288
289 $units = new ilSelectInputGUI($this->lng->txt('unit'), 'unit_' . $variable->getVariable());
290 $units->setOptions(array(0 => $this->lng->txt('no_selection')) + $unit_options);
291 if (is_object($variable->getUnit())) {
292 $units->setValue($variable->getUnit()->getId());
293 }
294
295 $precision = new ilNumberInputGUI($this->lng->txt('precision'), 'precision_' . $variable->getVariable());
296 $precision->setRequired(true);
297 $precision->setSize(3);
298 $precision->setMinValue(0);
299 $precision->setValue($variable->getPrecision());
300 $precision->setInfo($this->lng->txt('fq_precision_info'));
301
302 $intprecision = new ilNumberInputGUI($this->lng->txt('intprecision'), 'intprecision_' . $variable->getVariable());
303 $intprecision->setSize(3);
304 $intprecision->setMinValue(1);
305 $intprecision->setValue($variable->getIntprecision());
306 $intprecision->setInfo($this->lng->txt('intprecision_info'));
307
308 $form->addItem($variable_header);
309 $form->addItem($range_min);
310 $form->addItem($range_max);
311 $form->addItem($units);
312 $form->addItem($precision);
313 $form->addItem($intprecision);
314 }
315 }
316 $quest_vars = array();
317 $result_vars = array();
318 $results = $this->object->getResults();
319 if (count($results)) {
321 $num_r1 = (int) substr($r1->getResult(), 2);
322 $num_r2 = (int) substr($r2->getResult(), 2);
323 if ($num_r1 > $num_r2) {
324 return 1;
325 } elseif ($num_r1 < $num_r2) {
326 return -1;
327 }
328
329 return 0;
330 });
331
332 foreach ($results as $result) {
336 $result_header = new ilFormSectionHeaderGUI();
337 $result_header->setTitle(sprintf($this->lng->txt('result_x'), $result->getResult()));
338
339 $formula = new ilTextInputGUI($this->lng->txt('formula'), 'formula_' . $result->getResult());
340 $formula->setInfo($this->lng->txt('fq_formula_desc'));
341 $formula->setRequired(true);
342 $formula->setSize(50);
343 $formula->setValue($result->getFormula());
344 $formula->setSuffix(' = ' . $result->getResult());
345
346 if (
347 $suggest_range_for_result !== '' &&
348 strcmp($suggest_range_for_result, $result->getResult()) == 0 &&
349 strlen($result->substituteFormula($variables, $results))
350 ) {
351 $result->suggestRange($variables, $results);
352 }
353
354 $range_min = new ilNumberInputGUI($this->lng->txt('range_min'), 'range_min_' . $result->getResult());
355 $range_min->allowDecimals(true);
356 $range_min->setSize(3);
357 $range_min->setRequired(true);
358 $range_min->setValue($result->getRangeMin());
359
360 $range_max = new ilNumberInputGUI($this->lng->txt('range_max'), 'range_max_' . $result->getResult());
361 $range_max->allowDecimals(true);
362 $range_max->setSize(3);
363 $range_max->setRequired(true);
364 $range_max->setValue($result->getRangeMax());
365
366 $matches = array();
367
368 $precision = new ilNumberInputGUI($this->lng->txt('precision'), 'precision_' . $result->getResult());
369 $precision->setRequired(true);
370 $precision->setSize(3);
371 $precision->setMinValue(0);
372 $precision->setInfo($this->lng->txt('fq_precision_info'));
373 $precision->setValue($result->getPrecision());
374
375 $tolerance = new ilNumberInputGUI($this->lng->txt('tolerance'), 'tolerance_' . $result->getResult());
376 $tolerance->setSize(3);
377 $tolerance->setMinValue(0);
378 $tolerance->setMaxValue(100);
379 $tolerance->allowDecimals(true);
380 $tolerance->setInfo($this->lng->txt('tolerance_info'));
381 $tolerance->setValue($result->getTolerance());
382
383 $suggest_range_button = new ilCustomInputGUI('', '');
384 $suggest_range_button->setHtml('<input type="submit" class="btn btn-default" name="cmd[suggestrange_' . $result->getResult() . ']" value="' . $this->lng->txt("suggest_range") . '" />');
385
386 $sel_result_units = new ilSelectInputGUI($this->lng->txt('unit'), 'unit_' . $result->getResult());
387 $sel_result_units->setOptions(array(0 => $this->lng->txt('no_selection')) + $unit_options);
388 $sel_result_units->setInfo($this->lng->txt('result_unit_info'));
389 if (is_object($result->getUnit())) {
390 $sel_result_units->setValue($result->getUnit()->getId());
391 }
392
393 $mc_result_units = new ilMultiSelectInputGUI($this->lng->txt('result_units'), 'units_' . $result->getResult());
394 $mc_result_units->setOptions($unit_options);
395 $mc_result_units->setInfo($this->lng->txt('result_units_info'));
396 $selectedvalues = array();
397 foreach ($unit_options as $unit_id => $txt) {
398 if ($this->hasResultUnit($result, $unit_id, $result_units)) {
399 $selectedvalues[] = $unit_id;
400 }
401 }
402 $mc_result_units->setValue($selectedvalues);
403
404 $result_type = new ilRadioGroupInputGUI($this->lng->txt('result_type_selection'), 'result_type_' . $result->getResult());
405 $result_type->setRequired(true);
406
407 $no_type = new ilRadioOption($this->lng->txt('no_result_type'), 0);
408 $no_type->setInfo($this->lng->txt('fq_no_restriction_info'));
409
410 $result_dec = new ilRadioOption($this->lng->txt('result_dec'), 1);
411 $result_dec->setInfo($this->lng->txt('result_dec_info'));
412
413 $result_frac = new ilRadioOption($this->lng->txt('result_frac'), 2);
414 $result_frac->setInfo($this->lng->txt('result_frac_info'));
415
416 $result_co_frac = new ilRadioOption($this->lng->txt('result_co_frac'), 3);
417 $result_co_frac->setInfo($this->lng->txt('result_co_frac_info'));
418
419 $result_type->addOption($no_type);
420 $result_type->addOption($result_dec);
421 $result_type->addOption($result_frac);
422 $result_type->addOption($result_co_frac);
423 $result_type->setValue(strlen($result->getResultType()) ? $result->getResultType() : 0);
424
425 $points = new ilNumberInputGUI($this->lng->txt('points'), 'points_' . $result->getResult());
426 $points->allowDecimals(true);
427 $points->setRequired(true);
428 $points->setSize(3);
429 $points->setMinValue(0);
430 $points->setValue(strlen($result->getPoints()) ? $result->getPoints() : 1);
431
432 $rating_type = new ilCheckboxInputGUI($this->lng->txt('advanced_rating'), 'rating_advanced_' . $result->getResult());
433 $rating_type->setValue(1);
434 $rating_type->setInfo($this->lng->txt('advanced_rating_info'));
435
436 if (!$save) {
437 $advanced_rating = $this->canUseAdvancedRating($result);
438 if (!$advanced_rating) {
439 $rating_type->setDisabled(true);
440 $rating_type->setChecked(false);
441 } else {
442 $rating_type->setChecked(strlen($result->getRatingSimple()) && $result->getRatingSimple() ? false : true);
443 }
444 }
445
446 $sign = new ilNumberInputGUI($this->lng->txt('rating_sign'), 'rating_sign_' . $result->getResult());
447 $sign->setRequired(true);
448 $sign->setSize(3);
449 $sign->setMinValue(0);
450 $sign->setValue($result->getRatingSign());
451 $rating_type->addSubItem($sign);
452
453 $value = new ilNumberInputGUI($this->lng->txt('rating_value'), 'rating_value_' . $result->getResult());
454 $value->setRequired(true);
455 $value->setSize(3);
456 $value->setMinValue(0);
457 $value->setValue($result->getRatingValue());
458 $rating_type->addSubItem($value);
459
460 $unit = new ilNumberInputGUI($this->lng->txt('rating_unit'), 'rating_unit_' . $result->getResult());
461 $unit->setRequired(true);
462 $unit->setSize(3);
463 $unit->setMinValue(0);
464 $unit->setValue($result->getRatingUnit());
465 $rating_type->addSubItem($unit);
466
467 $info_text = new ilNonEditableValueGUI($this->lng->txt('additional_rating_info'));
468 $rating_type->addSubItem($info_text);
469
470 $form->addItem($result_header);
471 $form->addItem($formula);
472 $form->addItem($range_min);
473 $form->addItem($range_max);
474 $form->addItem($suggest_range_button);
475 $form->addItem($precision);
476 $form->addItem($tolerance);
477 $form->addItem($sel_result_units);
478 $form->addItem($mc_result_units);
479 $form->addItem($result_type);
480 $form->addItem($points);
481 $form->addItem($rating_type);
482 }
483
484 $defined_result_vars = array();
485
486 $defined_result_res = array();
487
488 foreach ($variables as $key => $object) {
489 $quest_vars[$key] = $key;
490 }
491
492 foreach ($results as $key => $object) {
493 $result_vars[$key] = $key;
494 }
495
496 foreach ($results as $tmp_result) {
500 $formula = $tmp_result->getFormula();
501
502 preg_match_all("/([$][v][0-9]*)/", $formula, $form_vars);
503 preg_match_all("/([$][r][0-9]*)/", $formula, $form_res);
504 foreach ($form_vars[0] as $res_var) {
505 $defined_result_vars[$res_var] = $res_var;
506 }
507
508 foreach ($form_res[0] as $res_res) {
509 $defined_result_res[$res_res] = $res_res;
510 }
511 }
512 }
513
514 $result_has_undefined_vars = [];
515 $question_has_unused_vars = [];
516 $result_has_undefined_res = [];
517
518 if (is_array($quest_vars) && count($quest_vars) > 0) {
519 $result_has_undefined_vars = array_diff($defined_result_vars, $quest_vars);
520 $question_has_unused_vars = array_diff($quest_vars, $defined_result_vars);
521 }
522
523 if (is_array($result_vars) && count($result_vars) > 0) {
524 $result_has_undefined_res = array_diff($defined_result_res, $result_vars);
525 }
526 $error_message = '';
527 $checked = false;
528 if (count($result_has_undefined_vars) > 0 || count($question_has_unused_vars) > 0) {
529 if (count($result_has_undefined_vars) > 0) {
530 $error_message .= $this->lng->txt("res_contains_undef_var") . '<br>';
531 }
532 if (count($question_has_unused_vars) > 0) {
533 $error_message .= $this->lng->txt("que_contains_unused_var") . '<br>';
534 }
535
536 $checked = false;
537 if ($save) {
538 $this->tpl->setOnScreenMessage('failure', $error_message);
539 }
540 }
541
542 if (is_array($result_has_undefined_res) && count($result_has_undefined_res) > 0) {
543 $error_message .= $this->lng->txt("res_contains_undef_res") . '<br>';
544 $checked = false;
545 }
546
547 if ($save && !$checked) {
548 $this->tpl->setOnScreenMessage('failure', $error_message);
549 }
550
551 if ($this->object->getId()) {
552 $hidden = new ilHiddenInputGUI("", "ID");
553 $hidden->setValue($this->object->getId());
554 $form->addItem($hidden);
555 }
556
557 $this->populateTaxonomyFormSection($form);
558
559 $form->addCommandButton('parseQuestion', $this->lng->txt("parseQuestion"));
560 $form->addCommandButton('saveReturnFQ', $this->lng->txt("save_return"));
561 $form->addCommandButton('saveFQ', $this->lng->txt("save"));
562
563 $errors = $checked;
564
565 if ($save) {
566 $found_vars = array();
567 $found_results = array();
568 foreach ($this->request->getParsedBody() as $key => $value) {
569 if (preg_match("/^unit_(\\\$v\d+)$/", $key, $matches)) {
570 array_push($found_vars, $matches[1]);
571 }
572 if (preg_match("/^unit_(\\\$r\d+)$/", $key, $matches)) {
573 array_push($found_results, $matches[1]);
574 }
575 }
576
577
578 foreach ($this->request->getParsedBody() as $key => $value) {
579 $item = $form->getItemByPostVar($key);
580 if ($item !== null) {
581 switch (get_class($item)) {
582 case 'ilDurationInputGUI':
583 $item->setHours($value['hh']);
584 $item->setMinutes($value['mm']);
585 $item->setSeconds($value['ss']);
586 break;
587 default:
588 $item->setValue($value);
589 }
590 }
591 }
592
593 $check = array_merge($found_vars, $found_results);
594 foreach ((array) $form->getItems() as $item) {
595 $postvar = $item->getPostVar();
596 if (preg_match("/_\\\$[r|v]\d+/", $postvar, $matches)) {
597 $k = substr(array_shift($matches), 1);
598 if (!in_array($k, $check)) {
599 $form->removeItemByPostVar($postvar);
600 }
601 }
602 }
603 $variables = array_filter($variables, fn ($k, $v) => in_array($v, $check), ARRAY_FILTER_USE_BOTH);
604 $results = array_filter($results, fn ($k, $v) => in_array($k, $check), ARRAY_FILTER_USE_BOTH);
605
606 $errors = !$form->checkInput();
607
608 $custom_errors = false;
609 if (count($variables)) {
610 foreach ($variables as $variable) {
614 $min_range = $form->getItemByPostVar('range_min_' . $variable->getVariable());
615 $max_range = $form->getItemByPostVar('range_max_' . $variable->getVariable());
616 if ($min_range->getValue() > $max_range->getValue()) {
617 $min_range->setAlert($this->lng->txt('err_range'));
618 $max_range->setAlert($this->lng->txt('err_range'));
619 $custom_errors = true;
620 }
621 $intPrecision = $form->getItemByPostVar('intprecision_' . $variable->getVariable());
622 $decimal_spots = $form->getItemByPostVar('precision_' . $variable->getVariable());
623 if ($decimal_spots->getValue() == 0) {
624 if (!$variable->isIntPrecisionValid(
625 $intPrecision->getValue(),
626 $min_range->getValue(),
627 $max_range->getValue()
628 )) {
629 $intPrecision->setAlert($this->lng->txt('err_division'));
630 $custom_errors = true;
631 }
632 }
633 }
634 }
635
636 if (count($results)) {
637 foreach ($results as $result) {
641 $min_range = $form->getItemByPostVar('range_min_' . $result->getResult());
642 $max_range = $form->getItemByPostVar('range_max_' . $result->getResult());
643 if ($min_range->getValue() > $max_range->getValue()) {
644 $min_range->setAlert($this->lng->txt('err_range'));
645 $max_range->setAlert($this->lng->txt('err_range'));
646 $custom_errors = true;
647 }
648
649
650 $formula = $form->getItemByPostVar('formula_' . $result->getResult());
651 if (strpos($formula->getValue(), $result->getResult()) !== false) {
652 $formula->setAlert($this->lng->txt('errRecursionInResult'));
653 $custom_errors = true;
654 }
655
656 $result_unit = $form->getItemByPostVar('unit_' . $result->getResult());
657 $rating_advanced = $form->getItemByPostVar('rating_advanced_' . $result->getResult());
658 if (((int) $result_unit->getValue() <= 0) && $rating_advanced->getChecked()) {
659 unset($_POST['rating_advanced_' . $result->getResult()]);
660 $rating_advanced->setDisabled(true);
661 $rating_advanced->setChecked(false);
662 $rating_advanced->setAlert($this->lng->txt('err_rating_advanced_not_allowed'));
663 $custom_errors = true;
664 } elseif ($rating_advanced->getChecked()) {
665 $rating_sign = $form->getItemByPostVar('rating_sign_' . $result->getResult());
666 $rating_value = $form->getItemByPostVar('rating_value_' . $result->getResult());
667 $rating_unit = $form->getItemByPostVar('rating_unit_' . $result->getResult());
668
669 $percentage = $rating_sign->getValue() + $rating_value->getValue() + $rating_unit->getValue();
670 if ($percentage != 100) {
671 $rating_advanced->setAlert($this->lng->txt('err_wrong_rating_advanced'));
672 $custom_errors = true;
673 }
674 }
675
676 preg_match_all("/([$][v][0-9]*)/", $formula->getValue(), $form_vars);
677 $result_has_undefined_vars = array_diff($form_vars[0], $found_vars);
678 if (count($result_has_undefined_vars)) {
679 $errors = true;
680 $this->tpl->setOnScreenMessage('info', $this->lng->txt('res_contains_undef_var'));
681 }
682 }
683 }
684
685 if ($custom_errors && !$errors) {
686 $errors = true;
687 $this->tpl->setOnScreenMessage('failure', $this->lng->txt('form_input_not_valid'));
688 }
689 foreach ($this->request->getParsedBody() as $key => $value) {
690 $item = $form->getItemByPostVar($key);
691 if ($item !== null) {
692 switch (get_class($item)) {
693 case 'ilDurationInputGUI':
694 $item->setHours($value['hh']);
695 $item->setMinutes($value['mm']);
696 $item->setSeconds($value['ss']);
697 break;
698 default:
699 $item->setValue($value);
700 }
701 }
702 } // again, because checkInput now performs the whole stripSlashes handling and we need this if we don't want to have duplication of backslashes
703 if ($errors) {
704 $checkonly = false;
705 }
706 }
707
708 if (!$checkonly) {
709 $this->tpl->setVariable('QUESTION_DATA', $form->getHTML());
710 }
711 return $errors;
712 }
713
714 private function hasResultUnit($result, $unit_id, $resultunits): bool
715 {
716 if (array_key_exists($result->getResult(), $resultunits)) {
717 if (array_key_exists($unit_id, $resultunits[$result->getResult()])) {
718 return true;
719 }
720 }
721 return false;
722 }
723
731 private function canUseAdvancedRating($result): bool
732 {
733 $resultunit = $result->getUnit();
734
735 /*
736 * if there is a result-unit (unit selectbox) selected it is possible to use advanced rating
737 * if there is no result-unit selected it is NOT possible to use advanced rating, because there is no
738 * definition if the result-value or the unit-value should be the correct solution!!
739 *
740 */
741 if (is_object($resultunit)) {
742 return true;
743 } else {
744 return false;
745 }
746 }
747
748 public function parseQuestion(): void
749 {
750 $this->writePostData();
752 $this->editQuestion();
753 }
754
755 public function saveReturnFQ(): void
756 {
757 global $DIC;
758 $ilUser = $DIC['ilUser'];
759 $old_id = $this->request->getQuestionId();
760 $result = $this->writePostData();
761 if ($result == 0) {
762 $ilUser->setPref("tst_lastquestiontype", $this->object->getQuestionType());
763 $ilUser->writePref("tst_lastquestiontype", $this->object->getQuestionType());
765 $this->object->saveToDb();
766 $originalexists = false;
767 if ($this->object->getOriginalId() != null && $this->object->_questionExistsInPool($this->object->getOriginalId())) {
768 $originalexists = true;
769 }
770 include_once "./Modules/TestQuestionPool/classes/class.assQuestion.php";
771 if (($this->request->raw("calling_test") || ($this->request->isset('calling_consumer') && (int) $this->request->raw('calling_consumer')))
772 && $originalexists && assQuestion::_isWriteable($this->object->getOriginalId(), $ilUser->getId())) {
773 $this->ctrl->redirect($this, "originalSyncForm");
774 } elseif ($this->request->raw("calling_test")) {
775 require_once 'Modules/Test/classes/class.ilObjTest.php';
776 $test = new ilObjTest($this->request->raw("calling_test"));
777 $q_id = $this->object->getId();
778 if (!assQuestion::_questionExistsInTest($this->object->getId(), $test->getTestId())) {
779 global $DIC;
780 $tree = $DIC['tree'];
781 $ilDB = $DIC['ilDB'];
782 $component_repository = $DIC['component.repository'];
783
784 $test = new ilObjTest($this->request->raw("calling_test"), true);
785
786 $testQuestionSetConfigFactory = new ilTestQuestionSetConfigFactory($tree, $ilDB, $component_repository, $test);
787
788 $test->insertQuestion(
789 $testQuestionSetConfigFactory->getQuestionSetConfig(),
790 $this->object->getId(),
791 true
792 );
793
794 if ($this->request->isset('prev_qid')) {
795 $test->moveQuestionAfter($this->object->getId(), $this->request->raw('prev_qid'));
796 }
797
798 $this->ctrl->setParameter($this, 'calling_test', $this->request->raw("calling_test"));
799 }
800 $this->tpl->setOnScreenMessage('success', $this->lng->txt("msg_obj_modified"), true);
801 $this->ctrl->redirectByClass('ilAssQuestionPreviewGUI', ilAssQuestionPreviewGUI::CMD_SHOW);
802 } else {
803 if ($this->object->getId() != $old_id) {
804 $this->callNewIdListeners($this->object->getId());
805 $this->tpl->setOnScreenMessage('success', $this->lng->txt("msg_obj_modified"), true);
806 $this->ctrl->redirectByClass("ilobjquestionpoolgui", "questions");
807 }
808 if (ilSession::get('info') != null) {
809 $this->tpl->setOnScreenMessage('success', ilSession::get('info') . "<br />" . $this->lng->txt("msg_obj_modified"), true);
810 } else {
811 $this->tpl->setOnScreenMessage('success', $this->lng->txt("msg_obj_modified"), true);
812 }
813 $this->ctrl->redirectByClass("ilAssQuestionPreviewGUI", ilAssQuestionPreviewGUI::CMD_SHOW);
814 }
815 } else {
816 $ilUser->setPref("tst_lastquestiontype", $this->object->getQuestionType());
817 $ilUser->writePref("tst_lastquestiontype", $this->object->getQuestionType());
818 $this->object->saveToDb();
819 $this->editQuestion();
820 }
821 }
822
823 public function saveFQ(): void
824 {
825 $result = $this->writePostData();
826
827 if ($result == 1) {
828 $this->editQuestion();
829 } else {
831 $this->save();
832 }
833 }
837 public function checkInput(): bool
838 {
839 if ((!$_POST["title"]) or (!$_POST["author"]) or (!$_POST["question"])) {
840 $this->addErrorMessage($this->lng->txt("fill_out_all_required_fields"));
841 return false;
842 }
843
844
845 return true;
846 }
847
860 public function getSolutionOutput(
861 $active_id,
862 $pass = null,
863 $graphicalOutput = false,
864 $result_output = false,
865 $show_question_only = true,
866 $show_feedback = false,
867 $show_correct_solution = false,
868 $show_manual_scoring = false,
869 $show_question_text = true
870 ): string {
871 // get the solution of the user for the active pass or from the last pass if allowed
872 $user_solution = array();
873 if (($active_id > 0) && (!$show_correct_solution)) {
874 $user_solution["active_id"] = $active_id;
875 $user_solution["pass"] = $pass;
876 $solutions = $this->object->getSolutionValues($active_id, $pass);
877 foreach ($solutions as $idx => $solution_value) {
878 if (preg_match("/^(\\\$v\\d+)$/", $solution_value["value1"], $matches)) {
879 $user_solution[$matches[1]] = $solution_value["value2"];
880 } elseif (preg_match("/^(\\\$r\\d+)$/", $solution_value["value1"], $matches)) {
881 if (!array_key_exists($matches[1], $user_solution)) {
882 $user_solution[$matches[1]] = array();
883 }
884 $user_solution[$matches[1]]["value"] = $solution_value["value2"];
885 } elseif (preg_match("/^(\\\$r\\d+)_unit$/", $solution_value["value1"], $matches)) {
886 if (!array_key_exists($matches[1], $user_solution)) {
887 $user_solution[$matches[1]] = array();
888 }
889 $user_solution[$matches[1]]["unit"] = $solution_value["value2"];
890 }
891 }
892 } elseif ($active_id) {
893 $user_solution = $this->object->getBestSolution($this->object->getSolutionValues($active_id, $pass));
894 } elseif (is_object($this->getPreviewSession())) {
895 $solutionValues = array();
896
897 $participantsSolution = $this->getPreviewSession()->getParticipantsSolution();
898 if (is_array($participantsSolution)) {
899 foreach ($participantsSolution as $val1 => $val2) {
900 $solutionValues[] = array('value1' => $val1, 'value2' => $val2);
901 }
902 }
903
904 $user_solution = $this->object->getBestSolution($solutionValues);
905 }
906
907 $template = new ilTemplate("tpl.il_as_qpl_formulaquestion_output_solution.html", true, true, 'Modules/TestQuestionPool');
908 $correctness_icons = [
909 'correct' => $this->generateCorrectnessIconsForCorrectness(self::CORRECTNESS_OK),
910 'not_correct' => $this->generateCorrectnessIconsForCorrectness(self::CORRECTNESS_NOT_OK)
911 ];
912 $questiontext = $this->object->substituteVariables($user_solution, $graphicalOutput, true, $result_output, $correctness_icons);
913
914 $template->setVariable("QUESTIONTEXT", $this->object->prepareTextareaOutput($questiontext, true));
915 $questionoutput = $template->get();
916 $solutiontemplate = new ilTemplate("tpl.il_as_tst_solution_output.html", true, true, "Modules/TestQuestionPool");
917 $feedback = ($show_feedback) ? $this->getGenericFeedbackOutput((int) $active_id, $pass) : "";
918 if (strlen($feedback)) {
919 $cssClass = (
920 $this->hasCorrectSolution($active_id, $pass) ?
922 );
923
924 $solutiontemplate->setVariable("ILC_FB_CSS_CLASS", $cssClass);
925 $solutiontemplate->setVariable("FEEDBACK", $this->object->prepareTextareaOutput($feedback, true));
926 }
927 $solutiontemplate->setVariable("SOLUTION_OUTPUT", $questionoutput);
928
929 $solutionoutput = $solutiontemplate->get();
930 if (!$show_question_only) {
931 // get page object output
932 $solutionoutput = $this->getILIASPage($solutionoutput);
933 }
934 return $solutionoutput;
935 }
936
937 public function getPreview($show_question_only = false, $showInlineFeedback = false): string
938 {
939 $user_solution = array();
940
941 if (is_object($this->getPreviewSession())) {
942 $solutions = (array) $this->getPreviewSession()->getParticipantsSolution();
943
944 foreach ($solutions as $val1 => $val2) {
945 if (preg_match("/^(\\\$v\\d+)$/", $val1, $matches)) {
946 $user_solution[$matches[1]] = $val2;
947 } elseif (preg_match("/^(\\\$r\\d+)$/", $val1, $matches)) {
948 if (!array_key_exists($matches[1], $user_solution)) {
949 $user_solution[$matches[1]] = array();
950 }
951 $user_solution[$matches[1]]["value"] = $val2;
952 } elseif (preg_match("/^(\\\$r\\d+)_unit$/", $val1, $matches)) {
953 if (!array_key_exists($matches[1], $user_solution)) {
954 $user_solution[$matches[1]] = array();
955 }
956 $user_solution[$matches[1]]["unit"] = $val2;
957 }
958
959 if (preg_match("/^(\\\$r\\d+)/", $val1, $matches) && !isset($user_solution[$matches[1]]["result_type"])) {
960 $user_solution[$matches[1]]["result_type"] = assFormulaQuestionResult::getResultTypeByQstId($this->object->getId(), $val1);
961 }
962 }
963 }
964
965 if (!$this->object->hasRequiredVariableSolutionValues($user_solution)) {
966 $user_solution = $this->object->getInitialVariableSolutionValues();
967
968 if (is_object($this->getPreviewSession())) {
969 $this->getPreviewSession()->setParticipantsSolution($user_solution);
970 }
971 }
972
973 $template = new ilTemplate("tpl.il_as_qpl_formulaquestion_output.html", true, true, 'Modules/TestQuestionPool');
974 if (is_object($this->getPreviewSession())) {
975 $questiontext = $this->object->substituteVariables($user_solution);
976 } else {
977 $questiontext = $this->object->substituteVariables(array());
978 }
979 $template->setVariable("QUESTIONTEXT", $this->object->prepareTextareaOutput($questiontext, true));
980 $questionoutput = $template->get();
981 if (!$show_question_only) {
982 // get page object output
983 $questionoutput = $this->getILIASPage($questionoutput);
984 }
985 return $questionoutput;
986 }
987
988 // hey: prevPassSolutions - pass will be always available from now on
989 public function getTestOutput($active_id, $pass, $is_postponed = false, $use_post_solutions = false, $show_feedback = false): string
990 // hey.
991 {
992 $this->tpl->setOnScreenMessage('info', $this->lng->txt('enter_valid_values'));
993 // get the solution of the user for the active pass or from the last pass if allowed
994 $user_solution = array();
995 if ($active_id) {
996 $solutions = $this->object->getTestOutputSolutions($active_id, $pass);
997
998 $actualPassIndex = null;
999 if ($this->object->getTestPresentationConfig()->isSolutionInitiallyPrefilled()) {
1000 require_once 'Modules/Test/classes/class.ilObjTest.php';
1001 $actualPassIndex = ilObjTest::_getPass($active_id);
1002 }
1003
1004 foreach ($solutions as $idx => $solution_value) {
1005 if (preg_match("/^(\\\$v\\d+)$/", $solution_value["value1"], $matches)) {
1006 if ($this->object->getTestPresentationConfig()->isSolutionInitiallyPrefilled()) {
1007 $this->object->saveCurrentSolution($active_id, $actualPassIndex, $matches[1], $solution_value["value2"], true);
1008 }
1009
1010 $user_solution[$matches[1]] = $solution_value["value2"];
1011 } elseif (preg_match("/^(\\\$r\\d+)$/", $solution_value["value1"], $matches)) {
1012 if (!array_key_exists($matches[1], $user_solution)) {
1013 $user_solution[$matches[1]] = array();
1014 }
1015 $user_solution[$matches[1]]["value"] = $solution_value["value2"];
1016 } elseif (preg_match("/^(\\\$r\\d+)_unit$/", $solution_value["value1"], $matches)) {
1017 if (!array_key_exists($matches[1], $user_solution)) {
1018 $user_solution[$matches[1]] = array();
1019 }
1020 $user_solution[$matches[1]]["unit"] = $solution_value["value2"];
1021 }
1022 if (preg_match("/^(\\\$r\\d+)/", $solution_value["value1"], $matches) && !isset($user_solution[$matches[1]]["result_type"])) {
1023 $user_solution[$matches[1]]["result_type"] = assFormulaQuestionResult::getResultTypeByQstId($this->object->getId(), $solution_value["value1"]);
1024 }
1025 }
1026 }
1027
1028 // fau: testNav - take question variables always from authorized solution because they are saved with this flag, even if an authorized solution is not saved
1029 $solutions = $this->object->getSolutionValues($active_id, $pass, true);
1030 foreach ($solutions as $idx => $solution_value) {
1031 if (preg_match("/^(\\\$v\\d+)$/", $solution_value["value1"], $matches)) {
1032 $user_solution[$matches[1]] = $solution_value["value2"];
1033 }
1034 }
1035 // fau.
1036
1037 if (!$this->object->hasRequiredVariableSolutionValues($user_solution)) {
1038 foreach ($this->object->getInitialVariableSolutionValues() as $val1 => $val2) {
1039 $this->object->saveCurrentSolution($active_id, $pass, $val1, $val2, true);
1040 }
1041 }
1042
1043 // generate the question output
1044 $template = new ilTemplate("tpl.il_as_qpl_formulaquestion_output.html", true, true, 'Modules/TestQuestionPool');
1045
1046 $questiontext = $this->object->substituteVariables($user_solution);
1047
1048 $template->setVariable("QUESTIONTEXT", $this->object->prepareTextareaOutput($questiontext, true));
1049
1050 $questionoutput = $template->get();
1051 $pageoutput = $this->outQuestionPage("", $is_postponed, $active_id, $questionoutput);
1052 return $pageoutput;
1053 }
1054
1055 public function getSpecificFeedbackOutput(array $userSolution): string
1056 {
1057 return '';
1058 }
1059}
$id
plugin.php for ilComponentBuildPluginInfoObjectiveTest::testAddPlugins
Definition: plugin.php:23
$check
Definition: buildRTE.php:81
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
canUseAdvancedRating($result)
Check if advanced rating can be used for a result.
getSpecificFeedbackOutput(array $userSolution)
Returns the answer specific feedback for the question.
hasResultUnit($result, $unit_id, $resultunits)
getPreview($show_question_only=false, $showInlineFeedback=false)
suggestRange(string $suggest_range_for_result)
getSolutionOutput( $active_id, $pass=null, $graphicalOutput=false, $result_output=false, $show_question_only=true, $show_feedback=false, $show_correct_solution=false, $show_manual_scoring=false, $show_question_text=true)
Get the question solution output.
setQuestionSpecificTabs(ilTabsGUI $ilTabs)
getTestOutput($active_id, $pass, $is_postponed=false, $use_post_solutions=false, $show_feedback=false)
writePostData(bool $always=false)
{Evaluates a posted edit form and writes the form data in the question object.integer A positive valu...
__construct($id=-1)
assFormulaQuestionGUI constructor The constructor takes possible arguments an creates an instance of ...
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
static getResultTypeByQstId($a_qst_id, $a_result)
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
populateTaxonomyFormSection(ilPropertyFormGUI $form)
callNewIdListeners(int $a_new_id)
getILIASPage(string $html="")
Returns the ILIAS Page around a question.
ilComponentRepository $component_repository
addBasicQuestionFormProperties(ilPropertyFormGUI $form)
getGenericFeedbackOutput(int $active_id, ?int $pass)
addErrorMessage(string $errormessage)
hasCorrectSolution($activeId, $passIndex)
generateCorrectnessIconsForCorrectness(int $correctness)
static _questionExistsInTest(int $question_id, int $test_id)
static _isWriteable(int $question_id, int $user_id)
This class represents a checkbox property in a property form.
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
This class represents a number property in a property form.
static _getPass($active_id)
Retrieves the actual pass of a given user for a given test.
setPref(string $a_keyword, ?string $a_value)
writePref(string $a_keyword, string $a_value)
This class represents a property form user interface.
This class represents a property in a property form.
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
This class represents a selection list property in a property form.
static get(string $a_var)
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
addTarget(string $a_text, string $a_link, $a_cmd="", $a_cmdClass="", string $a_frame="", bool $a_activate=false, bool $a_dir_text=false)
special template class to simplify handling of ITX/PEAR
This class represents a text property in a property form.
static stripOnlySlashes(string $a_str)
$txt
Definition: error.php:13
global $DIC
Definition: feed.php:28
$errors
Definition: imgupload.php:65
__construct(Container $dic, ilPlugin $plugin)
@inheritDoc
string $key
Consumer key/client ID value.
Definition: System.php:193
$results