ILIAS  release_8 Revision v8.24
class.assTextSubsetGUI.php
Go to the documentation of this file.
1<?php
2
19require_once './Modules/Test/classes/inc.AssessmentConstants.php';
20
37{
39
47 public function __construct($id = -1)
48 {
50 $this->object = new assTextSubset();
51 if ($id >= 0) {
52 $this->object->loadFromDb($id);
53 }
54 }
55
59 protected function writePostData(bool $always = false): int
60 {
61 /*
62 * sk 26.09.22: This is horrific but I don't see a better way right now,
63 * without needing to check most questions for side-effects.
64 */
65 $this->answers_from_post = $_POST['answers']['answer'];
66 $hasErrors = (!$always) ? $this->editQuestion(true) : false;
67 if (!$hasErrors) {
72 return 0;
73 }
74 return 1;
75 }
76
80 public function editQuestion($checkonly = false): bool
81 {
82 $save = $this->isSaveCommand();
83 $this->getQuestionTemplate();
84
85 $form = new ilPropertyFormGUI();
86 $this->editForm = $form;
87
88 $form->setFormAction($this->ctrl->getFormAction($this));
89 $form->setTitle($this->outQuestionType());
90 $form->setMultipart(false);
91 $form->setTableWidth("100%");
92 $form->setId("asstextsubset");
93
97 $this->populateTaxonomyFormSection($form);
99
100 $errors = false;
101 if ($save) {
102 $form->setValuesByPost();
103 $points = $form->getItemByPostVar('points');
104 $points->setValue($this->object->getMaximumPoints());
105 $errors = !$form->checkInput();
106 $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
107 if ($errors) {
108 $checkonly = false;
109 }
110 }
111
112 if (!$checkonly) {
113 $this->tpl->setVariable("QUESTION_DATA", $form->getHTML());
114 }
115 return $errors;
116 }
117
121 public function addanswers(): void
122 {
123 $this->writePostData(true);
124 $position = key($_POST['cmd']['addanswers']);
125 $this->object->addAnswer("", 0, $position + 1);
126 $this->editQuestion();
127 }
128
132 public function removeanswers(): void
133 {
134 $this->writePostData(true);
135 $position = key($_POST['cmd']['removeanswers']);
136 $this->object->deleteAnswer($position);
137 $this->editQuestion();
138 }
139
152 public function getSolutionOutput(
153 $active_id,
154 $pass = null,
155 $graphicalOutput = false,
156 $result_output = false,
157 $show_question_only = true,
158 $show_feedback = false,
159 $show_correct_solution = false,
160 $show_manual_scoring = false,
161 $show_question_text = true
162 ): string {
163 // get the solution of the user for the active pass or from the last pass if allowed
164 $solutions = array();
165 if (($active_id > 0) && (!$show_correct_solution)) {
166 $solutions = $this->object->getSolutionValues($active_id, $pass);
167 } else {
168 $rank = array();
169 foreach ($this->object->answers as $answer) {
170 $points_string_for_key = (string) $answer->getPoints();
171 if ($answer->getPoints() > 0) {
172 if (!array_key_exists($points_string_for_key, $rank)) {
173 $rank[$points_string_for_key] = array();
174 }
175 array_push($rank[$points_string_for_key], $answer->getAnswertext());
176 }
177 }
178 krsort($rank, SORT_NUMERIC);
179 foreach ($rank as $index => $bestsolutions) {
180 array_push($solutions, array("value1" => join(",", $bestsolutions), "points" => $index));
181 }
182 }
183
184 $template = new ilTemplate("tpl.il_as_qpl_textsubset_output_solution.html", true, true, "Modules/TestQuestionPool");
185 $solutiontemplate = new ilTemplate("tpl.il_as_tst_solution_output.html", true, true, "Modules/TestQuestionPool");
186 $available_answers = &$this->object->getAvailableAnswers();
187 for ($i = 0; $i < $this->object->getCorrectAnswers(); $i++) {
188 if (!array_key_exists($i, $solutions) || (strcmp($solutions[$i]["value1"], "") == 0)) {
189 } else {
190 if (($active_id > 0) && (!$show_correct_solution)) {
191 if ($graphicalOutput) {
192 // output of ok/not ok icons for user entered solutions
193 $index = $this->object->isAnswerCorrect($available_answers, $solutions[$i]["value1"]);
194 $correct = false;
195 if ($index !== false) {
196 unset($available_answers[$index]);
197 $correct = true;
198 }
199
200 $correctness_icon = $this->generateCorrectnessIconsForCorrectness(self::CORRECTNESS_NOT_OK);
201 if ($correct) {
202 $correctness_icon = $this->generateCorrectnessIconsForCorrectness(self::CORRECTNESS_OK);
203 }
204 $template->setCurrentBlock("icon_ok");
205 $template->setVariable("ICON_OK", $correctness_icon);
206 $template->parseCurrentBlock();
207 }
208 }
209 $template->setCurrentBlock("textsubset_row");
210 $template->setVariable("SOLUTION", $this->escapeTemplatePlaceholders($solutions[$i]["value1"]));
211 $template->setVariable("COUNTER", $i + 1);
212 if ($result_output) {
213 $points = $solutions[$i]["points"];
214 $resulttext = ($points == 1) ? "(%s " . $this->lng->txt("point") . ")" : "(%s " . $this->lng->txt("points") . ")";
215 $template->setVariable("RESULT_OUTPUT", sprintf($resulttext, $points));
216 }
217 $template->parseCurrentBlock();
218 }
219 }
220 if ($show_question_text == true) {
221 $template->setVariable("QUESTIONTEXT", $this->object->getQuestionForHTMLOutput());
222 }
223 $questionoutput = $template->get();
224 $feedback = ($show_feedback && !$this->isTestPresentationContext()) ? $this->getGenericFeedbackOutput((int) $active_id, $pass) : "";
225 if (strlen($feedback)) {
226 $cssClass = (
227 $this->hasCorrectSolution($active_id, $pass) ?
229 );
230
231 $solutiontemplate->setVariable("ILC_FB_CSS_CLASS", $cssClass);
232 $solutiontemplate->setVariable("FEEDBACK", $this->object->prepareTextareaOutput($feedback, true));
233 }
234 $solutiontemplate->setVariable("SOLUTION_OUTPUT", $questionoutput);
235
236 $solutionoutput = $solutiontemplate->get();
237 if (!$show_question_only) {
238 // get page object output
239 $solutionoutput = $this->getILIASPage($solutionoutput);
240 }
241 return $solutionoutput;
242 }
243
244 public function getPreview($show_question_only = false, $showInlineFeedback = false): string
245 {
246 $solutions = is_object($this->getPreviewSession()) ? (array) $this->getPreviewSession()->getParticipantsSolution() : array();
247 $template = new ilTemplate("tpl.il_as_qpl_textsubset_output.html", true, true, "Modules/TestQuestionPool");
248 $width = $this->object->getMaxTextboxWidth();
249 for ($i = 0; $i < $this->object->getCorrectAnswers(); $i++) {
250 $template->setCurrentBlock("textsubset_row");
251 foreach ($solutions as $idx => $solution_value) {
252 if ($idx == $i) {
253 $template->setVariable("TEXTFIELD_VALUE", " value=\""
254 . $this->escapeTemplatePlaceholders($solution_value)
255 . "\"");
256 }
257 }
258 $template->setVariable("COUNTER", $i + 1);
259 $template->setVariable("TEXTFIELD_ID", $i);
260 $template->setVariable("TEXTFIELD_SIZE", $width);
261 $template->parseCurrentBlock();
262 }
263 $template->setVariable("QUESTIONTEXT", $this->object->getQuestionForHTMLOutput());
264 $questionoutput = $template->get();
265 if (!$show_question_only) {
266 // get page object output
267 $questionoutput = $this->getILIASPage($questionoutput);
268 }
269 return $questionoutput;
270 }
271
272 public function getTestOutput($active_id, $pass = null, $is_postponed = false, $use_post_solutions = false, $inlineFeedback = false): string
273 {
274 // get the solution of the user for the active pass or from the last pass if allowed
275 $user_solution = "";
276 if ($active_id) {
277 $solutions = $this->object->getUserSolutionPreferingIntermediate($active_id, $pass);
278 }
279
280 $template = new ilTemplate("tpl.il_as_qpl_textsubset_output.html", true, true, "Modules/TestQuestionPool");
281 $width = $this->object->getMaxTextboxWidth();
282 for ($i = 0; $i < $this->object->getCorrectAnswers(); $i++) {
283 $template->setCurrentBlock("textsubset_row");
284 foreach ($solutions as $idx => $solution_value) {
285 if ($idx == $i) {
286 $template->setVariable("TEXTFIELD_VALUE", " value=\""
287 . $this->escapeTemplatePlaceholders($solution_value["value1"])
288 . "\"");
289 }
290 }
291 $template->setVariable("COUNTER", $i + 1);
292 $template->setVariable("TEXTFIELD_ID", $i);
293 $template->setVariable("TEXTFIELD_SIZE", $width);
294 $template->parseCurrentBlock();
295 }
296 $template->setVariable("QUESTIONTEXT", $this->object->getQuestionForHTMLOutput());
297 $questionoutput = $template->get();
298 $pageoutput = $this->outQuestionPage("", $is_postponed, $active_id, $questionoutput);
299 return $pageoutput;
300 }
301
302 public function getSpecificFeedbackOutput(array $userSolution): string
303 {
304 $output = "";
305 return $this->object->prepareTextareaOutput($output, true);
306 }
307
309 {
310 $this->object->setCorrectAnswers($_POST["correctanswers"]);
311 $this->object->setTextRating($_POST["text_rating"]);
312 }
313
315 {
316 // Delete all existing answers and create new answers from the form data
317 $this->object->flushAnswers();
318 foreach ($this->answers_from_post as $index => $answertext) {
319 $answertext = assQuestion::extendedTrim($answertext);
320 $this->object->addAnswer(htmlentities($answertext), $_POST['answers']['points'][$index], $index);
321 }
322 }
323
325 {
326 // number of requested answers
327 $correctanswers = new ilNumberInputGUI($this->lng->txt("nr_of_correct_answers"), "correctanswers");
328 $correctanswers->setMinValue(1);
329 $correctanswers->setDecimals(0);
330 $correctanswers->setSize(3);
331 $correctanswers->setValue($this->object->getCorrectAnswers());
332 $correctanswers->setRequired(true);
333 $form->addItem($correctanswers);
334
335 // maximum available points
336 $points = new ilNumberInputGUI($this->lng->txt("maximum_points"), "points");
337 $points->setMinValue(0.0);
338 $points->setMinvalueShouldBeGreater(true);
339 $points->setSize(6);
340 $points->setDisabled(true);
341 $points->allowDecimals(true);
342 $points->setValue($this->object->getMaximumPoints());
343 $points->setRequired(false);
344 $form->addItem($points);
345
346 // text rating
347 $textrating = new ilSelectInputGUI($this->lng->txt("text_rating"), "text_rating");
348 $text_options = array(
349 "ci" => $this->lng->txt("cloze_textgap_case_insensitive"),
350 "cs" => $this->lng->txt("cloze_textgap_case_sensitive")
351 );
352 if (!$this->object->getSelfAssessmentEditingMode()) {
353 $text_options["l1"] = sprintf($this->lng->txt("cloze_textgap_levenshtein_of"), "1");
354 $text_options["l2"] = sprintf($this->lng->txt("cloze_textgap_levenshtein_of"), "2");
355 $text_options["l3"] = sprintf($this->lng->txt("cloze_textgap_levenshtein_of"), "3");
356 $text_options["l4"] = sprintf($this->lng->txt("cloze_textgap_levenshtein_of"), "4");
357 $text_options["l5"] = sprintf($this->lng->txt("cloze_textgap_levenshtein_of"), "5");
358 }
359 $textrating->setOptions($text_options);
360 $textrating->setValue($this->object->getTextRating());
361 $form->addItem($textrating);
362 return $form;
363 }
364
366 {
367 $choices = new ilAnswerWizardInputGUI($this->lng->txt("answers"), "answers");
368 $choices->setRequired(true);
369 $choices->setQuestionObject($this->object);
370 $choices->setSingleline(true);
371 $choices->setAllowMove(false);
372 $choices->setMinValue(0.0);
373 if ($this->object->getAnswerCount() == 0) {
374 $this->object->addAnswer("", 0, 0);
375 }
376 $choices->setValues(array_map(
377 function (ASS_AnswerBinaryStateImage $value) {
378 $value->setAnswerText(html_entity_decode($value->getAnswerText()));
379 return $value;
380 },
381 $this->object->getAnswers()
382 ));
383 $form->addItem($choices);
384 return $form;
385 }
386
387
398 {
399 return array();
400 }
401
412 {
413 return array();
414 }
415
422 public function getAggregatedAnswersView(array $relevant_answers): string
423 {
424 return $this->renderAggregateView(
425 $this->aggregateAnswers($relevant_answers)
426 )->get();
427 }
428
429 public function aggregateAnswers($relevant_answers_chosen): array
430 {
431 $aggregate = array();
432
433 foreach ($relevant_answers_chosen as $relevant_answer) {
434 if (array_key_exists($relevant_answer['value1'], $aggregate)) {
435 $aggregate[$relevant_answer['value1']]++;
436 } else {
437 $aggregate[$relevant_answer['value1']] = 1;
438 }
439 }
440 return $aggregate;
441 }
442
448 public function renderAggregateView($aggregate): ilTemplate
449 {
450 $tpl = new ilTemplate('tpl.il_as_aggregated_answers_table.html', true, true, "Modules/TestQuestionPool");
451
452 foreach ($aggregate as $key => $value) {
453 $tpl->setCurrentBlock('aggregaterow');
454 $tpl->setVariable('OPTION', $key);
455 $tpl->setVariable('COUNT', $value);
456 $tpl->parseCurrentBlock();
457 }
458 return $tpl;
459 }
460
461 public function getAnswersFrequency($relevantAnswers, $questionIndex): array
462 {
463 $answers = array();
464
465 foreach ($relevantAnswers as $ans) {
466 if (!isset($answers[$ans['value1']])) {
467 $answers[$ans['value1']] = array(
468 'answer' => $ans['value1'], 'frequency' => 0
469 );
470 }
471
472 $answers[$ans['value1']]['frequency']++;
473 }
474 $answers = $this->completeAddAnswerAction($answers, $questionIndex);
475 return $answers;
476 }
477
478 protected function completeAddAnswerAction($answers, $questionIndex)
479 {
480 foreach ($answers as $key => $ans) {
481 $found = false;
482
483 foreach ($this->object->getAnswers() as $item) {
484 if ($ans['answer'] !== $item->getAnswerText()) {
485 continue;
486 }
487
488 $found = true;
489 break;
490 }
491
492 if (!$found) {
493 $answers[$key]['addable'] = true;
494 }
495 }
496
497 return $answers;
498 }
499
501 {
502 $choices = new ilAssAnswerCorrectionsInputGUI($this->lng->txt("answers"), "answers");
503 $choices->setRequired(true);
504 $choices->setQuestionObject($this->object);
505 $choices->setValues($this->object->getAnswers());
506 $form->addItem($choices);
507 }
508
513 {
514 $input = $form->getItemByPostVar('answers');
515 $values = $input->getValues();
516
517 foreach ($this->object->getAnswers() as $index => $answer) {
518 $points = (float) str_replace(',', '.', $values[$index]->getPoints());
519 $answer->setPoints($points);
520 }
521 }
522}
$id
plugin.php for ilComponentBuildPluginInfoObjectiveTest::testAddPlugins
Definition: plugin.php:23
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...
populateTaxonomyFormSection(ilPropertyFormGUI $form)
escapeTemplatePlaceholders(string $text)
getILIASPage(string $html="")
Returns the ILIAS Page around a question.
addBasicQuestionFormProperties(ilPropertyFormGUI $form)
getGenericFeedbackOutput(int $active_id, ?int $pass)
addQuestionFormCommandButtons(ilPropertyFormGUI $form)
hasCorrectSolution($activeId, $passIndex)
generateCorrectnessIconsForCorrectness(int $correctness)
static extendedTrim(string $value)
Trim non-printable characters from the beginning and end of a string.
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
writePostData(bool $always=false)
{Evaluates a posted edit form and writes the form data in the question object.integer A positive valu...
saveCorrectionsFormProperties(ilPropertyFormGUI $form)
getTestOutput($active_id, $pass=null, $is_postponed=false, $use_post_solutions=false, $inlineFeedback=false)
populateAnswerSpecificFormPart(\ilPropertyFormGUI $form)
populateCorrectionsFormProperties(ilPropertyFormGUI $form)
__construct($id=-1)
assTextSubsetGUI constructor
editQuestion($checkonly=false)
Creates an output of the edit form for the question.
completeAddAnswerAction($answers, $questionIndex)
addanswers()
Add a new answer.
getAggregatedAnswersView(array $relevant_answers)
Returns an html string containing a question specific representation of the answers so far given in t...
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.
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...
writeAnswerSpecificPostData(ilPropertyFormGUI $form)
Extracts the answer specific values from $_POST and applies them to the data object.
aggregateAnswers($relevant_answers_chosen)
populateQuestionSpecificFormPart(\ilPropertyFormGUI $form)
writeQuestionSpecificPostData(ilPropertyFormGUI $form)
Extracts the question specific values from $_POST and applies them to the data object.
removeanswers()
Remove an answer.
getSpecificFeedbackOutput(array $userSolution)
Returns the answer specific feedback for the question.
getAnswersFrequency($relevantAnswers, $questionIndex)
getAfterParticipationSuppressionQuestionPostVars()
Returns a list of postvars which will be suppressed in the form output when used in scoring adjustmen...
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...
This class represents a number property in a property form.
This class represents a property form user interface.
getItemByPostVar(string $a_post_var)
This class represents a selection list property in a property form.
special template class to simplify handling of ITX/PEAR
$errors
Definition: imgupload.php:65
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...
if($DIC->http() ->request() ->getMethod()=="GET" &&isset($DIC->http() ->request() ->getQueryParams()['tex'])) $tpl
Definition: latex.php:41
$index
Definition: metadata.php:145
$i
Definition: metadata.php:41
__construct(Container $dic, ilPlugin $plugin)
@inheritDoc
string $key
Consumer key/client ID value.
Definition: System.php:193