ILIAS  trunk Revision v12.0_alpha-377-g3641b37b9db
class.assErrorTextGUI.php
Go to the documentation of this file.
1<?php
2
34{
35 private const DEFAULT_POINTS_WRONG = -1;
36
38
39 public function __construct($id = -1)
40 {
41 global $DIC;
42 $this->tabs = $DIC->tabs();
43
45 $this->object = new assErrorText();
46 $this->setErrorMessage($this->lng->txt("msg_form_save_error"));
47 if ($id >= 0) {
48 $this->object->loadFromDb($id);
49 }
50 }
51
55 protected function writePostData(bool $always = false): int
56 {
57 $hasErrors = (!$always) ? $this->editQuestion(true) : false;
58 if (!$hasErrors) {
63 return 0;
64 }
65 return 1;
66 }
67
69 {
70 $data = $this->restructurePostDataForSaving($this->request_data_collector->raw('errordata') ?? []);
71 $this->object->setErrorData($data);
72 $this->object->removeErrorDataWithoutPosition();
73 }
74
75 private function restructurePostDataForSaving(array $post): array
76 {
77 $keys = $post['key'] ?? [];
78 $restructured_array = [];
79 foreach ($keys as $key => $text_wrong) {
80 $restructured_array[] = new assAnswerErrorText(
81 $text_wrong,
82 $post['value'][$key],
83 (float) str_replace(',', '.', $post['points'][$key])
84 );
85 }
86 return $restructured_array;
87 }
88
90 {
91 $this->object->setQuestion(
92 $this->request_data_collector->string('question')
93 );
94
95 $this->object->setErrorText(
96 $this->request_data_collector->raw('errortext')
97 );
98
99 $this->object->parseErrorText();
100
101 $this->object->setPointsWrong(
102 $this->request_data_collector->float('points_wrong') ?? self::DEFAULT_POINTS_WRONG
103 );
104
105 if (!$this->object->getSelfAssessmentEditingMode()) {
106 $this->object->setTextSize(
107 $this->request_data_collector->float('textsize')
108 );
109 }
110 }
111
112 public function editQuestion(
113 bool $checkonly = false,
114 ?bool $is_save_cmd = null
115 ): bool {
116 $save = $is_save_cmd ?? $this->isSaveCommand();
117
118 $form = new ilPropertyFormGUI();
119 $this->editForm = $form;
120
121 $form->setFormAction($this->ctrl->getFormAction($this));
122 $form->setTitle($this->outQuestionType());
123 $form->setMultipart(false);
124 $form->setTableWidth("100%");
125 $form->setId("orderinghorizontal");
126
127 $this->addBasicQuestionFormProperties($form);
128
130
131 if (count($this->object->getErrorData()) || $checkonly) {
132 $this->populateAnswerSpecificFormPart($form);
133 }
134
135 $this->populateTaxonomyFormSection($form);
136
137 $form->addCommandButton("analyze", $this->lng->txt('analyze_errortext'));
138 $this->addQuestionFormCommandButtons($form);
139
140 $errors = false;
141
142 if ($save) {
143 $form->setValuesByPost();
144 $errors = !$form->checkInput();
145 $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
146 if ($errors) {
147 $checkonly = false;
148 }
149 }
150
151 if (!$checkonly) {
152 $this->renderEditForm($form);
153 }
154 return $errors;
155 }
156
162 {
163 $header = new ilFormSectionHeaderGUI();
164 $header->setTitle($this->lng->txt("errors_section"));
165 $form->addItem($header);
166
167 $errordata = new ilErrorTextWizardInputGUI($this->lng->txt("errors"), "errordata");
168 $errordata->setKeyName($this->lng->txt('text_wrong'));
169 $errordata->setValueName($this->lng->txt('text_correct'));
170 $errordata->setValues($this->object->getErrorData());
171 $form->addItem($errordata);
172
173 // points for wrong selection
174 $points_wrong = new ilNumberInputGUI($this->lng->txt("points_wrong"), "points_wrong");
175 $points_wrong->allowDecimals(true);
176 $points_wrong->setMaxValue(0);
177 $points_wrong->setMaxvalueShouldBeLess(true);
178 $points_wrong->setValue($this->object->getPointsWrong());
179 $points_wrong->setInfo($this->lng->txt("points_wrong_info"));
180 $points_wrong->setSize(6);
181 $points_wrong->setRequired(true);
182 $form->addItem($points_wrong);
183 return $form;
184 }
185
191 {
192 // errortext
193 $errortext = new ilTextAreaInputGUI($this->lng->txt("errortext"), "errortext");
194 $errortext->setValue($this->object->getErrorText());
195 $errortext->setRequired(true);
196 $errortext->setInfo($this->lng->txt("errortext_info"));
197 $errortext->setRows(10);
198 $errortext->setCols(80);
199 $form->addItem($errortext);
200
201 if (!$this->object->getSelfAssessmentEditingMode()) {
202 // textsize
203 $textsize = new ilNumberInputGUI($this->lng->txt("textsize"), "textsize");
204 $textsize->setValue($this->object->getTextSize() ?? 100.0);
205 $textsize->setInfo($this->lng->txt("textsize_errortext_info"));
206 $textsize->setSize(6);
207 $textsize->setSuffix("%");
208 $textsize->setMinValue(10);
209 $textsize->setRequired(true);
210 $form->addItem($textsize);
211 }
212 return $form;
213 }
214
218 public function analyze(): void
219 {
220 $this->setAdditionalContentEditingModeFromPost();
221 $this->writePostData(true);
222 $this->saveTaxonomyAssignments();
223 $this->object->setErrorsFromParsedErrorText();
224 $this->tabs->activateTab('edit_question');
225 $this->editQuestion();
226 }
227
228 public function getSolutionOutput(
229 int $active_id,
230 ?int $pass = null,
231 bool $graphical_output = false,
232 bool $result_output = false,
233 bool $show_question_only = true,
234 bool $show_feedback = false,
235 bool $show_correct_solution = false,
236 bool $show_manual_scoring = false,
237 bool $show_question_text = true,
238 bool $show_inline_feedback = true
239 ): string {
240 $user_solutions = $this->getUsersSolutionFromPreviewOrDatabase($active_id, $pass, true);
241 return $this->renderSolutionOutput(
242 $user_solutions,
243 $active_id,
244 $pass,
245 $graphical_output,
246 $result_output,
247 $show_question_only,
248 $show_feedback,
249 $show_correct_solution,
250 $show_manual_scoring,
251 $show_question_text,
252 false,
253 $show_inline_feedback,
254 );
255 }
256
257 public function renderSolutionOutput(
258 mixed $user_solutions,
259 int $active_id,
260 ?int $pass,
261 bool $graphical_output = false,
262 bool $result_output = false,
263 bool $show_question_only = true,
264 bool $show_feedback = false,
265 bool $show_correct_solution = false,
266 bool $show_manual_scoring = false,
267 bool $show_question_text = true,
268 bool $show_autosave_title = false,
269 bool $show_inline_feedback = false,
270 ): ?string {
271 $template = new ilTemplate("tpl.il_as_qpl_errortext_output_solution.html", true, true, "components/ILIAS/TestQuestionPool");
272
273 $selections = [
274 'user' => $user_solutions ?
275 $user_solutions :
276 $this->getUsersSolutionFromPreviewOrDatabase($active_id, $pass, true)
277 ];
278 $selections['best'] = $this->object->getBestSelection();
279
280 $reached_points = $this->object->getPoints();
281 if ($active_id > 0 && !$show_correct_solution) {
282 $reached_points = $this->object->getReachedPoints($active_id, $pass);
283 }
284
285 if ($result_output === true) {
286 $resulttext = ($reached_points == 1) ? "(%s " . $this->lng->txt("point") . ")" : "(%s " . $this->lng->txt("points") . ")";
287 $template->setVariable("RESULT_OUTPUT", sprintf($resulttext, $reached_points));
288 }
289
290 if ($this->object->getTextSize() >= 10) {
291 $template->setVariable("STYLE", " style=\"font-size: " . $this->object->getTextSize() . "%;\"");
292 }
293
294 if ($show_question_text === true) {
295 $template->setVariable("QUESTIONTEXT", $this->renderLatex($this->object->getQuestionForHTMLOutput()));
296 }
297
298 $correctness_icons = [
299 'correct' => $this->generateCorrectnessIconsForCorrectness(self::CORRECTNESS_OK),
300 'not_correct' => $this->generateCorrectnessIconsForCorrectness(self::CORRECTNESS_NOT_OK)
301 ];
302 $errortext = $this->object->assembleErrorTextOutput($selections, $graphical_output, $show_correct_solution, false, $correctness_icons);
303
304 $template->setVariable("ERRORTEXT", $errortext);
305 $questionoutput = $template->get();
306
307 $solutiontemplate = new ilTemplate("tpl.il_as_tst_solution_output.html", true, true, "components/ILIAS/TestQuestionPool");
308
309 $feedback = '';
310 if ($show_feedback) {
311 if (!$this->isTestPresentationContext()) {
312 $fb = $this->getGenericFeedbackOutput($active_id, $pass);
313 $feedback .= mb_strlen($fb) ? $fb : '';
314 }
315
316 $fb = $this->getSpecificFeedbackOutput([]);
317 $feedback .= mb_strlen($fb) ? $fb : '';
318 }
319 if (mb_strlen($feedback)) {
320 $cssClass = (
321 $this->hasCorrectSolution($active_id, $pass) ?
323 );
324
325 $solutiontemplate->setVariable("ILC_FB_CSS_CLASS", $cssClass);
326 $solutiontemplate->setVariable("FEEDBACK", ilLegacyFormElementsUtil::prepareTextareaOutput($feedback, true));
327 }
328
329 $solutiontemplate->setVariable("SOLUTION_OUTPUT", $questionoutput);
330
331 $solutionoutput = $solutiontemplate->get();
332 if (!$show_question_only) {
333 // get page object output
334 $solutionoutput = $this->getILIASPage($solutionoutput);
335 }
336 return $solutionoutput;
337 }
338
339 public function getPreview(
340 bool $show_question_only = false,
341 bool $show_inline_feedback = false
342 ): string {
343 $selections = [
344 'user' => $this->getUsersSolutionFromPreviewOrDatabase()
345 ];
346
347 return $this->generateQuestionOutput($selections, $show_question_only);
348 }
349
350 public function getTestOutput(
351 int $active_id,
352 int $pass,
353 bool $is_question_postponed = false,
354 array|bool $user_post_solutions = false,
355 bool $show_specific_inline_feedback = false
356 ): string {
357 $selections = [
358 'user' => $this->getUsersSolutionFromPreviewOrDatabase($active_id, $pass, false)
359 ];
360
361 return $this->outQuestionPage(
362 '',
363 $is_question_postponed,
364 $active_id,
365 $this->generateQuestionOutput($selections, true)
366 );
367 }
368
369 private function generateQuestionOutput($selections, $show_question_only): string
370 {
371 $template = new ilTemplate("tpl.il_as_qpl_errortext_output.html", true, true, "components/ILIAS/TestQuestionPool");
372
373 if ($this->object->getTextSize() >= 10) {
374 $template->setVariable("STYLE", " style=\"font-size: " . $this->object->getTextSize() . "%;\"");
375 }
376 $template->setVariable("QUESTIONTEXT", $this->renderLatex($this->object->getQuestionForHTMLOutput()));
377 $errortext = $this->object->assembleErrorTextOutput($selections);
378 if ($this->getTargetGuiClass() !== null) {
379 $this->ctrl->setParameterByClass($this->getTargetGuiClass(), 'errorvalue', '');
380 }
381 $template->setVariable("ERRORTEXT", $errortext);
382 $template->setVariable("ERRORTEXT_ID", "qst_" . $this->object->getId());
383 $template->setVariable("ERRORTEXT_VALUE", join(',', $selections['user']));
384
385 $this->tpl->addOnLoadCode('il.test.player.errortext.init()');
386 $this->tpl->addJavascript('assets/js/errortext.js');
387 $questionoutput = $template->get();
388
389 if ($show_question_only) {
390 return $questionoutput;
391 }
392
393 return $this->getILIASPage($questionoutput);
394 }
395
397 int $active_id = 0,
398 ?int $pass = null,
399 bool $only_authorized = false
400 ): array {
401 if (is_object($this->getPreviewSession())) {
402 return (array) $this->getPreviewSession()->getParticipantsSolution();
403 }
404
405 if ($active_id > 0) {
406 $selections = [];
407 $solutions = $only_authorized
408 ? $this->object->getSolutionValues($active_id, $pass ?? 0, true)
409 : $this->object->getUserSolutionPreferingIntermediate($active_id, $pass);
410 foreach ($solutions as $solution) {
411 $selections[] = $solution['value1'];
412 }
413 return $selections;
414 }
415
416 return [];
417 }
418
419 public function getSpecificFeedbackOutput(array $user_solution): string
420 {
421 if (!$this->object->feedbackOBJ->specificAnswerFeedbackExists()) {
422 return '';
423 }
424
425 $feedback = '<table class="test_specific_feedback"><tbody>';
426 $elements = $this->object->getErrorData();
427 foreach ($elements as $index => $element) {
428 $feedback .= '<tr>';
429 $feedback .= '<td class="text-nowrap">' . $index . '. ' . $element->getTextWrong() . ':</td>';
430 $feedback .= '<td>' . $this->object->feedbackOBJ->getSpecificAnswerFeedbackTestPresentation(
431 $this->object->getId(),
432 0,
433 $index
434 ) . '</td>';
435
436 $feedback .= '</tr>';
437 }
438 $feedback .= '</tbody></table>';
439
440 return $this->renderLatex(ilLegacyFormElementsUtil::prepareTextareaOutput($feedback, true));
441 }
442
453 {
454 return [];
455 }
456
467 {
468 return [];
469 }
470
477 public function getAggregatedAnswersView(array $relevant_answers): string
478 {
479 $errortext = $this->object->getErrorText();
480
481 $passdata = []; // Regroup answers into units of passes.
482 foreach ($relevant_answers as $answer_chosen) {
483 $passdata[$answer_chosen['active_fi'] . '-' . $answer_chosen['pass']][$answer_chosen['value2']][] = $answer_chosen['value1'];
484 }
485
486 $html = '';
487 foreach ($passdata as $key => $pass) {
488 $passdata[$key] = $this->object->createErrorTextOutput($pass);
489 $html .= $passdata[$key] . '<hr /><br />';
490 }
491
492 return $html;
493 }
494
495 public function getAnswersFrequency($relevant_answers, $question_index): array
496 {
497 $answers_by_active_and_pass = [];
498
499 foreach ($relevant_answers as $row) {
500 $key = $row['active_fi'] . ':' . $row['pass'];
501
502 if (!isset($answers_by_active_and_pass[$key])) {
503 $answers_by_active_and_pass[$key] = ['user' => []];
504 }
505
506 $answers_by_active_and_pass[$key]['user'][] = $row['value1'];
507 }
508
509 $answers = [];
510
511 foreach ($answers_by_active_and_pass as $answer) {
512 $error_text = '<div class="errortext">' . $this->object->assembleErrorTextOutput($answer) . '</div>';
513 $error_text_hashed = md5($error_text);
514
515 if (!isset($answers[$error_text_hashed])) {
516 $answers[$error_text_hashed] = [
517 'answer' => $error_text, 'frequency' => 0
518 ];
519 }
520
521 $answers[$error_text_hashed]['frequency']++;
522 }
523
524 return array_values($answers);
525 }
526
528 {
529 $errordata = new ilAssErrorTextCorrectionsInputGUI($this->lng->txt('errors'), 'errordata');
530 $errordata->setKeyName($this->lng->txt('text_wrong'));
531 $errordata->setValueName($this->lng->txt('text_correct'));
532 $errordata->setValues($this->object->getErrorData());
533 $form->addItem($errordata);
534
535 // points for wrong selection
536 $points_wrong = new ilNumberInputGUI($this->lng->txt('points_wrong'), 'points_wrong');
537 $points_wrong->allowDecimals(true);
538 $points_wrong->setMaxValue(0);
539 $points_wrong->setMaxvalueShouldBeLess(true);
540 $points_wrong->setValue($this->object->getPointsWrong());
541 $points_wrong->setInfo($this->lng->txt('points_wrong_info'));
542 $points_wrong->setSize(6);
543 $points_wrong->setRequired(true);
544 $form->addItem($points_wrong);
545 }
546
551 {
552 $existing_errordata = $this->object->getErrorData();
553 $this->object->flushErrorData();
554 $new_errordata = $this->request_data_collector->raw('errordata');
555 $errordata = [];
556 foreach ($new_errordata['points'] as $index => $points) {
557 $errordata[$index] = $existing_errordata[$index]->withPoints(
558 (float) str_replace(',', '.', $points)
559 );
560 }
561 $this->object->setErrorData($errordata);
562 $this->object->setPointsWrong((float) str_replace(',', '.', $form->getInput('points_wrong')));
563 }
564}
$id
plugin.php for ilComponentBuildPluginInfoObjectiveTest::testAddPlugins
Definition: plugin.php:23
return true
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,)
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)
getAggregatedAnswersView(array $relevant_answers)
Returns an html string containing a question specific representation of the answers so far given in t...
saveCorrectionsFormProperties(ilPropertyFormGUI $form)
getAnswersFrequency($relevant_answers, $question_index)
populateCorrectionsFormProperties(ilPropertyFormGUI $form)
getUsersSolutionFromPreviewOrDatabase(int $active_id=0, ?int $pass=null, bool $only_authorized=false)
getPreview(bool $show_question_only=false, bool $show_inline_feedback=false)
getAfterParticipationSuppressionQuestionPostVars()
Returns a list of postvars which will be suppressed in the form output when used in scoring adjustmen...
populateQuestionSpecificFormPart(ilPropertyFormGUI $form)
writeQuestionSpecificPostData(ilPropertyFormGUI $form)
Extracts the question specific values from the request and applies them to the data object.
writeAnswerSpecificPostData(ilPropertyFormGUI $form)
Extracts the answer specific values from the request and applies them to the data object.
getAfterParticipationSuppressionAnswerPostVars()
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)
populateAnswerSpecificFormPart(ilPropertyFormGUI $form)
getSpecificFeedbackOutput(array $user_solution)
Returns the answer specific feedback for the question.
generateQuestionOutput($selections, $show_question_only)
writePostData(bool $always=false)
{Evaluates a posted edit form and writes the form data in the question object.integer A positive valu...
restructurePostDataForSaving(array $post)
analyze()
Parse the error text.
getTestOutput(int $active_id, int $pass, bool $is_question_postponed=false, array|bool $user_post_solutions=false, bool $show_specific_inline_feedback=false)
Class for error text questions.
populateTaxonomyFormSection(ilPropertyFormGUI $form)
addBasicQuestionFormProperties(ilPropertyFormGUI $form)
renderEditForm(ilPropertyFormGUI $form)
addQuestionFormCommandButtons(ilPropertyFormGUI $form)
setErrorMessage(string $errormessage)
This class represents a key value pair wizard property in a property form.
This class represents a section header in a property form.
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,...
This class represents a number property in a property form.
This class represents a property form user interface.
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-...
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
special template class to simplify handling of ITX/PEAR
This class represents a text area property in a property form.
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
$post
Definition: ltitoken.php:46
__construct(Container $dic, ilPlugin $plugin)
@inheritDoc
if(!file_exists('../ilias.ini.php'))
global $DIC
Definition: shib_login.php:26