ILIAS  release_9 Revision v9.13-25-g2c18ec4c24f
class.assNumericGUI.php
Go to the documentation of this file.
1 <?php
2 
19 require_once './Modules/Test/classes/inc.AssessmentConstants.php';
20 
38 {
46  public function __construct($id = -1)
47  {
49  $this->object = new assNumeric();
50  if ($id >= 0) {
51  $this->object->loadFromDb($id);
52  }
53  }
54 
55  public function getCommand($cmd)
56  {
57  if (substr($cmd, 0, 6) == "delete") {
58  $cmd = "delete";
59  }
60  return $cmd;
61  }
62 
66  protected function writePostData(bool $always = false): int
67  {
68  $hasErrors = (!$always) ? $this->editQuestion(true) : false;
69  if (!$hasErrors) {
73  $this->saveTaxonomyAssignments();
74  return 0;
75  }
76  return 1;
77  }
78 
86  public function editQuestion($checkonly = false): bool
87  {
88  $save = $this->isSaveCommand();
89  $this->getQuestionTemplate();
90 
91  $form = new ilPropertyFormGUI();
92  $this->editForm = $form;
93 
94  $form->setFormAction($this->ctrl->getFormAction($this));
95  $form->setTitle($this->outQuestionType());
96  $form->setMultipart(true);
97  $form->setTableWidth("100%");
98  $form->setId("assnumeric");
99 
100  $this->addBasicQuestionFormProperties($form);
101  $this->populateQuestionSpecificFormPart($form);
102  $this->populateAnswerSpecificFormPart($form);
103  $this->populateTaxonomyFormSection($form);
104  $this->addQuestionFormCommandButtons($form);
105 
106  $errors = false;
107 
108  if ($save) {
109  $form->setValuesByPost();
110  $errors = !$form->checkInput();
111  $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
112 
113  $lower = $form->getItemByPostVar('lowerlimit');
114  $upper = $form->getItemByPostVar('upperlimit');
115 
116  if (!$this->checkRange($lower->getValue(), $upper->getValue())) {
117  global $DIC;
118  $lower->setAlert($DIC->language()->txt('qpl_numeric_lower_needs_valid_lower_alert'));
119  $upper->setAlert($DIC->language()->txt('qpl_numeric_upper_needs_valid_upper_alert'));
120  $this->tpl->setOnScreenMessage('failure', $DIC->language()->txt("form_input_not_valid"));
121  $errors = true;
122  }
123 
124  if ($errors) {
125  $checkonly = false;
126  }
127  }
128 
129  if (!$checkonly) {
130  $this->tpl->setVariable("QUESTION_DATA", $form->getHTML());
131  }
132  return $errors;
133  }
134 
142  public function checkRange($lower, $upper): bool
143  {
144  $eval = new EvalMath();
145  $eval->suppress_errors = true;
146  if (($eval->e($lower) !== false) and ($eval->e($upper) !== false)) {
147  if ($eval->e($lower) <= $eval->e($upper)) {
148  return true;
149  } else {
150  return false;
151  }
152  }
153  return false;
154  }
155 
169  public function getSolutionOutput(
170  $active_id,
171  $pass = null,
172  $graphicalOutput = false,
173  $result_output = false,
174  $show_question_only = true,
175  $show_feedback = false,
176  $show_correct_solution = false,
177  $show_manual_scoring = false,
178  $show_question_text = true
179  ): string {
180  // get the solution of the user for the active pass or from the last pass if allowed
181  $solutions = [];
182  if (($active_id > 0) && (!$show_correct_solution)) {
183  $solutions = $this->object->getSolutionValues($active_id, $pass);
184  } else {
185  array_push($solutions, [
186  'value1' => sprintf(
187  $this->lng->txt("value_between_x_and_y"),
188  $this->object->getLowerLimit(),
189  $this->object->getUpperLimit()
190  )
191  ]);
192  }
193 
194  return $this->renderSolutionOutput(
195  $solutions,
196  $active_id,
197  $pass,
198  $graphicalOutput,
199  $result_output,
200  $show_question_only,
201  $show_feedback,
202  $show_correct_solution,
203  $show_manual_scoring,
204  $show_question_text,
205  false,
206  false,
207  );
208  }
209 
210  public function renderSolutionOutput(
211  mixed $user_solutions,
212  int $active_id,
213  ?int $pass,
214  bool $graphical_output = false,
215  bool $result_output = false,
216  bool $show_question_only = true,
217  bool $show_feedback = false,
218  bool $show_correct_solution = false,
219  bool $show_manual_scoring = false,
220  bool $show_question_text = true,
221  bool $show_autosave_title = false,
222  bool $show_inline_feedback = false,
223  ): ?string {
224  $template = new ilTemplate("tpl.il_as_qpl_numeric_output_solution.html", true, true, "Modules/TestQuestionPool");
225  $solutiontemplate = new ilTemplate("tpl.il_as_tst_solution_output.html", true, true, "Modules/TestQuestionPool");
226  if (is_array($user_solutions)) {
227  if (($active_id > 0) && (!$show_correct_solution)) {
228  if ($graphical_output) {
229  if ($this->object->getStep() === null) {
230  $reached_points = $this->object->getReachedPoints($active_id, $pass);
231  } else {
232  $reached_points = $this->object->calculateReachedPoints($active_id, $pass);
233  }
234 
235  $correctness_icon = $this->generateCorrectnessIconsForCorrectness(self::CORRECTNESS_NOT_OK);
236  if ($reached_points == $this->object->getMaximumPoints()) {
237  $correctness_icon = $this->generateCorrectnessIconsForCorrectness(self::CORRECTNESS_OK);
238  }
239  $template->setCurrentBlock("icon_ok");
240  $template->setVariable("ICON_OK", $correctness_icon);
241  $template->parseCurrentBlock();
242  }
243  }
244  foreach ($user_solutions as $solution) {
245  $template->setVariable("NUMERIC_VALUE", $solution['value1']);
246  }
247  if (count($user_solutions) == 0) {
248  $template->setVariable("NUMERIC_VALUE", "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;");
249  }
250  }
251  $template->setVariable("NUMERIC_SIZE", $this->object->getMaxChars());
252  if ($show_question_text == true) {
253  $template->setVariable("QUESTIONTEXT", $this->object->getQuestionForHTMLOutput());
254  }
255  $questionoutput = $template->get();
256  //$feedback = ($show_feedback) ? $this->getAnswerFeedbackOutput($active_id, $pass) : ""; // Moving new method
257  // due to deprecation.
258  $feedback = ($show_feedback && !$this->isTestPresentationContext()) ? $this->getGenericFeedbackOutput((int) $active_id, $pass) : "";
259  if (strlen($feedback)) {
260  $cssClass = (
261  $this->hasCorrectSolution($active_id, $pass) ?
263  );
264 
265  $solutiontemplate->setVariable("ILC_FB_CSS_CLASS", $cssClass);
266  $solutiontemplate->setVariable("FEEDBACK", ilLegacyFormElementsUtil::prepareTextareaOutput($feedback, true));
267  }
268  $solutiontemplate->setVariable("SOLUTION_OUTPUT", $questionoutput);
269 
270  $solutionoutput = $solutiontemplate->get();
271  if (!$show_question_only) {
272  // get page object output
273  $solutionoutput = $this->getILIASPage($solutionoutput);
274  }
275  return $solutionoutput;
276  }
277 
283  public function getPreview($show_question_only = false, $showInlineFeedback = false): string
284  {
285  // generate the question output
286  $template = new ilTemplate("tpl.il_as_qpl_numeric_output.html", true, true, "Modules/TestQuestionPool");
287  if (is_object($this->getPreviewSession())) {
288  $template->setVariable("NUMERIC_VALUE", " value=\"" . $this->getPreviewSession()->getParticipantsSolution() . "\"");
289  }
290  $template->setVariable("NUMERIC_SIZE", $this->object->getMaxChars());
291  $template->setVariable("QUESTIONTEXT", $this->object->getQuestionForHTMLOutput());
292  $questionoutput = $template->get();
293  if (!$show_question_only) {
294  // get page object output
295  $questionoutput = $this->getILIASPage($questionoutput);
296  }
297  return $questionoutput;
298  }
299 
308  // hey: prevPassSolutions - pass will be always available from now on
309  public function getTestOutput($active_id, $pass, $is_postponed = false, $use_post_solutions = false, $inlineFeedback = false): string
310  // hey.
311  {
312  $solutions = null;
313  // get the solution of the user for the active pass or from the last pass if allowed
314  if ($use_post_solutions !== false) {
316  $solutions = array(
317  array('value1' => $use_post_solutions['numeric_result'])
318  );
319  } elseif ($active_id) {
320  $solutions = $this->object->getTestOutputSolutions($active_id, $pass);
321  }
322 
323  // generate the question output
324  $template = new ilTemplate("tpl.il_as_qpl_numeric_output.html", true, true, "Modules/TestQuestionPool");
325  if (is_array($solutions)) {
326  foreach ($solutions as $solution) {
327  $template->setVariable("NUMERIC_VALUE", " value=\"" . $solution['value1'] . "\"");
328  }
329  }
330  $template->setVariable("NUMERIC_SIZE", $this->object->getMaxChars());
331  $template->setVariable("QUESTIONTEXT", $this->object->getQuestionForHTMLOutput());
332  $questionoutput = $template->get();
333  $pageoutput = $this->outQuestionPage("", $is_postponed, $active_id, $questionoutput);
334  return $pageoutput;
335  }
336 
342  public function getSpecificFeedbackOutput(array $userSolution): string
343  {
344  $output = "";
346  }
347 
349  {
350  $this->object->setMaxChars($_POST["maxchars"]);
351  }
352 
353  public function writeAnswerSpecificPostData(ilPropertyFormGUI $form): void
354  {
355  $this->object->setLowerLimit($_POST['lowerlimit']);
356  $this->object->setUpperLimit($_POST['upperlimit']);
357  $this->object->setPoints((float) str_replace(',', '.', $_POST['points']));
358  }
359 
361  {
362  // maxchars
363  $maxchars = new ilNumberInputGUI($this->lng->txt("maxchars"), "maxchars");
364  $maxchars->setInfo($this->lng->txt('qpl_maxchars_info_numeric_question'));
365  $maxchars->setSize(10);
366  $maxchars->setDecimals(0);
367  $maxchars->setMinValue(1);
368  $maxchars->setRequired(true);
369  if ($this->object->getMaxChars() > 0) {
370  $maxchars->setValue($this->object->getMaxChars());
371  }
372  $form->addItem($maxchars);
373  return $form;
374  }
375 
377  {
378  // points
379  $points = new ilNumberInputGUI($this->lng->txt("points"), "points");
380  $points->allowDecimals(true);
381  $points->setValue($this->object->getPoints() > 0 ? $this->object->getPoints() : '');
382  $points->setRequired(true);
383  $points->setSize(3);
384  $points->setMinValue(0.0);
385  $points->setMinvalueShouldBeGreater(true);
386  $form->addItem($points);
387 
388  $header = new ilFormSectionHeaderGUI();
389  $header->setTitle($this->lng->txt("range"));
390  $form->addItem($header);
391 
392  // lower bound
393  $lower_limit = new ilFormulaInputGUI($this->lng->txt("range_lower_limit"), "lowerlimit");
394  $lower_limit->setSize(25);
395  $lower_limit->setMaxLength(20);
396  $lower_limit->setRequired(true);
397  $lower_limit->setValue((string) $this->object->getLowerLimit());
398  $form->addItem($lower_limit);
399 
400  // upper bound
401  $upper_limit = new ilFormulaInputGUI($this->lng->txt("range_upper_limit"), "upperlimit");
402  $upper_limit->setSize(25);
403  $upper_limit->setMaxLength(20);
404  $upper_limit->setRequired(true);
405  $upper_limit->setValue((string) $this->object->getUpperLimit());
406  $form->addItem($upper_limit);
407 
408  // reset input length, if max chars are set
409  if ($this->object->getMaxChars() > 0) {
410  $lower_limit->setSize($this->object->getMaxChars());
411  $lower_limit->setMaxLength($this->object->getMaxChars());
412  $upper_limit->setSize($this->object->getMaxChars());
413  $upper_limit->setMaxLength($this->object->getMaxChars());
414  }
415  return $form;
416  }
417 
428  {
429  return [];
430  }
431 
442  {
443  return [];
444  }
445 
452  public function getAggregatedAnswersView(array $relevant_answers): string
453  {
454  return $this->renderAggregateView(
455  $this->aggregateAnswers($relevant_answers)
456  )->get();
457  }
458 
459  public function aggregateAnswers($relevant_answers_chosen): array
460  {
461  $aggregate = [];
462 
463  foreach ($relevant_answers_chosen as $relevant_answer) {
464  if (array_key_exists($relevant_answer['value1'], $aggregate)) {
465  $aggregate[$relevant_answer['value1']]++;
466  } else {
467  $aggregate[$relevant_answer['value1']] = 1;
468  }
469  }
470  return $aggregate;
471  }
472 
478  public function renderAggregateView($aggregate): ilTemplate
479  {
480  $tpl = new ilTemplate('tpl.il_as_aggregated_answers_table.html', true, true, "Modules/TestQuestionPool");
481 
482  $tpl->setCurrentBlock('headercell');
483  $tpl->setVariable('HEADER', $this->lng->txt('tst_answer_aggr_answer_header'));
485 
486  $tpl->setCurrentBlock('headercell');
487  $tpl->setVariable('HEADER', $this->lng->txt('tst_answer_aggr_frequency_header'));
489 
490  foreach ($aggregate as $key => $value) {
491  $tpl->setCurrentBlock('aggregaterow');
492  $tpl->setVariable('OPTION', $key);
493  $tpl->setVariable('COUNT', $value);
495  }
496  return $tpl;
497  }
498 
499  public function getAnswersFrequency($relevantAnswers, $questionIndex): array
500  {
501  $answers = [];
502 
503  foreach ($relevantAnswers as $ans) {
504  if (!isset($answers[$ans['value1']])) {
505  $answers[$ans['value1']] = array(
506  'answer' => $ans['value1'], 'frequency' => 0
507  );
508  }
509 
510  $answers[$ans['value1']]['frequency']++;
511  }
512 
513  return $answers;
514  }
515 
517  {
518  // points
519  $points = new ilNumberInputGUI($this->lng->txt("points"), "points");
520  $points->allowDecimals(true);
521  $points->setValue($this->object->getPoints() > 0 ? $this->object->getPoints() : '');
522  $points->setRequired(true);
523  $points->setSize(3);
524  $points->setMinValue(0.0);
525  $points->setMinvalueShouldBeGreater(true);
526  $form->addItem($points);
527 
528  $header = new ilFormSectionHeaderGUI();
529  $header->setTitle($this->lng->txt("range"));
530  $form->addItem($header);
531 
532  // lower bound
533  $lower_limit = new ilFormulaInputGUI($this->lng->txt("range_lower_limit"), "lowerlimit");
534  $lower_limit->setSize(25);
535  $lower_limit->setMaxLength(20);
536  $lower_limit->setRequired(true);
537  $lower_limit->setValue($this->object->getLowerLimit());
538  $form->addItem($lower_limit);
539 
540  // upper bound
541  $upper_limit = new ilFormulaInputGUI($this->lng->txt("range_upper_limit"), "upperlimit");
542  $upper_limit->setSize(25);
543  $upper_limit->setMaxLength(20);
544  $upper_limit->setRequired(true);
545  $upper_limit->setValue($this->object->getUpperLimit());
546  $form->addItem($upper_limit);
547 
548  // reset input length, if max chars are set
549  if ($this->object->getMaxChars() > 0) {
550  $lower_limit->setSize($this->object->getMaxChars());
551  $lower_limit->setMaxLength($this->object->getMaxChars());
552  $upper_limit->setSize($this->object->getMaxChars());
553  $upper_limit->setMaxLength($this->object->getMaxChars());
554  }
555  }
556 
561  {
562  $this->object->setPoints((float) str_replace(',', '.', $form->getInput('points')));
563  $this->object->setLowerLimit((float) str_replace(',', '.', $form->getInput('lowerlimit')));
564  $this->object->setUpperLimit((float) str_replace(',', '.', $form->getInput('upperlimit')));
565  }
566 }
editQuestion($checkonly=false)
Creates an output of the edit form for the question.
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
hasCorrectSolution($activeId, $passIndex)
generateCorrectnessIconsForCorrectness(int $correctness)
setCurrentBlock(string $blockname=self::DEFAULT_BLOCK)
Sets the template to the given block.
getPreview($show_question_only=false, $showInlineFeedback=false)
getAfterParticipationSuppressionAnswerPostVars()
Returns a list of postvars which will be suppressed in the form output when used in scoring adjustmen...
writeQuestionSpecificPostData(ilPropertyFormGUI $form)
Extracts the question specific values from $_POST and applies them to the data object.
saveCorrectionsFormProperties(ilPropertyFormGUI $form)
getAnswersFrequency($relevantAnswers, $questionIndex)
aggregateAnswers($relevant_answers_chosen)
addBasicQuestionFormProperties(ilPropertyFormGUI $form)
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.
getSpecificFeedbackOutput(array $userSolution)
parseCurrentBlock(string $blockname=self::DEFAULT_BLOCK)
Parses the given block.
ilGlobalPageTemplate $tpl
populateTaxonomyFormSection(ilPropertyFormGUI $form)
getInput(string $a_post_var, bool $ensureValidation=true)
Returns the input of an item, if item provides getInput method and as fallback the value of the HTTP-...
addQuestionFormCommandButtons(ilPropertyFormGUI $form)
global $DIC
Definition: feed.php:28
writeAnswerSpecificPostData(ilPropertyFormGUI $form)
Extracts the answer specific values from $_POST and applies them to the data object.
checkRange($lower, $upper)
Checks the range limits.
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
__construct(VocabulariesInterface $vocabularies)
string $key
Consumer key/client ID value.
Definition: System.php:193
getTestOutput($active_id, $pass, $is_postponed=false, $use_post_solutions=false, $inlineFeedback=false)
Basic GUI class for assessment questions.
populateQuestionSpecificFormPart(\ilPropertyFormGUI $form)
getAggregatedAnswersView(array $relevant_answers)
Returns an html string containing a question specific representation of the answers so far given in t...
getAfterParticipationSuppressionQuestionPostVars()
Returns a list of postvars which will be suppressed in the form output when used in scoring adjustmen...
populateCorrectionsFormProperties(ilPropertyFormGUI $form)
getILIASPage(string $html="")
Returns the ILIAS Page around a question.
outQuestionPage($a_temp_var, $a_postponed=false, $active_id="", $html="", $inlineFeedbackEnabled=false)
writePostData(bool $always=false)
{}
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
$id
plugin.php for ilComponentBuildPluginInfoObjectiveTest::testAddPlugins
Definition: plugin.php:23
__construct($id=-1)
assNumericGUI constructor
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
renderAggregateView($aggregate)
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
renderSolutionOutput(mixed $user_solutions, int $active_id, ?int $pass, bool $graphical_output=false, bool $result_output=false, bool $show_question_only=true, bool $show_feedback=false, bool $show_correct_solution=false, bool $show_manual_scoring=false, bool $show_question_text=true, bool $show_autosave_title=false, bool $show_inline_feedback=false,)
static prepareTextareaOutput(string $txt_output, bool $prepare_for_latex_output=false, bool $omitNl2BrWhenTextArea=false)
Prepares a string for a text area output where latex code may be in it If the text is HTML-free...
populateAnswerSpecificFormPart(\ilPropertyFormGUI $form)
setVariable(string $variable, $value='')
Sets the given variable to the given value.
getGenericFeedbackOutput(int $active_id, ?int $pass)