ILIAS  release_6 Revision v6.24-5-g0c8bfefb3b8
All Data Structures Namespaces Files Functions Variables Modules Pages
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 
4 include_once "./Modules/TestQuestionPool/classes/class.assQuestionGUI.php";
5 include_once "./Modules/TestQuestionPool/classes/class.assFormulaQuestion.php";
6 include_once "./Modules/TestQuestionPool/classes/class.assFormulaQuestionResult.php";
7 include_once "./Modules/TestQuestionPool/classes/class.assFormulaQuestionVariable.php";
8 include_once "./Modules/TestQuestionPool/classes/class.assFormulaQuestionUnit.php";
9 include_once "./Modules/TestQuestionPool/classes/class.assFormulaQuestionUnitCategory.php";
10 include_once "./Modules/Test/classes/inc.AssessmentConstants.php";
11 require_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 {
277  $this->resetSavedPreviewSession();
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 
415  uasort($results, function (assFormulaQuestionResult $r1, assFormulaQuestionResult $r2) {
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 
782  private function canUseAdvancedRating($result)
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());
814  $this->saveTaxonomyAssignments();
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 {
887  $this->saveTaxonomyAssignments();
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 }
hasCorrectSolution($activeId, $passIndex)
$errors
addTab_QuestionPreview(ilTabsGUI $tabsGUI)
This class represents an option in a radio group.
setOptions($a_options)
Set Options.
addBasicQuestionFormProperties($form)
Add basic question form properties: assessment: title, author, description, question, working time.
static _getPass($active_id)
Retrieves the actual pass of a given user for a given test.
$_SESSION["AccountId"]
$result
addTab_QuestionHints(ilTabsGUI $tabs)
adds the hints tab to ilTabsGUI
This class represents a property form user interface.
Single choice question GUI representation The assFormulaQuestionGUI class encapsulates the GUI repres...
addErrorMessage($errormessage)
$_GET["client_id"]
This class represents a section header in a property form.
suggestRange()
Suggest a range for a result public.
This class represents a checkbox property in a property form.
Class for single choice questions assFormulaQuestion is a class for single choice questions...
getPreview($show_question_only=false, $showInlineFeedback=false)
canUseAdvancedRating($result)
Check if advanced rating can be used for a 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.
callNewIdListeners($a_new_id)
Call the new id listeners.
getQuestionTemplate()
get question template
setInfo($a_info)
Set Info.
populateTaxonomyFormSection(ilPropertyFormGUI $form)
getUseIntermediateSolution()
Get if intermediate solution should be used for solution output.
static getResultTypeByQstId($a_qst_id, $a_result)
static stripOnlySlashes($a_str)
strip slashes if magic qoutes is enabled
allowDecimals($a_value)
Toggle Decimals.
static sendInfo($a_info="", $a_keep=false)
Send Info Message to Screen.
setQuestionTabs()
Sets the ILIAS tabs for this question type Sets the ILIAS tabs for this question type public...
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 property in a property form.
static getReturnToPageLink($q_id=null)
getILIASPage($html="")
Returns the ILIAS Page around a question.
This class represents a number property in a property form.
setValue($a_value)
Set Value.
getTestOutput($active_id, $pass, $is_postponed=false, $use_post_solutions=false, $show_feedback=false)
$ilUser
Definition: imgupload.php:18
addTab_QuestionFeedback(ilTabsGUI $tabs)
adds the feedback tab to ilTabsGUI
$results
Basic GUI class for assessment questions.
$txt
Definition: error.php:13
static sendFailure($a_info="", $a_keep=false)
Send Failure Message to Screen.
__construct($id=-1)
assFormulaQuestionGUI constructor The constructor takes possible arguments an creates an instance of ...
static _questionExistsInTest($question_id, $test_id)
setSize($a_size)
Set Size.
This class represents a custom property in a property form.
This class represents a non editable value in a property form.
outQuestionPage($a_temp_var, $a_postponed=false, $active_id="", $html="", $inlineFeedbackEnabled=false)
output question page
__construct(Container $dic, ilPlugin $plugin)
addBackTab(ilTabsGUI $ilTabs)
global $ilDB
$DIC
Definition: xapitoken.php:46
$url
getGenericFeedbackOutput($active_id, $pass)
Returns the answer specific feedback for the question.
static _getUsePreviousAnswers($active_id, $user_active_user_setting=false)
Returns if the previous results should be hidden for a learner.
static redirect($a_script)
save()
save question
supportsIntermediateSolutionOutput()
Question type specific support of intermediate solution output The function getSolutionOutput respect...
hasResultUnit($result, $unit_id, $resultunits)
$_POST["username"]
setRequired($a_required)
Set Required.
$test
Definition: Utf8Test.php:84
static _isWriteable($question_id, $user_id)
Returns true if the question is writeable by a certain user.