ILIAS  release_6 Revision v6.24-5-g0c8bfefb3b8
class.assFormulaQuestionGUI.php
Go to the documentation of this file.
1<?php
2/* Copyright (c) 1998-2013 ILIAS open source, Extended GPL, see docs/LICENSE */
3
4include_once "./Modules/TestQuestionPool/classes/class.assQuestionGUI.php";
5include_once "./Modules/TestQuestionPool/classes/class.assFormulaQuestion.php";
6include_once "./Modules/TestQuestionPool/classes/class.assFormulaQuestionResult.php";
7include_once "./Modules/TestQuestionPool/classes/class.assFormulaQuestionVariable.php";
8include_once "./Modules/TestQuestionPool/classes/class.assFormulaQuestionUnit.php";
9include_once "./Modules/TestQuestionPool/classes/class.assFormulaQuestionUnitCategory.php";
10include_once "./Modules/Test/classes/inc.AssessmentConstants.php";
11require_once './Modules/TestQuestionPool/interfaces/interface.ilGuiAnswerScoringAdjustable.php';
12
23{
30 public function __construct($id = -1)
31 {
33 $this->object = new assFormulaQuestion();
34 $this->newUnitId = null;
35 if ($id >= 0) {
36 $this->object->loadFromDb($id);
37 }
38 }
39
45 public function setQuestionTabs()
46 {
47 global $DIC;
48 $rbacsystem = $DIC['rbacsystem'];
49 $ilTabs = $DIC['ilTabs'];
50
51 $ilTabs->clearTargets();
52
53 $this->ctrl->setParameterByClass("ilAssQuestionPageGUI", "q_id", $_GET["q_id"]);
54 include_once "./Modules/TestQuestionPool/classes/class.assQuestion.php";
55 $q_type = $this->object->getQuestionType();
56
57 if (strlen($q_type)) {
58 $classname = $q_type . "GUI";
59 $this->ctrl->setParameterByClass(strtolower($classname), "sel_question_types", $q_type);
60 $this->ctrl->setParameterByClass(strtolower($classname), "q_id", $_GET["q_id"]);
61 }
62
63 if ($_GET["q_id"]) {
64 if ($rbacsystem->checkAccess('write', $_GET["ref_id"])) {
65 // edit page
66 $ilTabs->addTarget(
67 "edit_page",
68 $this->ctrl->getLinkTargetByClass("ilAssQuestionPageGUI", "edit"),
69 array("edit", "insert", "exec_pg"),
70 "",
71 "",
72 $force_active
73 );
74 }
75
76 $this->addTab_QuestionPreview($ilTabs);
77 }
78
79 $force_active = false;
80 if ($rbacsystem->checkAccess('write', $_GET["ref_id"])) {
81 $url = "";
82
83 if ($classname) {
84 $url = $this->ctrl->getLinkTargetByClass($classname, "editQuestion");
85 }
86 $commands = $_POST["cmd"];
87 if (is_array($commands)) {
88 foreach ($commands as $key => $value) {
89 if (preg_match("/^suggestrange_.*/", $key, $matches)) {
90 $force_active = true;
91 }
92 }
93 }
94 // edit question properties
95 $ilTabs->addTarget(
96 "edit_question",
97 $url,
98 array(
99 "editQuestion", "save", "cancel", "addSuggestedSolution",
100 "cancelExplorer", "linkChilds", "removeSuggestedSolution",
101 "parseQuestion", "saveEdit", "suggestRange"
102 ),
103 $classname,
104 "",
105 $force_active
106 );
107 }
108
109 if ($_GET["q_id"]) {
110 // add tab for question feedback within common class assQuestionGUI
111 $this->addTab_QuestionFeedback($ilTabs);
112 }
113
114 if ($_GET["q_id"]) {
115 // add tab for question hint within common class assQuestionGUI
116 $this->addTab_QuestionHints($ilTabs);
117 }
118
119 // Unit editor
120 if ($_GET['q_id']) {
121 // add tab for question hint within common class assQuestionGUI
122 $this->addTab_Units($ilTabs);
123 }
124
125 // Assessment of questions sub menu entry
126 if ($_GET["q_id"]) {
127 $ilTabs->addTarget(
128 "statistics",
129 $this->ctrl->getLinkTargetByClass($classname, "assessment"),
130 array("assessment"),
131 $classname,
132 ""
133 );
134 }
135
136 $this->addBackTab($ilTabs);
137 }
138
139 public function getCommand($cmd)
140 {
141 if (preg_match("/suggestrange_(.*?)/", $cmd, $matches)) {
142 $cmd = "suggestRange";
143 }
144 return $cmd;
145 }
146
151 public function suggestRange()
152 {
153 if ($this->writePostData()) {
155 }
156 $this->editQuestion();
157 }
158
162 protected function writePostData($always = false)
163 {
164 $hasErrors = (!$always) ? $this->editQuestion(true) : false;
165 $checked = true;
166 if (!$hasErrors) {
167 $this->object->setTitle($_POST["title"]);
168 $this->object->setAuthor($_POST["author"]);
169 $this->object->setComment($_POST["comment"]);
170 include_once "./Services/AdvancedEditing/classes/class.ilObjAdvancedEditing.php";
171 $questiontext = ilUtil::stripOnlySlashes($_POST["question"]);
172 $this->object->setQuestion($questiontext);
173 $this->object->setEstimatedWorkingTime(
174 $_POST["Estimated"]["hh"],
175 $_POST["Estimated"]["mm"],
176 $_POST["Estimated"]["ss"]
177 );
178
179 $this->object->parseQuestionText();
180 $found_vars = array();
181 $found_results = array();
182
183
184 foreach ($_POST as $key => $value) {
185 if (preg_match("/^unit_(\\\$v\d+)$/", $key, $matches)) {
186 array_push($found_vars, $matches[1]);
187 }
188 if (preg_match("/^unit_(\\\$r\d+)$/", $key, $matches)) {
189 array_push($found_results, $matches[1]);
190 }
191 }
192
193 try {
194 $lifecycle = ilAssQuestionLifecycle::getInstance($_POST['lifecycle']);
195 $this->object->setLifecycle($lifecycle);
197 }
198
199 // if(!$this->object->checkForDuplicateVariables())
200 // {
201//
202 // $this->addErrorMessage($this->lng->txt("err_duplicate_variables"));
203 // $checked = FALSE;
204 // }
205 if (!$this->object->checkForDuplicateResults()) {
206 $this->addErrorMessage($this->lng->txt("err_duplicate_results"));
207 $checked = false;
208 }
209
210 foreach ($found_vars as $variable) {
211 if ($this->object->getVariable($variable) != null) {
212 $varObj = new assFormulaQuestionVariable($variable, $_POST["range_min_$variable"], $_POST["range_max_$variable"], $this->object->getUnitrepository()->getUnit($_POST["unit_$variable"]), $_POST["precision_$variable"], $_POST["intprecision_$variable"]);
213 $varObj->setRangeMinTxt($_POST["range_min_$variable"]);
214 $varObj->setRangeMaxTxt($_POST["range_max_$variable"]);
215 $this->object->addVariable($varObj);
216 }
217 }
218
219 $tmp_form_vars = array();
220 $tmp_quest_vars = array();
221 foreach ($found_results as $result) {
222 $tmp_res_match = preg_match_all("/([$][v][0-9]*)/", $_POST["formula_$result"], $form_vars);
223 $tmp_form_vars = array_merge($tmp_form_vars, $form_vars[0]);
224
225 $tmp_que_match = preg_match_all("/([$][v][0-9]*)/", $_POST['question'], $quest_vars);
226 $tmp_quest_vars = array_merge($tmp_quest_vars, $quest_vars[0]);
227 }
228 $result_has_undefined_vars = array_diff($tmp_form_vars, $found_vars);
229 $question_has_unused_vars = array_diff($tmp_quest_vars, $tmp_form_vars);
230
231 if (count($result_has_undefined_vars) > 0 || count($question_has_unused_vars) > 0) {
232 $error_message = '';
233 if (count($result_has_undefined_vars) > 0) {
234 $error_message .= $this->lng->txt("res_contains_undef_var") . '<br>';
235 }
236 if (count($question_has_unused_vars) > 0) {
237 $error_message .= $this->lng->txt("que_contains_unused_var");
238 }
239 $checked = false;
240 if ($this->isSaveCommand()) {
241 ilUtil::sendFailure($error_message);
242 }
243 }
244 foreach ($found_results as $result) {
245 if (is_object($this->object->getUnitrepository()->getUnit($_POST["unit_$result"]))) {
246 $tmp_result_unit = $this->object->getUnitrepository()->getUnit($_POST["unit_$result"]);
247 } else {
248 $tmp_result_unit = null;
249 }
250
251 if ($this->object->getResult($result) != null) {
252 $use_simple_rating = ($_POST["rating_advanced_$result"] == 1) ? false : true;
253 $resObj = new assFormulaQuestionResult(
254 $result,
255 $_POST["range_min_$result"],
256 $_POST["range_max_$result"],
257 $_POST["tolerance_$result"],
258 $tmp_result_unit,
259 $_POST["formula_$result"],
260 $_POST["points_$result"],
261 $_POST["precision_$result"],
262 $use_simple_rating,
263 ($_POST["rating_advanced_$result"] == 1) ? $_POST["rating_sign_$result"] : "",
264 ($_POST["rating_advanced_$result"] == 1) ? $_POST["rating_value_$result"] : "",
265 ($_POST["rating_advanced_$result"] == 1) ? $_POST["rating_unit_$result"] : "",
266 $_POST["result_type_$result"] != 0 ? $_POST["result_type_$result"] : 0
267 );
268 $resObj->setRangeMinTxt($_POST["range_min_$result"]);
269 $resObj->setRangeMaxTxt($_POST["range_max_$result"]);
270 $this->object->addResult($resObj);
271 $this->object->addResultUnits($resObj, $_POST["units_$result"]);
272 }
273 }
274 if ($checked == false) {
275 return 1;
276 } else {
278 return 0;
279 }
280 } else {
281 return 1;
282 }
283 }
284
285 public function resetSavedPreviewSession()
286 {
287 global $DIC;
288 $ilUser = $DIC['ilUser'];
289 $user_id = $ilUser->getId();
290 $question_id = $this->object->getId();
291 require_once 'Modules/TestQuestionPool/classes/class.ilAssQuestionPreviewSession.php';
292 $ilAssQuestionPreviewSession = new ilAssQuestionPreviewSession($user_id, $question_id);
293 $ilAssQuestionPreviewSession->setParticipantsSolution(array());
294 }
295
296 public function isSaveCommand()
297 {
298 return in_array($this->ctrl->getCmd(), array('saveFQ', 'saveEdit', 'saveReturnFQ'));
299 }
300
306 public function editQuestion($checkonly = false)
307 {
308 $save = $this->isSaveCommand();
309
310 $this->getQuestionTemplate();
311
312 include_once("./Services/Form/classes/class.ilPropertyFormGUI.php");
313 $form = new ilPropertyFormGUI();
314 $this->editForm = $form;
315
316 $form->setFormAction($this->ctrl->getFormAction($this));
317 $form->setTitle($this->outQuestionType());
318 $form->setMultipart(false);
319 $form->setTableWidth('100%');
320 $form->setId('assformulaquestion');
321
322 // title, author, description, question, working time (assessment mode)
323 $this->addBasicQuestionFormProperties($form);
324
325 // Add info text
326 $question = $form->getItemByPostVar('question');
327 $question->setInfo($this->lng->txt('fq_question_desc'));
328
329 $variables = $this->object->getVariables();
330 $categorized_units = $this->object->getUnitrepository()->getCategorizedUnits();
331 $result_units = $this->object->__get('resultunits');
332
333 $unit_options = array();
334 $category_name = '';
335 $new_category = false;
336 foreach ((array) $categorized_units as $item) {
340 if ($item instanceof assFormulaQuestionUnitCategory) {
341 if ($category_name != $item->getDisplayString()) {
342 $new_category = true;
343 $category_name = $item->getDisplayString();
344 }
345 continue;
346 }
347 $unit_options[$item->getId()] = $item->getDisplayString() . ($new_category ? ' (' . $category_name . ')' : '');
348 $new_category = false;
349 }
350
351 if (count($variables)) {
352 uasort($variables, function (assFormulaQuestionVariable $v1, assFormulaQuestionVariable $v2) {
353 $num_v1 = (int) substr($v1->getVariable(), 2);
354 $num_v2 = (int) substr($v2->getVariable(), 2);
355 if ($num_v1 > $num_v2) {
356 return 1;
357 } elseif ($num_v1 < $num_v2) {
358 return -1;
359 }
360
361 return 0;
362 });
363
364 foreach ($variables as $variable) {
368 $variable_header = new ilFormSectionHeaderGUI();
369 $variable_header->setTitle(sprintf($this->lng->txt('variable_x'), $variable->getVariable()));
370
371 $range_min = new ilNumberInputGUI($this->lng->txt('range_min'), 'range_min_' . $variable->getVariable());
372 $range_min->allowDecimals(true);
373 $range_min->setSize(3);
374 $range_min->setRequired(true);
375 $range_min->setValue($variable->getRangeMin());
376
377 $range_max = new ilNumberInputGUI($this->lng->txt('range_max'), 'range_max_' . $variable->getVariable());
378 $range_max->allowDecimals(true);
379 $range_max->setSize(3);
380 $range_max->setRequired(true);
381 $range_max->setValue($variable->getRangeMax());
382
383 $units = new ilSelectInputGUI($this->lng->txt('unit'), 'unit_' . $variable->getVariable());
384 $units->setOptions(array(0 => $this->lng->txt('no_selection')) + $unit_options);
385 if (is_object($variable->getUnit())) {
386 $units->setValue($variable->getUnit()->getId());
387 }
388
389 $precision = new ilNumberInputGUI($this->lng->txt('precision'), 'precision_' . $variable->getVariable());
390 $precision->setRequired(true);
391 $precision->setSize(3);
392 $precision->setMinValue(0);
393 $precision->setValue($variable->getPrecision());
394 $precision->setInfo($this->lng->txt('fq_precision_info'));
395
396 $intprecision = new ilNumberInputGUI($this->lng->txt('intprecision'), 'intprecision_' . $variable->getVariable());
397 $intprecision->setSize(3);
398 $intprecision->setMinValue(1);
399 $intprecision->setValue($variable->getIntprecision());
400 $intprecision->setInfo($this->lng->txt('intprecision_info'));
401
402 $form->addItem($variable_header);
403 $form->addItem($range_min);
404 $form->addItem($range_max);
405 $form->addItem($units);
406 $form->addItem($precision);
407 $form->addItem($intprecision);
408 }
409 }
410
411 $results = $this->object->getResults();
412 if (count($results)) {
413 require_once 'Services/Form/classes/class.ilMultiSelectInputGUI.php';
414
416 $num_r1 = (int) substr($r1->getResult(), 2);
417 $num_r2 = (int) substr($r2->getResult(), 2);
418 if ($num_r1 > $num_r2) {
419 return 1;
420 } elseif ($num_r1 < $num_r2) {
421 return -1;
422 }
423
424 return 0;
425 });
426
427 foreach ($results as $result) {
431 $result_header = new ilFormSectionHeaderGUI();
432 $result_header->setTitle(sprintf($this->lng->txt('result_x'), $result->getResult()));
433
434 $formula = new ilTextInputGUI($this->lng->txt('formula'), 'formula_' . $result->getResult());
435 $formula->setInfo($this->lng->txt('fq_formula_desc'));
436 $formula->setRequired(true);
437 $formula->setSize(50);
438 $formula->setValue($result->getFormula());
439 $formula->setSuffix(' = ' . $result->getResult());
440
441 if (
442 preg_match("/suggestrange_(.*)/", $this->ctrl->getCmd(), $matches) &&
443 strcmp($matches[1], $result->getResult()) == 0
444 ) {
445 // suggest a range for the result
446 if (strlen($result->substituteFormula($variables, $results))) {
447 $result->suggestRange($variables, $results);
448 }
449 }
450
451 $range_min = new ilNumberInputGUI($this->lng->txt('range_min'), 'range_min_' . $result->getResult());
452 $range_min->allowDecimals(true);
453 $range_min->setSize(3);
454 $range_min->setRequired(true);
455 $range_min->setValue($result->getRangeMin());
456
457 $range_max = new ilNumberInputGUI($this->lng->txt('range_max'), 'range_max_' . $result->getResult());
458 $range_max->allowDecimals(true);
459 $range_max->setSize(3);
460 $range_max->setRequired(true);
461 $range_max->setValue($result->getRangeMax());
462
463 $matches = array();
464
465 $precision = new ilNumberInputGUI($this->lng->txt('precision'), 'precision_' . $result->getResult());
466 $precision->setRequired(true);
467 $precision->setSize(3);
468 $precision->setMinValue(0);
469 $precision->setInfo($this->lng->txt('fq_precision_info'));
470 $precision->setValue($result->getPrecision());
471
472 $tolerance = new ilNumberInputGUI($this->lng->txt('tolerance'), 'tolerance_' . $result->getResult());
473 $tolerance->setSize(3);
474 $tolerance->setMinValue(0);
475 $tolerance->setMaxValue(100);
476 $tolerance->allowDecimals(true);
477 $tolerance->setInfo($this->lng->txt('tolerance_info'));
478 $tolerance->setValue($result->getTolerance());
479
480 $suggest_range_button = new ilCustomInputGUI('', '');
481 $suggest_range_button->setHtml('<input type="submit" class="btn btn-default" name="cmd[suggestrange_' . $result->getResult() . ']" value="' . $this->lng->txt("suggest_range") . '" />');
482
483 $sel_result_units = new ilSelectInputGUI($this->lng->txt('unit'), 'unit_' . $result->getResult());
484 $sel_result_units->setOptions(array(0 => $this->lng->txt('no_selection')) + $unit_options);
485 $sel_result_units->setInfo($this->lng->txt('result_unit_info'));
486 if (is_object($result->getUnit())) {
487 $sel_result_units->setValue($result->getUnit()->getId());
488 }
489
490 $mc_result_units = new ilMultiSelectInputGUI($this->lng->txt('result_units'), 'units_' . $result->getResult());
491 $mc_result_units->setOptions($unit_options);
492 $mc_result_units->setInfo($this->lng->txt('result_units_info'));
493 $selectedvalues = array();
494 foreach ($unit_options as $unit_id => $txt) {
495 if ($this->hasResultUnit($result, $unit_id, $result_units)) {
496 $selectedvalues[] = $unit_id;
497 }
498 }
499 $mc_result_units->setValue($selectedvalues);
500
501 $result_type = new ilRadioGroupInputGUI($this->lng->txt('result_type_selection'), 'result_type_' . $result->getResult());
502 $result_type->setRequired(true);
503
504 $no_type = new ilRadioOption($this->lng->txt('no_result_type'), 0);
505 $no_type->setInfo($this->lng->txt('fq_no_restriction_info'));
506
507 $result_dec = new ilRadioOption($this->lng->txt('result_dec'), 1);
508 $result_dec->setInfo($this->lng->txt('result_dec_info'));
509
510 $result_frac = new ilRadioOption($this->lng->txt('result_frac'), 2);
511 $result_frac->setInfo($this->lng->txt('result_frac_info'));
512
513 $result_co_frac = new ilRadioOption($this->lng->txt('result_co_frac'), 3);
514 $result_co_frac->setInfo($this->lng->txt('result_co_frac_info'));
515
516 $result_type->addOption($no_type);
517 $result_type->addOption($result_dec);
518 $result_type->addOption($result_frac);
519 $result_type->addOption($result_co_frac);
520 $result_type->setValue(strlen($result->getResultType()) ? $result->getResultType() : 0);
521
522 $points = new ilNumberInputGUI($this->lng->txt('points'), 'points_' . $result->getResult());
523 $points->allowDecimals(true);
524 $points->setRequired(true);
525 $points->setSize(3);
526 $points->setMinValue(0);
527 $points->setValue(strlen($result->getPoints()) ? $result->getPoints() : 1);
528
529 $rating_type = new ilCheckboxInputGUI($this->lng->txt('advanced_rating'), 'rating_advanced_' . $result->getResult());
530 $rating_type->setValue(1);
531 $rating_type->setInfo($this->lng->txt('advanced_rating_info'));
532
533 if (!$save) {
534 $advanced_rating = $this->canUseAdvancedRating($result);
535 if (!$advanced_rating) {
536 $rating_type->setDisabled(true);
537 $rating_type->setChecked(false);
538 } else {
539 $rating_type->setChecked(strlen($result->getRatingSimple()) && $result->getRatingSimple() ? false : true);
540 }
541 }
542
543 $sign = new ilNumberInputGUI($this->lng->txt('rating_sign'), 'rating_sign_' . $result->getResult());
544 $sign->setRequired(true);
545 $sign->setSize(3);
546 $sign->setMinValue(0);
547 $sign->setValue($result->getRatingSign());
548 $rating_type->addSubItem($sign);
549
550 $value = new ilNumberInputGUI($this->lng->txt('rating_value'), 'rating_value_' . $result->getResult());
551 $value->setRequired(true);
552 $value->setSize(3);
553 $value->setMinValue(0);
554 $value->setValue($result->getRatingValue());
555 $rating_type->addSubItem($value);
556
557 $unit = new ilNumberInputGUI($this->lng->txt('rating_unit'), 'rating_unit_' . $result->getResult());
558 $unit->setRequired(true);
559 $unit->setSize(3);
560 $unit->setMinValue(0);
561 $unit->setValue($result->getRatingUnit());
562 $rating_type->addSubItem($unit);
563
564 $info_text = new ilNonEditableValueGUI($this->lng->txt('additional_rating_info'));
565 $rating_type->addSubItem($info_text);
566
567 $form->addItem($result_header);
568 $form->addItem($formula);
569 $form->addItem($range_min);
570 $form->addItem($range_max);
571 $form->addItem($suggest_range_button);
572 $form->addItem($precision);
573 $form->addItem($tolerance);
574 $form->addItem($sel_result_units);
575 $form->addItem($mc_result_units);
576 $form->addItem($result_type);
577 $form->addItem($points);
578 $form->addItem($rating_type);
579 }
580
581 $defined_result_vars = array();
582 $quest_vars = array();
583
584 $defined_result_res = array();
585 $result_vars = array();
586
587 foreach ($variables as $key => $object) {
588 $quest_vars[$key] = $key;
589 }
590
591 foreach ($results as $key => $object) {
592 $result_vars[$key] = $key;
593 }
594
595 foreach ($results as $tmp_result) {
599 $formula = $tmp_result->getFormula();
600
601 preg_match_all("/([$][v][0-9]*)/", $formula, $form_vars);
602 preg_match_all("/([$][r][0-9]*)/", $formula, $form_res);
603 foreach ($form_vars[0] as $res_var) {
604 $defined_result_vars[$res_var] = $res_var;
605 }
606
607 foreach ($form_res[0] as $res_res) {
608 $defined_result_res[$res_res] = $res_res;
609 }
610 }
611 }
612
613 $result_has_undefined_vars = [];
614 $question_has_unused_vars = [];
615 $result_has_undefined_res = [];
616
617 if (is_array($quest_vars) && count($quest_vars) > 0) {
618 $result_has_undefined_vars = array_diff($defined_result_vars, $quest_vars);
619 $question_has_unused_vars = array_diff($quest_vars, $defined_result_vars);
620 }
621
622 if (is_array($result_vars) && count($result_vars) > 0) {
623 $result_has_undefined_res = array_diff($defined_result_res, $result_vars);
624 }
625 $error_message = '';
626
627 if (count($result_has_undefined_vars) > 0 || count($question_has_unused_vars) > 0) {
628 if (count($result_has_undefined_vars) > 0) {
629 $error_message .= $this->lng->txt("res_contains_undef_var") . '<br>';
630 }
631 if (count($question_has_unused_vars) > 0) {
632 $error_message .= $this->lng->txt("que_contains_unused_var") . '<br>';
633 }
634
635 $checked = false;
636 if ($save) {
637 ilUtil::sendFailure($error_message);
638 }
639 }
640
641 if (is_array($result_has_undefined_res) && count($result_has_undefined_res) > 0) {
642 $error_message .= $this->lng->txt("res_contains_undef_res") . '<br>';
643 $checked = false;
644 }
645
646 if ($save && !$checked) {
647 ilUtil::sendFailure($error_message);
648 }
649
650 if ($this->object->getId()) {
651 $hidden = new ilHiddenInputGUI("", "ID");
652 $hidden->setValue($this->object->getId());
653 $form->addItem($hidden);
654 }
655
656 $this->populateTaxonomyFormSection($form);
657
658 $form->addCommandButton('parseQuestion', $this->lng->txt("parseQuestion"));
659 $form->addCommandButton('saveReturnFQ', $this->lng->txt("save_return"));
660 $form->addCommandButton('saveFQ', $this->lng->txt("save"));
661
662 $errors = $checked;
663
664 if ($save) {
665 $found_vars = array();
666 $found_results = array();
667 foreach ((array) $_POST as $key => $value) {
668 if (preg_match("/^unit_(\\\$v\d+)$/", $key, $matches)) {
669 array_push($found_vars, $matches[1]);
670 }
671 if (preg_match("/^unit_(\\\$r\d+)$/", $key, $matches)) {
672 array_push($found_results, $matches[1]);
673 }
674 }
675
676 $form->setValuesByPost();
677 $errors = !$form->checkInput();
678
679 $custom_errors = false;
680 if (count($variables)) {
681 foreach ($variables as $variable) {
685 $min_range = $form->getItemByPostVar('range_min_' . $variable->getVariable());
686 $max_range = $form->getItemByPostVar('range_max_' . $variable->getVariable());
687 if ($min_range->getValue() > $max_range->getValue()) {
688 $min_range->setAlert($this->lng->txt('err_range'));
689 $max_range->setAlert($this->lng->txt('err_range'));
690 $custom_errors = true;
691 }
692 $intPrecision = $form->getItemByPostVar('intprecision_' . $variable->getVariable());
693 if ($intPrecision->getValue() > $max_range->getValue()) {
694 $intPrecision->setAlert($this->lng->txt('err_division'));
695 $custom_errors = true;
696 }
697 }
698 }
699
700 if (count($results)) {
701 foreach ($results as $result) {
705 $min_range = $form->getItemByPostVar('range_min_' . $result->getResult());
706 $max_range = $form->getItemByPostVar('range_max_' . $result->getResult());
707 if ($min_range->getValue() > $max_range->getValue()) {
708 $min_range->setAlert($this->lng->txt('err_range'));
709 $max_range->setAlert($this->lng->txt('err_range'));
710 $custom_errors = true;
711 }
712
713
714 $formula = $form->getItemByPostVar('formula_' . $result->getResult());
715 if (strpos($formula->getValue(), $result->getResult()) !== false) {
716 $formula->setAlert($this->lng->txt('errRecursionInResult'));
717 $custom_errors = true;
718 }
719
720 $result_unit = $form->getItemByPostVar('unit_' . $result->getResult());
721 $rating_advanced = $form->getItemByPostVar('rating_advanced_' . $result->getResult());
722 if (((int) $result_unit->getValue() <= 0) && $rating_advanced->getChecked()) {
723 unset($_POST['rating_advanced_' . $result->getResult()]);
724 $rating_advanced->setDisabled(true);
725 $rating_advanced->setChecked(false);
726 $rating_advanced->setAlert($this->lng->txt('err_rating_advanced_not_allowed'));
727 $custom_errors = true;
728 } elseif ($rating_advanced->getChecked()) {
729 $rating_sign = $form->getItemByPostVar('rating_sign_' . $result->getResult());
730 $rating_value = $form->getItemByPostVar('rating_value_' . $result->getResult());
731 $rating_unit = $form->getItemByPostVar('rating_unit_' . $result->getResult());
732
733 $percentage = $rating_sign->getValue() + $rating_value->getValue() + $rating_unit->getValue();
734 if ($percentage != 100) {
735 $rating_advanced->setAlert($this->lng->txt('err_wrong_rating_advanced'));
736 $custom_errors = true;
737 }
738 }
739
740 preg_match_all("/([$][v][0-9]*)/", $formula->getValue(), $form_vars);
741 $result_has_undefined_vars = array_diff($form_vars[0], (array) $found_vars);
742 if (count($result_has_undefined_vars)) {
743 $errors = true;
744 ilUtil::sendInfo($this->lng->txt('res_contains_undef_var'));
745 }
746 }
747 }
748
749 if ($custom_errors && !$errors) {
750 $errors = true;
751 ilUtil::sendFailure($this->lng->txt('form_input_not_valid'));
752 }
753 $form->setValuesByPost(); // again, because checkInput now performs the whole stripSlashes handling and we need this if we don't want to have duplication of backslashes
754 if ($errors) {
755 $checkonly = false;
756 }
757 }
758
759 if (!$checkonly) {
760 $this->tpl->setVariable('QUESTION_DATA', $form->getHTML());
761 }
762 return $errors;
763 }
764
765 private function hasResultUnit($result, $unit_id, $resultunits)
766 {
767 if (array_key_exists($result->getResult(), $resultunits)) {
768 if (array_key_exists($unit_id, $resultunits[$result->getResult()])) {
769 return true;
770 }
771 }
772 return false;
773 }
774
783 {
784 $resultunit = $result->getUnit();
785
786 /*
787 * if there is a result-unit (unit selectbox) selected it is possible to use advanced rating
788 * if there is no result-unit selected it is NOT possible to use advanced rating, because there is no
789 * definition if the result-value or the unit-value should be the correct solution!!
790 *
791 */
792 if (is_object($resultunit)) {
793 return true;
794 } else {
795 return false;
796 }
797 }
798
799 public function parseQuestion()
800 {
801 $this->writePostData();
802 $this->editQuestion();
803 }
804
805 public function saveReturnFQ()
806 {
807 global $DIC;
808 $ilUser = $DIC['ilUser'];
809 $old_id = $_GET["q_id"];
810 $result = $this->writePostData();
811 if ($result == 0) {
812 $ilUser->setPref("tst_lastquestiontype", $this->object->getQuestionType());
813 $ilUser->writePref("tst_lastquestiontype", $this->object->getQuestionType());
815 $this->object->saveToDb();
816 $originalexists = $this->object->_questionExistsInPool($this->object->original_id);
817 include_once "./Modules/TestQuestionPool/classes/class.assQuestion.php";
818 if (($_GET["calling_test"] || (isset($_GET['calling_consumer']) && (int) $_GET['calling_consumer'])) && $originalexists && assQuestion::_isWriteable($this->object->original_id, $ilUser->getId())) {
819 $this->ctrl->redirect($this, "originalSyncForm");
820 return;
821 } elseif ($_GET["calling_test"]) {
822 require_once 'Modules/Test/classes/class.ilObjTest.php';
823 $test = new ilObjTest($_GET["calling_test"]);
824 #var_dump(assQuestion::_questionExistsInTest($this->object->getId(), $test->getTestId()));
825 $q_id = $this->object->getId();
826 if (!assQuestion::_questionExistsInTest($this->object->getId(), $test->getTestId())) {
827 global $DIC;
828 $tree = $DIC['tree'];
829 $ilDB = $DIC['ilDB'];
830 $ilPluginAdmin = $DIC['ilPluginAdmin'];
831
832 include_once("./Modules/Test/classes/class.ilObjTest.php");
833 $_GET["ref_id"] = $_GET["calling_test"];
834 $test = new ilObjTest($_GET["calling_test"], true);
835
836 require_once 'Modules/Test/classes/class.ilTestQuestionSetConfigFactory.php';
837 $testQuestionSetConfigFactory = new ilTestQuestionSetConfigFactory($tree, $ilDB, $ilPluginAdmin, $test);
838
839 $new_id = $test->insertQuestion(
840 $testQuestionSetConfigFactory->getQuestionSetConfig(),
841 $this->object->getId()
842 );
843
844 $q_id = $new_id;
845 if (isset($_REQUEST['prev_qid'])) {
846 $test->moveQuestionAfter($this->object->getId() + 1, $_REQUEST['prev_qid']);
847 }
848
849 $this->ctrl->setParameter($this, 'q_id', $new_id);
850 $this->ctrl->setParameter($this, 'calling_test', $_GET['calling_test']);
851 #$this->ctrl->setParameter($this, 'test_ref_id', false);
852 }
853 ilUtil::sendSuccess($this->lng->txt("msg_obj_modified"), true);
854 if ($_REQUEST['test_express_mode']) {
856 } else {
857 ilUtil::redirect("ilias.php?baseClass=ilObjTestGUI&cmd=questions&ref_id=" . $_GET["calling_test"]);
858 }
859 } else {
860 if ($this->object->getId() != $old_id) {
861 $this->callNewIdListeners($this->object->getId());
862 ilUtil::sendSuccess($this->lng->txt("msg_obj_modified"), true);
863 $this->ctrl->redirectByClass("ilobjquestionpoolgui", "questions");
864 }
865 if (strcmp($_SESSION["info"], "") != 0) {
866 ilUtil::sendSuccess($_SESSION["info"] . "<br />" . $this->lng->txt("msg_obj_modified"), true);
867 } else {
868 ilUtil::sendSuccess($this->lng->txt("msg_obj_modified"), true);
869 }
870 $this->ctrl->redirectByClass("ilobjquestionpoolgui", "questions");
871 }
872 } else {
873 $ilUser->setPref("tst_lastquestiontype", $this->object->getQuestionType());
874 $ilUser->writePref("tst_lastquestiontype", $this->object->getQuestionType());
875 $this->object->saveToDb();
876 $this->editQuestion();
877 }
878 }
879
880 public function saveFQ()
881 {
882 $result = $this->writePostData();
883
884 if ($result == 1) {
885 $this->editQuestion();
886 } else {
888 $this->save();
889 }
890 }
894 public function checkInput()
895 {
896 if ((!$_POST["title"]) or (!$_POST["author"]) or (!$_POST["question"])) {
897 $this->addErrorMessage($this->lng->txt("fill_out_all_required_fields"));
898 return false;
899 }
900
901
902 return true;
903 }
904
911 {
912 return true;
913 }
914
915
928 public function getSolutionOutput(
929 $active_id,
930 $pass = null,
931 $graphicalOutput = false,
932 $result_output = false,
933 $show_question_only = true,
934 $show_feedback = false,
935 $show_correct_solution = false,
936 $show_manual_scoring = false,
937 $show_question_text = true
938 ) {
939 // get the solution of the user for the active pass or from the last pass if allowed
940 $user_solution = array();
941 if (($active_id > 0) && (!$show_correct_solution)) {
942 $solutions = array();
943 include_once "./Modules/Test/classes/class.ilObjTest.php";
944 if (!ilObjTest::_getUsePreviousAnswers($active_id, true)) {
945 if (is_null($pass)) {
946 $pass = ilObjTest::_getPass($active_id);
947 }
948 }
949 $user_solution["active_id"] = $active_id;
950 $user_solution["pass"] = $pass;
951 $solutions = $this->object->getSolutionValues($active_id, $pass, !$this->getUseIntermediateSolution());
952 foreach ($solutions as $idx => $solution_value) {
953 if (preg_match("/^(\\\$v\\d+)$/", $solution_value["value1"], $matches)) {
954 $user_solution[$matches[1]] = $solution_value["value2"];
955 } elseif (preg_match("/^(\\\$r\\d+)$/", $solution_value["value1"], $matches)) {
956 if (!array_key_exists($matches[1], $user_solution)) {
957 $user_solution[$matches[1]] = array();
958 }
959 $user_solution[$matches[1]]["value"] = $solution_value["value2"];
960 } elseif (preg_match("/^(\\\$r\\d+)_unit$/", $solution_value["value1"], $matches)) {
961 if (!array_key_exists($matches[1], $user_solution)) {
962 $user_solution[$matches[1]] = array();
963 }
964 $user_solution[$matches[1]]["unit"] = $solution_value["value2"];
965 }
966 }
967 } elseif ($active_id) {
968 $solutions = null;
969 include_once "./Modules/Test/classes/class.ilObjTest.php";
970 if (!ilObjTest::_getUsePreviousAnswers($active_id, true)) {
971 if (is_null($pass)) {
972 $pass = ilObjTest::_getPass($active_id);
973 }
974 }
975 $user_solution = (array) $this->object->getBestSolution($this->object->getSolutionValues($active_id, $pass));
976 } elseif (is_object($this->getPreviewSession())) {
977 $solutionValues = array();
978
979 $participantsSolution = $this->getPreviewSession()->getParticipantsSolution();
980 if (is_array($participantsSolution)) {
981 foreach ($participantsSolution as $val1 => $val2) {
982 $solutionValues[] = array('value1' => $val1, 'value2' => $val2);
983 }
984 }
985
986 $user_solution = (array) $this->object->getBestSolution($solutionValues);
987 }
988
989 $template = new ilTemplate("tpl.il_as_qpl_formulaquestion_output_solution.html", true, true, 'Modules/TestQuestionPool');
990 $questiontext = $this->object->substituteVariables($user_solution, $graphicalOutput, true, $result_output);
991
992 $template->setVariable("QUESTIONTEXT", $this->object->prepareTextareaOutput($questiontext, true));
993 $questionoutput = $template->get();
994 $solutiontemplate = new ilTemplate("tpl.il_as_tst_solution_output.html", true, true, "Modules/TestQuestionPool");
995 $feedback = ($show_feedback) ? $this->getGenericFeedbackOutput($active_id, $pass) : "";
996 if (strlen($feedback)) {
997 $cssClass = (
998 $this->hasCorrectSolution($active_id, $pass) ?
1000 );
1001
1002 $solutiontemplate->setVariable("ILC_FB_CSS_CLASS", $cssClass);
1003 $solutiontemplate->setVariable("FEEDBACK", $this->object->prepareTextareaOutput($feedback, true));
1004 }
1005 $solutiontemplate->setVariable("SOLUTION_OUTPUT", $questionoutput);
1006
1007 $solutionoutput = $solutiontemplate->get();
1008 if (!$show_question_only) {
1009 // get page object output
1010 $solutionoutput = $this->getILIASPage($solutionoutput);
1011 }
1012 return $solutionoutput;
1013 }
1014
1015 public function getPreview($show_question_only = false, $showInlineFeedback = false)
1016 {
1017 $user_solution = array();
1018
1019 if (is_object($this->getPreviewSession())) {
1020 $solutions = (array) $this->getPreviewSession()->getParticipantsSolution();
1021
1022 foreach ($solutions as $val1 => $val2) {
1023 if (preg_match("/^(\\\$v\\d+)$/", $val1, $matches)) {
1024 $user_solution[$matches[1]] = $val2;
1025 } elseif (preg_match("/^(\\\$r\\d+)$/", $val1, $matches)) {
1026 if (!array_key_exists($matches[1], $user_solution)) {
1027 $user_solution[$matches[1]] = array();
1028 }
1029 $user_solution[$matches[1]]["value"] = $val2;
1030 } elseif (preg_match("/^(\\\$r\\d+)_unit$/", $val1, $matches)) {
1031 if (!array_key_exists($matches[1], $user_solution)) {
1032 $user_solution[$matches[1]] = array();
1033 }
1034 $user_solution[$matches[1]]["unit"] = $val2;
1035 }
1036
1037 if (preg_match("/^(\\\$r\\d+)/", $val1, $matches) && $user_solution[$matches[1]]["result_type"] == 0) {
1038 $user_solution[$matches[1]]["result_type"] = assFormulaQuestionResult::getResultTypeByQstId($this->object->getId(), $val1);
1039 }
1040 }
1041 }
1042
1043 if (!$this->object->hasRequiredVariableSolutionValues($user_solution)) {
1044 $user_solution = $this->object->getInitialVariableSolutionValues();
1045
1046 if (is_object($this->getPreviewSession())) {
1047 $this->getPreviewSession()->setParticipantsSolution($user_solution);
1048 }
1049 }
1050
1051 $template = new ilTemplate("tpl.il_as_qpl_formulaquestion_output.html", true, true, 'Modules/TestQuestionPool');
1052 if (is_object($this->getPreviewSession())) {
1053 $questiontext = $this->object->substituteVariables($user_solution, false, false, false);
1054 } else {
1055 $questiontext = $this->object->substituteVariables(array());
1056 }
1057 $template->setVariable("QUESTIONTEXT", $this->object->prepareTextareaOutput($questiontext, true));
1058 $questionoutput = $template->get();
1059 if (!$show_question_only) {
1060 // get page object output
1061 $questionoutput = $this->getILIASPage($questionoutput);
1062 }
1063 return $questionoutput;
1064 }
1065
1066 // hey: prevPassSolutions - pass will be always available from now on
1067 public function getTestOutput($active_id, $pass, $is_postponed = false, $use_post_solutions = false, $show_feedback = false)
1068 // hey.
1069 {
1070 ilUtil::sendInfo($this->lng->txt('enter_valid_values'));
1071 // get the solution of the user for the active pass or from the last pass if allowed
1072 $user_solution = array();
1073 if ($active_id) {
1074 $solutions = (array) $this->object->getTestOutputSolutions($active_id, $pass);
1075
1076 $actualPassIndex = null;
1077 if ($this->object->getTestPresentationConfig()->isSolutionInitiallyPrefilled()) {
1078 require_once 'Modules/Test/classes/class.ilObjTest.php';
1079 $actualPassIndex = ilObjTest::_getPass($active_id);
1080 }
1081
1082 foreach ($solutions as $idx => $solution_value) {
1083 if (preg_match("/^(\\\$v\\d+)$/", $solution_value["value1"], $matches)) {
1084 if ($this->object->getTestPresentationConfig()->isSolutionInitiallyPrefilled()) {
1085 $this->object->saveCurrentSolution($active_id, $actualPassIndex, $matches[1], $solution_value["value2"], true);
1086 }
1087
1088 $user_solution[$matches[1]] = $solution_value["value2"];
1089 } elseif (preg_match("/^(\\\$r\\d+)$/", $solution_value["value1"], $matches)) {
1090 if (!array_key_exists($matches[1], $user_solution)) {
1091 $user_solution[$matches[1]] = array();
1092 }
1093 $user_solution[$matches[1]]["value"] = $solution_value["value2"];
1094 } elseif (preg_match("/^(\\\$r\\d+)_unit$/", $solution_value["value1"], $matches)) {
1095 if (!array_key_exists($matches[1], $user_solution)) {
1096 $user_solution[$matches[1]] = array();
1097 }
1098 $user_solution[$matches[1]]["unit"] = $solution_value["value2"];
1099 }
1100
1101 if (preg_match("/^(\\\$r\\d+)/", $solution_value["value1"], $matches) && $user_solution[$matches[1]]["result_type"] == 0) {
1102 $user_solution[$matches[1]]["result_type"] = assFormulaQuestionResult::getResultTypeByQstId($this->object->getId(), $solution_value["value1"]);
1103 }
1104 }
1105 }
1106
1107 // fau: testNav - take question variables always from authorized solution because they are saved with this flag, even if an authorized solution is not saved
1108 $solutions = $this->object->getSolutionValues($active_id, $pass, true);
1109 foreach ($solutions as $idx => $solution_value) {
1110 if (preg_match("/^(\\\$v\\d+)$/", $solution_value["value1"], $matches)) {
1111 $user_solution[$matches[1]] = $solution_value["value2"];
1112 }
1113 }
1114 // fau.
1115
1116 if (!$this->object->hasRequiredVariableSolutionValues($user_solution)) {
1117 foreach ($this->object->getInitialVariableSolutionValues() as $val1 => $val2) {
1118 $this->object->saveCurrentSolution($active_id, $pass, $val1, $val2, true);
1119 }
1120 }
1121
1122 // generate the question output
1123 $template = new ilTemplate("tpl.il_as_qpl_formulaquestion_output.html", true, true, 'Modules/TestQuestionPool');
1124
1125 $questiontext = $this->object->substituteVariables($user_solution);
1126
1127 $template->setVariable("QUESTIONTEXT", $this->object->prepareTextareaOutput($questiontext, true));
1128
1129 $questionoutput = $template->get();
1130 $pageoutput = $this->outQuestionPage("", $is_postponed, $active_id, $questionoutput);
1131 return $pageoutput;
1132 }
1133
1134 public function getSpecificFeedbackOutput($userSolution)
1135 {
1136 return '';
1137 }
1138}
$result
$test
Definition: Utf8Test.php:84
$_GET["client_id"]
$_POST["username"]
$_SESSION["AccountId"]
An exception for terminatinating execution or to throw for unit testing.
Single choice question GUI representation The assFormulaQuestionGUI class encapsulates the GUI repres...
getSpecificFeedbackOutput($userSolution)
Returns the answer specific feedback for the question.
canUseAdvancedRating($result)
Check if advanced rating can be used for a result.
hasResultUnit($result, $unit_id, $resultunits)
getPreview($show_question_only=false, $showInlineFeedback=false)
suggestRange()
Suggest a range for a result @access public.
setQuestionTabs()
Sets the ILIAS tabs for this question type Sets the ILIAS tabs for this question type @access public.
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.
supportsIntermediateSolutionOutput()
Question type specific support of intermediate solution output The function getSolutionOutput respect...
getTestOutput($active_id, $pass, $is_postponed=false, $use_post_solutions=false, $show_feedback=false)
__construct($id=-1)
assFormulaQuestionGUI constructor The constructor takes possible arguments an creates an instance of ...
writePostData($always=false)
{Evaluates a posted edit form and writes the form data in the question object.integer A positive valu...
static getResultTypeByQstId($a_qst_id, $a_result)
Class for single choice questions assFormulaQuestion is a class for single choice questions.
Basic GUI class for assessment questions.
populateTaxonomyFormSection(ilPropertyFormGUI $form)
callNewIdListeners($a_new_id)
Call the new id listeners.
addTab_QuestionHints(ilTabsGUI $tabs)
adds the hints tab to ilTabsGUI
getILIASPage($html="")
Returns the ILIAS Page around a question.
getQuestionTemplate()
get question template
outQuestionPage($a_temp_var, $a_postponed=false, $active_id="", $html="", $inlineFeedbackEnabled=false)
output question page
getUseIntermediateSolution()
Get if intermediate solution should be used for solution output.
addErrorMessage($errormessage)
addBackTab(ilTabsGUI $ilTabs)
hasCorrectSolution($activeId, $passIndex)
addTab_QuestionFeedback(ilTabsGUI $tabs)
adds the feedback tab to ilTabsGUI
addBasicQuestionFormProperties($form)
Add basic question form properties: assessment: title, author, description, question,...
addTab_QuestionPreview(ilTabsGUI $tabsGUI)
getGenericFeedbackOutput($active_id, $pass)
Returns the answer specific feedback for the question.
static _questionExistsInTest($question_id, $test_id)
static _isWriteable($question_id, $user_id)
Returns true if the question is writeable by a certain user.
This class represents a checkbox property in a property form.
This class represents a custom property in a property form.
This class represents a section header in a property form.
This class represents a hidden form property in a property form.
This class represents a multi selection list property in a property form.
This class represents a non editable value in a property form.
This class represents a number property in a property form.
static _getUsePreviousAnswers($active_id, $user_active_user_setting=false)
Returns if the previous results should be hidden for a learner.
static _getPass($active_id)
Retrieves the actual pass of a given user for a given test.
This class represents a property form user interface.
This class represents a property in a property form.
This class represents an option in a radio group.
This class represents a selection list property in a property form.
special template class to simplify handling of ITX/PEAR
static getReturnToPageLink($q_id=null)
This class represents a text property in a property form.
static stripOnlySlashes($a_str)
strip slashes if magic qoutes is enabled
static redirect($a_script)
static sendFailure($a_info="", $a_keep=false)
Send Failure Message to Screen.
static sendInfo($a_info="", $a_keep=false)
Send Info Message to Screen.
$txt
Definition: error.php:13
__construct(Container $dic, ilPlugin $plugin)
@inheritDoc
$url
$results
global $ilDB
$errors
$ilUser
Definition: imgupload.php:18
$DIC
Definition: xapitoken.php:46