ILIAS  release_5-4 Revision v5.4.26-12-gabc799a52e6
class.assErrorTextGUI.php
Go to the documentation of this file.
1 <?php
2 /* Copyright (c) 1998-2013 ILIAS open source, Extended GPL, see docs/LICENSE */
3 
4 require_once './Modules/TestQuestionPool/classes/class.assQuestionGUI.php';
5 require_once './Modules/TestQuestionPool/interfaces/interface.ilGuiQuestionScoringAdjustable.php';
6 require_once './Modules/TestQuestionPool/interfaces/interface.ilGuiAnswerScoringAdjustable.php';
7 
8 require_once './Modules/Test/classes/inc.AssessmentConstants.php';
9 
25 {
34  public function __construct($id = -1)
35  {
36  parent::__construct();
37  include_once "./Modules/TestQuestionPool/classes/class.assErrorText.php";
38  $this->object = new assErrorText();
39  $this->setErrorMessage($this->lng->txt("msg_form_save_error"));
40  if ($id >= 0) {
41  $this->object->loadFromDb($id);
42  }
43  }
44 
48  protected function writePostData($always = false)
49  {
50  $hasErrors = (!$always) ? $this->editQuestion(true) : false;
51  if (!$hasErrors) {
52  require_once 'Services/Form/classes/class.ilPropertyFormGUI.php';
56  $this->saveTaxonomyAssignments();
57  return 0;
58  }
59  return 1;
60  }
61 
63  {
64  if (is_array($_POST['errordata']['key'])) {
65  $this->object->flushErrorData();
66  foreach ($_POST['errordata']['key'] as $idx => $val) {
67  $this->object->addErrorData(
68  $val,
69  $_POST['errordata']['value'][$idx],
70  $_POST['errordata']['points'][$idx]
71  );
72  }
73  }
74  }
75 
77  {
78  $questiontext = $_POST["question"];
79  $this->object->setQuestion($questiontext);
80  $this->object->setErrorText($_POST["errortext"]);
81  $points_wrong = str_replace(",", ".", $_POST["points_wrong"]);
82  if (strlen($points_wrong) == 0) {
83  $points_wrong = -1.0;
84  }
85  $this->object->setPointsWrong($points_wrong);
86 
87  if (!$this->object->getSelfAssessmentEditingMode()) {
88  $this->object->setTextSize($_POST["textsize"]);
89  }
90  }
91 
99  public function editQuestion($checkonly = false)
100  {
101  $save = $this->isSaveCommand();
102  $this->getQuestionTemplate();
103 
104  include_once("./Services/Form/classes/class.ilPropertyFormGUI.php");
105  $form = new ilPropertyFormGUI();
106  $this->editForm = $form;
107 
108  $form->setFormAction($this->ctrl->getFormAction($this));
109  $form->setTitle($this->outQuestionType());
110  $form->setMultipart(false);
111  $form->setTableWidth("100%");
112  $form->setId("orderinghorizontal");
113 
115 
117 
118  if (count($this->object->getErrorData()) || $checkonly) {
120  }
121 
123 
124  $form->addCommandButton("analyze", $this->lng->txt('analyze_errortext'));
126 
127  $errors = false;
128 
129  if ($save) {
130  $form->setValuesByPost();
131  $errors = !$form->checkInput();
132  $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
133  if ($errors) {
134  $checkonly = false;
135  }
136  }
137 
138  if (!$checkonly) {
139  $this->tpl->setVariable("QUESTION_DATA", $form->getHTML());
140  }
141  return $errors;
142  }
143 
149  {
151  $header->setTitle($this->lng->txt("errors_section"));
152  $form->addItem($header);
153 
154  include_once "./Modules/TestQuestionPool/classes/class.ilErrorTextWizardInputGUI.php";
155  $errordata = new ilErrorTextWizardInputGUI($this->lng->txt("errors"), "errordata");
156  $errordata->setKeyName($this->lng->txt('text_wrong'));
157  $errordata->setValueName($this->lng->txt('text_correct'));
158  $errordata->setValues($this->object->getErrorData());
159  $form->addItem($errordata);
160 
161  // points for wrong selection
162  $points_wrong = new ilNumberInputGUI($this->lng->txt("points_wrong"), "points_wrong");
163  $points_wrong->allowDecimals(true);
164  $points_wrong->setMaxValue(0);
165  $points_wrong->setMaxvalueShouldBeLess(true);
166  $points_wrong->setValue($this->object->getPointsWrong());
167  $points_wrong->setInfo($this->lng->txt("points_wrong_info"));
168  $points_wrong->setSize(6);
169  $points_wrong->setRequired(true);
170  $form->addItem($points_wrong);
171  return $form;
172  }
173 
179  {
180  // errortext
181  $errortext = new ilTextAreaInputGUI($this->lng->txt("errortext"), "errortext");
182  $errortext->setValue($this->object->getErrorText());
183  $errortext->setRequired(true);
184  $errortext->setInfo($this->lng->txt("errortext_info"));
185  $errortext->setRows(10);
186  $errortext->setCols(80);
187  $form->addItem($errortext);
188 
189  if (!$this->object->getSelfAssessmentEditingMode()) {
190  // textsize
191  $textsize = new ilNumberInputGUI($this->lng->txt("textsize"), "textsize");
192  $textsize->setValue(strlen($this->object->getTextSize()) ? $this->object->getTextSize() : 100.0);
193  $textsize->setInfo($this->lng->txt("textsize_errortext_info"));
194  $textsize->setSize(6);
195  $textsize->setSuffix("%");
196  $textsize->setMinValue(10);
197  $textsize->setRequired(true);
198  $form->addItem($textsize);
199  }
200  }
201 
205  public function analyze()
206  {
207  $this->writePostData(true);
208  $this->object->setErrorData($this->object->getErrorsFromText($_POST['errortext']));
209  $this->editQuestion();
210  }
211 
218  {
219  return true;
220  }
221 
240  public function getSolutionOutput(
241  $active_id,
242  $pass = null,
243  $graphicalOutput = false,
244  $result_output = false,
245  $show_question_only = true,
246  $show_feedback = false,
247  $show_correct_solution = false,
248  $show_manual_scoring = false,
249  $show_question_text = true
250  ) {
251  // get the solution of the user for the active pass or from the last pass if allowed
252  $template = new ilTemplate("tpl.il_as_qpl_errortext_output_solution.html", true, true, "Modules/TestQuestionPool");
253 
254  $selections = array();
255  if (($active_id > 0) && (!$show_correct_solution)) {
256 
257  /* Retrieve tst_solutions entries. */
258  $reached_points = $this->object->getReachedPoints($active_id, $pass);
259  $solutions = $this->object->getSolutionValues($active_id, $pass, !$this->getUseIntermediateSolution());
260  if (is_array($solutions)) {
261  foreach ($solutions as $solution) {
262  array_push($selections, (int) $solution['value1']);
263  }
264  $errortext_value = join(",", $selections);
265  }
266  } else {
267  $selections = $this->object->getBestSelection();
268  $reached_points = $this->object->getPoints();
269  }
270 
271  if ($result_output) {
272  $resulttext = ($reached_points == 1) ? "(%s " . $this->lng->txt("point") . ")" : "(%s " . $this->lng->txt("points") . ")";
273  $template->setVariable("RESULT_OUTPUT", sprintf($resulttext, $reached_points));
274  }
275 
276  if ($this->object->getTextSize() >= 10) {
277  $template->setVariable("STYLE", " style=\"font-size: " . $this->object->getTextSize() . "%;\"");
278  }
279 
280  if ($show_question_text == true) {
281  $template->setVariable("QUESTIONTEXT", $this->object->prepareTextareaOutput($this->object->getQuestion(), true));
282  }
283 
284  $errortext = $this->object->createErrorTextOutput($selections, $graphicalOutput, $show_correct_solution, false);
285 
286  $template->setVariable("ERRORTEXT", $errortext);
287  $questionoutput = $template->get();
288 
289  $solutiontemplate = new ilTemplate("tpl.il_as_tst_solution_output.html", true, true, "Modules/TestQuestionPool");
290 
291  $feedback = '';
292  if ($show_feedback) {
293  if (!$this->isTestPresentationContext()) {
294  $fb = $this->getGenericFeedbackOutput($active_id, $pass);
295  $feedback .= strlen($fb) ? $fb : '';
296  }
297 
298  $fb = $this->getSpecificFeedbackOutput(array());
299  $feedback .= strlen($fb) ? $fb : '';
300  }
301  if (strlen($feedback)) {
302  $cssClass = (
303  $this->hasCorrectSolution($active_id, $pass) ?
305  );
306 
307  $solutiontemplate->setVariable("ILC_FB_CSS_CLASS", $cssClass);
308  $solutiontemplate->setVariable("FEEDBACK", $this->object->prepareTextareaOutput($feedback, true));
309  }
310 
311  $solutiontemplate->setVariable("SOLUTION_OUTPUT", $questionoutput);
312 
313  $solutionoutput = $solutiontemplate->get();
314  if (!$show_question_only) {
315  // get page object output
316  $solutionoutput = $this->getILIASPage($solutionoutput);
317  }
318  return $solutionoutput;
319  }
320 
321  public function getPreview($show_question_only = false, $showInlineFeedback = false)
322  {
323  $selections = is_object($this->getPreviewSession()) ? (array) $this->getPreviewSession()->getParticipantsSolution() : array();
324 
325  $template = new ilTemplate("tpl.il_as_qpl_errortext_output.html", true, true, "Modules/TestQuestionPool");
326  if ($this->object->getTextSize() >= 10) {
327  $template->setVariable("STYLE", " style=\"font-size: " . $this->object->getTextSize() . "%;\"");
328  }
329  $template->setVariable("QUESTIONTEXT", $this->object->prepareTextareaOutput($this->object->getQuestion(), true));
330  $errortext = $this->object->createErrorTextOutput($selections);
331  $template->setVariable("ERRORTEXT", $errortext);
332  $template->setVariable("ERRORTEXT_ID", "qst_" . $this->object->getId());
333  $questionoutput = $template->get();
334  if (!$show_question_only) {
335  // get page object output
336  $questionoutput = $this->getILIASPage($questionoutput);
337  }
338  $this->tpl->addJavascript("./Modules/TestQuestionPool/templates/default/errortext.js");
339  return $questionoutput;
340  }
341 
342  public function getTestOutput(
343  $active_id,
344  // hey: prevPassSolutions - will be always available from now on
345  $pass,
346  // hey.
347  $is_postponed = false,
348  $use_post_solutions = false,
349  $show_feedback = false
350  ) {
351  // generate the question output
352  $template = new ilTemplate("tpl.il_as_qpl_errortext_output.html", true, true, "Modules/TestQuestionPool");
353  if ($active_id) {
354  // hey: prevPassSolutions - obsolete due to central check
355  #$solutions = NULL;
356  #include_once "./Modules/Test/classes/class.ilObjTest.php";
357  #if (!ilObjTest::_getUsePreviousAnswers($active_id, true))
358  #{
359  # if (is_null($pass)) $pass = ilObjTest::_getPass($active_id);
360  #}
361  $solutions = $this->object->getTestOutputSolutions($active_id, $pass);
362  // hey.
363  }
364  $errortext_value = "";
365  $selections = array();
366  if (is_array($solutions)) {
367  foreach ($solutions as $solution) {
368  array_push($selections, $solution['value1']);
369  }
370  $errortext_value = join(",", $selections);
371  }
372  if ($this->object->getTextSize() >= 10) {
373  $template->setVariable("STYLE", " style=\"font-size: " . $this->object->getTextSize() . "%;\"");
374  }
375  $template->setVariable("QUESTIONTEXT", $this->object->prepareTextareaOutput($this->object->getQuestion(), true));
376  $errortext = $this->object->createErrorTextOutput($selections);
377  $this->ctrl->setParameterByClass($this->getTargetGuiClass(), 'errorvalue', '');
378  $template->setVariable("ERRORTEXT", $errortext);
379  $template->setVariable("ERRORTEXT_ID", "qst_" . $this->object->getId());
380  $template->setVariable("ERRORTEXT_VALUE", $errortext_value);
381 
382  $questionoutput = $template->get();
383  if (!$show_question_only) {
384  // get page object output
385  $questionoutput = $this->getILIASPage($questionoutput);
386  }
387  $this->tpl->addJavascript("./Modules/TestQuestionPool/templates/default/errortext.js");
388  $questionoutput = $template->get();
389  $pageoutput = $this->outQuestionPage("", $is_postponed, $active_id, $questionoutput);
390  return $pageoutput;
391  }
392 
400  public function setQuestionTabs()
401  {
402  global $DIC;
403  $rbacsystem = $DIC['rbacsystem'];
404  $ilTabs = $DIC['ilTabs'];
405 
406  $ilTabs->clearTargets();
407 
408  $this->ctrl->setParameterByClass("ilAssQuestionPageGUI", "q_id", $_GET["q_id"]);
409  include_once "./Modules/TestQuestionPool/classes/class.assQuestion.php";
410  $q_type = $this->object->getQuestionType();
411 
412  if (strlen($q_type)) {
413  $classname = $q_type . "GUI";
414  $this->ctrl->setParameterByClass(strtolower($classname), "sel_question_types", $q_type);
415  $this->ctrl->setParameterByClass(strtolower($classname), "q_id", $_GET["q_id"]);
416  }
417 
418  if ($_GET["q_id"]) {
419  if ($rbacsystem->checkAccess('write', $_GET["ref_id"])) {
420  // edit page
421  $ilTabs->addTarget(
422  "edit_page",
423  $this->ctrl->getLinkTargetByClass("ilAssQuestionPageGUI", "edit"),
424  array("edit", "insert", "exec_pg"),
425  "",
426  "",
427  $force_active
428  );
429  }
430 
431  $this->addTab_QuestionPreview($ilTabs);
432  }
433 
434  $force_active = false;
435  if ($rbacsystem->checkAccess('write', $_GET["ref_id"])) {
436  $url = "";
437  if ($classname) {
438  $url = $this->ctrl->getLinkTargetByClass($classname, "editQuestion");
439  }
440  // edit question properties
441  $ilTabs->addTarget(
442  "edit_question",
443  $url,
444  array("editQuestion", "save", "saveEdit", "analyze", "originalSyncForm"),
445  $classname,
446  "",
447  $force_active
448  );
449  }
450 
451  // add tab for question feedback within common class assQuestionGUI
452  $this->addTab_QuestionFeedback($ilTabs);
453 
454  // add tab for question hint within common class assQuestionGUI
455  $this->addTab_QuestionHints($ilTabs);
456 
457  // add tab for question's suggested solution within common class assQuestionGUI
458  $this->addTab_SuggestedSolution($ilTabs, $classname);
459 
460  // Assessment of questions sub menu entry
461  if ($_GET["q_id"]) {
462  $ilTabs->addTarget(
463  "statistics",
464  $this->ctrl->getLinkTargetByClass($classname, "assessment"),
465  array("assessment"),
466  $classname,
467  ""
468  );
469  }
470 
471  $this->addBackTab($ilTabs);
472  }
473 
474  public function getSpecificFeedbackOutput($userSolution)
475  {
476  $selection = $this->object->getBestSelection(false);
477 
478  if (!$this->object->feedbackOBJ->specificAnswerFeedbackExists()) {
479  return '';
480  }
481 
482  $feedback = '<table class="test_specific_feedback"><tbody>';
483 
484  $elements = array();
485  foreach (preg_split("/[\n\r]+/", $this->object->errortext) as $line) {
486  $elements = array_merge($elements, preg_split("/\s+/", $line));
487  }
488 
489  $matchedIndexes = array();
490 
491  $i = 0;
492  foreach ($selection as $index => $answer) {
493  $element = array();
494  foreach ($answer as $answerPartIndex) {
495  $element[] = $elements[$answerPartIndex];
496  }
497 
498  $element = implode(' ', $element);
499  $element = str_replace(array('((', '))', '#'), array('', '', ''), $element);
500 
501  $ordinal = $index + 1;
502 
503  $feedback .= '<tr>';
504 
505  $feedback .= '<td class="text-nowrap">' . $ordinal . '. ' . $element . ':</td>';
506 
507  foreach ($this->object->getErrorData() as $idx => $ans) {
508  if (isset($matchedIndexes[$idx])) {
509  continue;
510  }
511 
512  if (preg_match('/' . preg_quote($ans->text_wrong, '/') . '/', $element)) {
513  $fb = $this->object->feedbackOBJ->getSpecificAnswerFeedbackTestPresentation(
514  $this->object->getId(),
515  0,
516  $idx
517  );
518 
519  $feedback .= '<td>' . $fb . '</td>';
520 
521  $matchedIndexes[$idx] = $idx;
522 
523  break;
524  }
525  }
526 
527  $feedback .= '</tr>';
528  }
529 
530  $feedback .= '</tbody></table>';
531 
532  return $this->object->prepareTextareaOutput($feedback, true);
533  }
534 
545  {
546  return array();
547  }
548 
559  {
560  return array();
561  }
562 
571  public function getAggregatedAnswersView($relevant_answers)
572  {
573  $errortext = $this->object->getErrorText();
574 
575  $passdata = array(); // Regroup answers into units of passes.
576  foreach ($relevant_answers as $answer_chosen) {
577  $passdata[$answer_chosen['active_fi'] . '-' . $answer_chosen['pass']][$answer_chosen['value2']][] = $answer_chosen['value1'];
578  }
579 
580  $html = '';
581  foreach ($passdata as $key => $pass) {
582  $passdata[$key] = $this->object->createErrorTextOutput($pass);
583  $html .= $passdata[$key] . '<hr /><br />';
584  }
585 
586  return $html;
587  }
588 
589  public function getAnswersFrequency($relevantAnswers, $questionIndex)
590  {
591  $answersByActiveAndPass = array();
592 
593  foreach ($relevantAnswers as $row) {
594  $key = $row['active_fi'] . ':' . $row['pass'];
595 
596  if (!isset($answersByActiveAndPass[$key])) {
597  $answersByActiveAndPass[$key] = array();
598  }
599 
600  if (!isset($answersByActiveAndPass[$key][$row['value2']])) {
601  $answersByActiveAndPass[$key][$row['value2']] = array();
602  }
603 
604  $answersByActiveAndPass[$key][$row['value2']][] = $row['value1'];
605  }
606 
607  $answers = array();
608 
609  foreach ($answersByActiveAndPass as $ans) {
610  $errorText = $this->object->createErrorTextOutput($ans);
611  $errorMd5 = md5($errorText);
612 
613  if (!isset($answers[$errorMd5])) {
614  $answers[$errorMd5] = array(
615  'answer' => $errorText, 'frequency' => 0
616  );
617  }
618 
619  $answers[$errorMd5]['frequency']++;
620  }
621 
622  return array_values($answers);
623  }
624 
626  {
627  // error terms
628  include_once "./Modules/TestQuestionPool/classes/forms/class.ilAssErrorTextCorrectionsInputGUI.php";
629  $errordata = new ilAssErrorTextCorrectionsInputGUI($this->lng->txt("errors"), "errordata");
630  $errordata->setKeyName($this->lng->txt('text_wrong'));
631  $errordata->setValueName($this->lng->txt('text_correct'));
632  $errordata->setValues($this->object->getErrorData());
633  $form->addItem($errordata);
634 
635  // points for wrong selection
636  $points_wrong = new ilNumberInputGUI($this->lng->txt("points_wrong"), "points_wrong");
637  $points_wrong->allowDecimals(true);
638  $points_wrong->setMaxValue(0);
639  $points_wrong->setMaxvalueShouldBeLess(true);
640  $points_wrong->setValue($this->object->getPointsWrong());
641  $points_wrong->setInfo($this->lng->txt("points_wrong_info"));
642  $points_wrong->setSize(6);
643  $points_wrong->setRequired(true);
644  $form->addItem($points_wrong);
645 
646  return $form;
647  }
648 
653  {
654  $this->object->flushErrorData();
655  foreach ($form->getItemByPostVar('errordata')->getValues() as $idx => $errAnswer) {
656  $this->object->addErrorData(
657  $errAnswer->text_wrong,
658  $errAnswer->text_correct,
659  $errAnswer->points
660  );
661  }
662 
663  $this->object->setPointsWrong((float) $form->getInput('points_wrong'));
664  }
665 }
hasCorrectSolution($activeId, $passIndex)
addTab_QuestionPreview(ilTabsGUI $tabsGUI)
addBasicQuestionFormProperties($form)
Add basic question form properties: assessment: title, author, description, question, working time.
getItemByPostVar($a_post_var)
Get Item by POST variable.
setValue($a_value)
Set Value.
addTab_QuestionHints(ilTabsGUI $tabs)
adds the hints tab to ilTabsGUI
$template
This class represents a property form user interface.
global $DIC
Definition: saml.php:7
$_GET["client_id"]
getAnswersFrequency($relevantAnswers, $questionIndex)
This class represents a section header in a property form.
populateQuestionSpecificFormPart(ilPropertyFormGUI $form)
populateCorrectionsFormProperties(ilPropertyFormGUI $form)
if(!array_key_exists('StateId', $_REQUEST)) $id
setValue($a_value)
Set Value.
supportsIntermediateSolutionOutput()
Question type specific support of intermediate solution output The function getSolutionOutput respect...
populateAnswerSpecificFormPart(ilPropertyFormGUI $form)
writePostData($always=false)
{}
addItem($a_item)
Add Item (Property, SectionHeader).
$index
Definition: metadata.php:60
getQuestionTemplate()
get question template
__construct($id=-1)
assErrorTextGUI constructor
getAfterParticipationSuppressionAnswerPostVars()
Returns a list of postvars which will be suppressed in the form output when used in scoring adjustmen...
populateTaxonomyFormSection(ilPropertyFormGUI $form)
writeQuestionSpecificPostData(ilPropertyFormGUI $form)
Extracts the question specific values from $_POST and applies them to the data object.
getSpecificFeedbackOutput($userSolution)
getUseIntermediateSolution()
Get if intermediate solution should be used for solution output.
getTestOutput( $active_id, $pass, $is_postponed=false, $use_post_solutions=false, $show_feedback=false)
allowDecimals($a_value)
Toggle Decimals.
getAfterParticipationSuppressionQuestionPostVars()
Returns a list of postvars which will be suppressed in the form output when used in scoring adjustmen...
if(isset($_POST['submit'])) $form
getILIASPage($html="")
Returns the ILIAS Page around a question.
This class represents a number property in a property form.
special template class to simplify handling of ITX/PEAR
Class for error text questions.
saveCorrectionsFormProperties(ilPropertyFormGUI $form)
addTab_QuestionFeedback(ilTabsGUI $tabs)
adds the feedback tab to ilTabsGUI
getPreview($show_question_only=false, $showInlineFeedback=false)
getInput($a_post_var, $ensureValidation=true)
Returns the value of a HTTP-POST variable, identified by the passed id.
writeAnswerSpecificPostData(ilPropertyFormGUI $form)
Extracts the answer specific values from $_POST and applies them to the data object.
The assErrorTextGUI class encapsulates the GUI representation for error text questions.
Basic GUI class for assessment questions.
setErrorMessage($errormessage)
setQuestionTabs()
Sets the ILIAS tabs for this question type.
analyze()
Parse the error text.
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.
$row
editQuestion($checkonly=false)
Creates an output of the edit form for the question.
$errors
Definition: index.php:6
outQuestionPage($a_temp_var, $a_postponed=false, $active_id="", $html="", $inlineFeedbackEnabled=false)
output question page
This class represents a text area property in a property form.
addBackTab(ilTabsGUI $ilTabs)
$i
Definition: disco.tpl.php:19
This class represents a key value pair wizard property in a property form.
Interface ilGuiAnswerScoringAdjustable.
$url
getGenericFeedbackOutput($active_id, $pass)
Returns the answer specific feedback for the question.
Interface ilGuiQuestionScoringAdjustable.
$key
Definition: croninfo.php:18
$_POST["username"]
$html
Definition: example_001.php:87
addTab_SuggestedSolution(ilTabsGUI $tabs, $classname)
getAggregatedAnswersView($relevant_answers)
Returns an html string containing a question specific representation of the answers so far given in t...
addQuestionFormCommandButtons($form)
Add the command buttons of a question properties form.