ILIAS  trunk Revision v11.0_alpha-2638-g80c1d007f79
class.assNumericGUI.php
Go to the documentation of this file.
1 <?php
2 
36 {
44  public function __construct($id = -1)
45  {
47  $this->object = new assNumeric();
48  if ($id >= 0) {
49  $this->object->loadFromDb($id);
50  }
51  }
52 
53  public function getCommand($cmd)
54  {
55  if (substr($cmd, 0, 6) == "delete") {
56  $cmd = "delete";
57  }
58  return $cmd;
59  }
60 
64  protected function writePostData(bool $always = false): int
65  {
66  $hasErrors = (!$always) ? $this->editQuestion(true) : false;
67  if (!$hasErrors) {
71  $this->saveTaxonomyAssignments();
72  return 0;
73  }
74  return 1;
75  }
76 
77  public function editQuestion(
78  bool $checkonly = false,
79  ?bool $is_save_cmd = null
80  ): bool {
81  $save = $is_save_cmd ?? $this->isSaveCommand();
82 
83  $form = new ilPropertyFormGUI();
84  $this->editForm = $form;
85 
86  $form->setFormAction($this->ctrl->getFormAction($this));
87  $form->setTitle($this->outQuestionType());
88  $form->setMultipart(true);
89  $form->setTableWidth("100%");
90  $form->setId("assnumeric");
91 
92  $this->addBasicQuestionFormProperties($form);
94  $this->populateAnswerSpecificFormPart($form);
95  $this->populateTaxonomyFormSection($form);
96  $this->addQuestionFormCommandButtons($form);
97 
98  $errors = false;
99 
100  if ($save) {
101  $form->setValuesByPost();
102  $errors = !$form->checkInput();
103  $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
104 
105  $lower = $form->getItemByPostVar('lowerlimit');
106  $upper = $form->getItemByPostVar('upperlimit');
107 
108  $to_float_trafo = $this->refinery->byTrying([
109  $this->refinery->kindlyTo()->float(),
110  $this->refinery->always(0.0)
111  ]);
112 
113  if (!$this->checkRange(
114  $to_float_trafo->transform($lower->getValue()),
115  $to_float_trafo->transform($upper->getValue())
116  )) {
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->renderEditForm($form);
131  }
132  return $errors;
133  }
134 
135  public function checkRange(float $lower, float $upper): bool
136  {
137  $eval = new EvalMath();
138  $eval->suppress_errors = true;
139  if (($eval->e($lower) !== false) and ($eval->e($upper) !== false)) {
140  if ($eval->e($lower) <= $eval->e($upper)) {
141  return true;
142  } else {
143  return false;
144  }
145  }
146  return false;
147  }
148 
149  public function getSolutionOutput(
150  int $active_id,
151  ?int $pass = null,
152  bool $graphical_output = false,
153  bool $result_output = false,
154  bool $show_question_only = true,
155  bool $show_feedback = false,
156  bool $show_correct_solution = false,
157  bool $show_manual_scoring = false,
158  bool $show_question_text = true,
159  bool $show_inline_feedback = true
160  ): string {
161  // get the solution of the user for the active pass or from the last pass if allowed
162  $solutions = [];
163  if (($active_id > 0) && (!$show_correct_solution)) {
164  $solutions = $this->object->getSolutionValues($active_id, $pass);
165  } else {
166  array_push($solutions, [
167  'value1' => sprintf(
168  $this->lng->txt("value_between_x_and_y"),
169  $this->object->getLowerLimit(),
170  $this->object->getUpperLimit()
171  )
172  ]);
173  }
174 
175  return $this->renderSolutionOutput(
176  $solutions,
177  $active_id,
178  $pass,
179  $graphical_output,
180  $result_output,
181  $show_question_only,
182  $show_feedback,
183  $show_correct_solution,
184  $show_manual_scoring,
185  $show_question_text,
186  false,
187  $show_inline_feedback
188  );
189  }
190 
191  public function renderSolutionOutput(
192  mixed $user_solutions,
193  int $active_id,
194  ?int $pass,
195  bool $graphical_output = false,
196  bool $result_output = false,
197  bool $show_question_only = true,
198  bool $show_feedback = false,
199  bool $show_correct_solution = false,
200  bool $show_manual_scoring = false,
201  bool $show_question_text = true,
202  bool $show_autosave_title = false,
203  bool $show_inline_feedback = false,
204  ): ?string {
205  $template = new ilTemplate("tpl.il_as_qpl_numeric_output_solution.html", true, true, "components/ILIAS/TestQuestionPool");
206  $solutiontemplate = new ilTemplate("tpl.il_as_tst_solution_output.html", true, true, "components/ILIAS/TestQuestionPool");
207  if (is_array($user_solutions)) {
208  if (($active_id > 0) && (!$show_correct_solution)) {
209  if ($graphical_output) {
210  if ($this->object->getStep() === null) {
211  $reached_points = $this->object->getReachedPoints($active_id, $pass);
212  } else {
213  $reached_points = $this->object->calculateReachedPoints($active_id, $pass);
214  }
215 
216  $correctness_icon = $this->generateCorrectnessIconsForCorrectness(self::CORRECTNESS_NOT_OK);
217  if ($reached_points == $this->object->getMaximumPoints()) {
218  $correctness_icon = $this->generateCorrectnessIconsForCorrectness(self::CORRECTNESS_OK);
219  }
220  $template->setCurrentBlock("icon_ok");
221  $template->setVariable("ICON_OK", $correctness_icon);
222  $template->parseCurrentBlock();
223  }
224  }
225  foreach ($user_solutions as $solution) {
226  $template->setVariable("NUMERIC_VALUE", $solution['value1']);
227  }
228  if (count($user_solutions) == 0) {
229  $template->setVariable("NUMERIC_VALUE", "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;");
230  }
231  }
232  $template->setVariable("NUMERIC_SIZE", $this->object->getMaxChars());
233  if ($show_question_text == true) {
234  $template->setVariable("QUESTIONTEXT", $this->renderLatex($this->object->getQuestionForHTMLOutput()));
235  }
236  $questionoutput = $template->get();
237  //$feedback = ($show_feedback) ? $this->getAnswerFeedbackOutput($active_id, $pass) : ""; // Moving new method
238  // due to deprecation.
239  $feedback = ($show_feedback && !$this->isTestPresentationContext()) ? $this->getGenericFeedbackOutput((int) $active_id, $pass) : "";
240  if (strlen($feedback)) {
241  $cssClass = (
242  $this->hasCorrectSolution($active_id, $pass) ?
244  );
245 
246  $solutiontemplate->setVariable("ILC_FB_CSS_CLASS", $cssClass);
247  $solutiontemplate->setVariable("FEEDBACK", ilLegacyFormElementsUtil::prepareTextareaOutput($feedback, true));
248  }
249  $solutiontemplate->setVariable("SOLUTION_OUTPUT", $questionoutput);
250 
251  $solutionoutput = $solutiontemplate->get();
252  if (!$show_question_only) {
253  // get page object output
254  $solutionoutput = $this->getILIASPage($solutionoutput);
255  }
256  return $solutionoutput;
257  }
258 
259  public function getPreview(
260  bool $show_question_only = false,
261  bool $show_inline_feedback = false
262  ): string {
263  // generate the question output
264  $template = new ilTemplate("tpl.il_as_qpl_numeric_output.html", true, true, "components/ILIAS/TestQuestionPool");
265  if (is_object($this->getPreviewSession())) {
266  $template->setVariable("NUMERIC_VALUE", " value=\"" . $this->getPreviewSession()->getParticipantsSolution() . "\"");
267  }
268  $template->setVariable("NUMERIC_SIZE", $this->object->getMaxChars());
269  $template->setVariable("QUESTIONTEXT", $this->renderLatex($this->object->getQuestionForHTMLOutput()));
270  $questionoutput = $template->get();
271  if (!$show_question_only) {
272  // get page object output
273  $questionoutput = $this->getILIASPage($questionoutput);
274  }
275  return $questionoutput;
276  }
277 
278  public function getTestOutput(
279  int $active_id,
280  int $pass,
281  bool $is_question_postponed = false,
282  array|bool $user_post_solutions = false,
283  bool $show_specific_inline_feedback = false
284  ): string {
285  $solutions = null;
286  // get the solution of the user for the active pass or from the last pass if allowed
287  if ($user_post_solutions !== false) {
289  $solutions = [
290  ['value1' => $user_post_solutions['numeric_result']]
291  ];
292  } elseif ($active_id) {
293  $solutions = $this->object->getTestOutputSolutions($active_id, $pass);
294  }
295 
296  // generate the question output
297  $template = new ilTemplate("tpl.il_as_qpl_numeric_output.html", true, true, "components/ILIAS/TestQuestionPool");
298  if (is_array($solutions)) {
299  foreach ($solutions as $solution) {
300  $template->setVariable("NUMERIC_VALUE", " value=\"" . $solution['value1'] . "\"");
301  }
302  }
303  $template->setVariable("NUMERIC_SIZE", $this->object->getMaxChars());
304  $template->setVariable("QUESTIONTEXT", $this->renderLatex($this->object->getQuestionForHTMLOutput()));
305  $questionoutput = $template->get();
306  $pageoutput = $this->outQuestionPage("", $is_question_postponed, $active_id, $questionoutput);
307  return $pageoutput;
308  }
309 
315  public function getSpecificFeedbackOutput(array $userSolution): string
316  {
317  $output = "";
319  }
320 
322  {
323  $this->object->setMaxChars($this->request_data_collector->int('maxchars') ?? 6);
324  }
325 
326  public function writeAnswerSpecificPostData(ilPropertyFormGUI $form): void
327  {
328  $this->object->setLowerLimit($this->request_data_collector->float('lowerlimit'));
329  $this->object->setUpperLimit($this->request_data_collector->float('upperlimit'));
330  $this->object->setPoints($this->request_data_collector->float('points'));
331  }
332 
334  {
335  // maxchars
336  $maxchars = new ilNumberInputGUI($this->lng->txt("maxchars"), "maxchars");
337  $maxchars->setInfo($this->lng->txt('qpl_maxchars_info_numeric_question'));
338  $maxchars->setSize(10);
339  $maxchars->setDecimals(0);
340  $maxchars->setMinValue(1);
341  $maxchars->setRequired(true);
342  if ($this->object->getMaxChars() > 0) {
343  $maxchars->setValue($this->object->getMaxChars());
344  }
345  $form->addItem($maxchars);
346  return $form;
347  }
348 
350  {
351  // points
352  $points = new ilNumberInputGUI($this->lng->txt("points"), "points");
353  $points->allowDecimals(true);
354  $points->setValue($this->object->getPoints() > 0 ? $this->object->getPoints() : '');
355  $points->setRequired(true);
356  $points->setSize(3);
357  $points->setMinValue(0.0);
358  $points->setMinvalueShouldBeGreater(true);
359  $form->addItem($points);
360 
361  $header = new ilFormSectionHeaderGUI();
362  $header->setTitle($this->lng->txt("range"));
363  $form->addItem($header);
364 
365  // lower bound
366  $lower_limit = new ilFormulaInputGUI($this->lng->txt("range_lower_limit"), "lowerlimit");
367  $lower_limit->setSize(25);
368  $lower_limit->setMaxLength(20);
369  $lower_limit->setRequired(true);
370  $lower_limit->setValue((string) $this->object->getLowerLimit());
371  $form->addItem($lower_limit);
372 
373  // upper bound
374  $upper_limit = new ilFormulaInputGUI($this->lng->txt("range_upper_limit"), "upperlimit");
375  $upper_limit->setSize(25);
376  $upper_limit->setMaxLength(20);
377  $upper_limit->setRequired(true);
378  $upper_limit->setValue((string) $this->object->getUpperLimit());
379  $form->addItem($upper_limit);
380 
381  // reset input length, if max chars are set
382  if ($this->object->getMaxChars() > 0) {
383  $lower_limit->setSize($this->object->getMaxChars());
384  $lower_limit->setMaxLength($this->object->getMaxChars());
385  $upper_limit->setSize($this->object->getMaxChars());
386  $upper_limit->setMaxLength($this->object->getMaxChars());
387  }
388  return $form;
389  }
390 
401  {
402  return [];
403  }
404 
415  {
416  return [];
417  }
418 
419  public function getAnswersFrequency($relevantAnswers, $questionIndex): array
420  {
421  $answers = [];
422 
423  foreach ($relevantAnswers as $ans) {
424  if (!isset($answers[$ans['value1']])) {
425  $answers[$ans['value1']] = [
426  'answer' => $ans['value1'], 'frequency' => 0
427  ];
428  }
429 
430  $answers[$ans['value1']]['frequency']++;
431  }
432 
433  return $answers;
434  }
435 
437  {
438  // points
439  $points = new ilNumberInputGUI($this->lng->txt("points"), "points");
440  $points->allowDecimals(true);
441  $points->setValue($this->object->getPoints() > 0 ? $this->object->getPoints() : '');
442  $points->setRequired(true);
443  $points->setSize(3);
444  $points->setMinValue(0.0);
445  $points->setMinvalueShouldBeGreater(true);
446  $form->addItem($points);
447 
448  $header = new ilFormSectionHeaderGUI();
449  $header->setTitle($this->lng->txt("range"));
450  $form->addItem($header);
451 
452  // lower bound
453  $lower_limit = new ilFormulaInputGUI($this->lng->txt("range_lower_limit"), "lowerlimit");
454  $lower_limit->setSize(25);
455  $lower_limit->setMaxLength(20);
456  $lower_limit->setRequired(true);
457  $lower_limit->setValue($this->object->getLowerLimit());
458  $form->addItem($lower_limit);
459 
460  // upper bound
461  $upper_limit = new ilFormulaInputGUI($this->lng->txt("range_upper_limit"), "upperlimit");
462  $upper_limit->setSize(25);
463  $upper_limit->setMaxLength(20);
464  $upper_limit->setRequired(true);
465  $upper_limit->setValue($this->object->getUpperLimit());
466  $form->addItem($upper_limit);
467 
468  // reset input length, if max chars are set
469  if ($this->object->getMaxChars() > 0) {
470  $lower_limit->setSize($this->object->getMaxChars());
471  $lower_limit->setMaxLength($this->object->getMaxChars());
472  $upper_limit->setSize($this->object->getMaxChars());
473  $upper_limit->setMaxLength($this->object->getMaxChars());
474  }
475  }
476 
481  {
482  $this->object->setPoints((float) str_replace(',', '.', $form->getInput('points')));
483  $this->object->setLowerLimit((float) str_replace(',', '.', $form->getInput('lowerlimit')));
484  $this->object->setUpperLimit((float) str_replace(',', '.', $form->getInput('upperlimit')));
485  }
486 }
This class represents a formula text property in a property form.
hasCorrectSolution($activeId, $passIndex)
generateCorrectnessIconsForCorrectness(int $correctness)
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 the request and applies them to the data object...
renderLatex($content)
Wrap content with latex in a LatexContent UI component and render it to be processed by MathJax in th...
saveCorrectionsFormProperties(ilPropertyFormGUI $form)
getAnswersFrequency($relevantAnswers, $questionIndex)
addBasicQuestionFormProperties(ilPropertyFormGUI $form)
getSpecificFeedbackOutput(array $userSolution)
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)
while($session_entry=$r->fetchRow(ilDBConstants::FETCHMODE_ASSOC)) return null
allowDecimals(bool $a_value)
writeAnswerSpecificPostData(ilPropertyFormGUI $form)
Extracts the answer specific values from the request and applies them to the data object...
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
getTestOutput(int $active_id, int $pass, bool $is_question_postponed=false, array|bool $user_post_solutions=false, bool $show_specific_inline_feedback=false)
This class represents a number property in a property form.
global $DIC
Definition: shib_login.php:26
populateQuestionSpecificFormPart(\ilPropertyFormGUI $form)
getAfterParticipationSuppressionQuestionPostVars()
Returns a list of postvars which will be suppressed in the form output when used in scoring adjustmen...
editQuestion(bool $checkonly=false, ?bool $is_save_cmd=null)
getSolutionOutput(int $active_id, ?int $pass=null, 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_inline_feedback=true)
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)
{}
getPreview(bool $show_question_only=false, bool $show_inline_feedback=false)
Class for numeric questions.
checkRange(float $lower, float $upper)
$id
plugin.php for ilComponentBuildPluginInfoObjectiveTest::testAddPlugins
Definition: plugin.php:23
__construct(Container $dic, ilPlugin $plugin)
__construct($id=-1)
assNumericGUI constructor
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
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)
renderEditForm(ilPropertyFormGUI $form)
getGenericFeedbackOutput(int $active_id, ?int $pass)