ILIAS  release_8 Revision v8.19
All Data Structures Namespaces Files Functions Variables Modules Pages
class.assTextSubsetGUI.php
Go to the documentation of this file.
1 <?php
2 
19 require_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) {
71  $this->saveTaxonomyAssignments();
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 
94  $this->addBasicQuestionFormProperties($form);
96  $this->populateAnswerSpecificFormPart($form);
97  $this->populateTaxonomyFormSection($form);
98  $this->addQuestionFormCommandButtons($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 
314  public function writeAnswerSpecificPostData(ilPropertyFormGUI $form): void
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);
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 }
populateCorrectionsFormProperties(ilPropertyFormGUI $form)
hasCorrectSolution($activeId, $passIndex)
editQuestion($checkonly=false)
Creates an output of the edit form for the question.
generateCorrectnessIconsForCorrectness(int $correctness)
setCurrentBlock(string $blockname=self::DEFAULT_BLOCK)
Sets the template to the given block.
getPreview($show_question_only=false, $showInlineFeedback=false)
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.
$errors
Definition: imgupload.php:65
getAfterParticipationSuppressionAnswerPostVars()
Returns a list of postvars which will be suppressed in the form output when used in scoring adjustmen...
getItemByPostVar(string $a_post_var)
getSpecificFeedbackOutput(array $userSolution)
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
addBasicQuestionFormProperties(ilPropertyFormGUI $form)
parseCurrentBlock(string $blockname=self::DEFAULT_BLOCK)
Parses the given block.
escapeTemplatePlaceholders(string $text)
saveCorrectionsFormProperties(ilPropertyFormGUI $form)
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
setOptions(array $a_options)
ilGlobalPageTemplate $tpl
populateQuestionSpecificFormPart(\ilPropertyFormGUI $form)
populateTaxonomyFormSection(ilPropertyFormGUI $form)
removeanswers()
Remove an answer.
$index
Definition: metadata.php:145
addQuestionFormCommandButtons(ilPropertyFormGUI $form)
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
getAnswersFrequency($relevantAnswers, $questionIndex)
This class represents a number property in a property form.
string $key
Consumer key/client ID value.
Definition: System.php:193
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...
setRequired(bool $a_required)
populateAnswerSpecificFormPart(\ilPropertyFormGUI $form)
getTestOutput($active_id, $pass=null, $is_postponed=false, $use_post_solutions=false, $inlineFeedback=false)
static extendedTrim(string $value)
Trim non-printable characters from the beginning and end of a string.
getILIASPage(string $html="")
Returns the ILIAS Page around a question.
outQuestionPage($a_temp_var, $a_postponed=false, $active_id="", $html="", $inlineFeedbackEnabled=false)
setMinValue(float $a_minvalue, bool $a_display_always=false)
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
__construct(Container $dic, ilPlugin $plugin)
getAggregatedAnswersView(array $relevant_answers)
Returns an html string containing a question specific representation of the answers so far given in t...
completeAddAnswerAction($answers, $questionIndex)
$id
plugin.php for ilComponentBuildPluginInfoObjectiveTest::testAddPlugins
Definition: plugin.php:23
writeQuestionSpecificPostData(ilPropertyFormGUI $form)
Extracts the question specific values from $_POST 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...
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
__construct($id=-1)
assTextSubsetGUI constructor
aggregateAnswers($relevant_answers_chosen)
writeAnswerSpecificPostData(ilPropertyFormGUI $form)
Extracts the answer specific values from $_POST and applies them to the data object.
setVariable(string $variable, $value='')
Sets the given variable to the given value.
addanswers()
Add a new answer.
writePostData(bool $always=false)
{}
$i
Definition: metadata.php:41
getGenericFeedbackOutput(int $active_id, ?int $pass)