ILIAS  Release_4_4_x_branch Revision 61816
 All Data Structures Namespaces Files Functions Variables Groups Pages
class.assTextSubsetGUI.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 require_once './Modules/Test/classes/inc.AssessmentConstants.php';
8 
24 {
32  public function __construct($id = -1)
33  {
35  require_once './Modules/TestQuestionPool/classes/class.assTextSubset.php';
36  $this->object = new assTextSubset();
37  if ($id >= 0)
38  {
39  $this->object->loadFromDb($id);
40  }
41  }
42 
50  public function writePostData($always = false)
51  {
52  $hasErrors = (!$always) ? $this->editQuestion(true) : false;
53  if (!$hasErrors)
54  {
58  $this->saveTaxonomyAssignments();
59  return 0;
60  }
61  return 1;
62  }
63 
67  public function editQuestion($checkonly = FALSE)
68  {
69  $save = $this->isSaveCommand();
70  $this->getQuestionTemplate();
71 
72  require_once './Services/Form/classes/class.ilPropertyFormGUI.php';
73  $form = new ilPropertyFormGUI();
74  $form->setFormAction($this->ctrl->getFormAction($this));
75  $form->setTitle($this->outQuestionType());
76  $form->setMultipart(FALSE);
77  $form->setTableWidth("100%");
78  $form->setId("asstextsubset");
79 
80  $this->addBasicQuestionFormProperties($form);
81  $this->populateQuestionSpecificFormPart( $form );
82  $this->populateAnswerSpecificFormPart( $form );
83  $this->populateTaxonomyFormSection($form);
84  $this->addQuestionFormCommandButtons($form);
85 
86  $errors = false;
87  if ($save)
88  {
89  $form->setValuesByPost();
90  $points = $form->getItemByPostVar('points');
91  $points->setValue($this->object->getMaximumPoints());
92  $errors = !$form->checkInput();
93  $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
94  if ($errors) $checkonly = false;
95  }
96 
97  if (!$checkonly) $this->tpl->setVariable("QUESTION_DATA", $form->getHTML());
98  return $errors;
99  }
100 
104  public function addanswers()
105  {
106  $this->writePostData(true);
107  $position = key($_POST['cmd']['addanswers']);
108  $this->object->addAnswer("", 0, $position+1);
109  $this->editQuestion();
110  }
111 
115  public function removeanswers()
116  {
117  $this->writePostData(true);
118  $position = key($_POST['cmd']['removeanswers']);
119  $this->object->deleteAnswer($position);
120  $this->editQuestion();
121  }
122 
123  function outQuestionForTest($formaction, $active_id, $pass = NULL, $is_postponed = FALSE, $use_post_solutions = FALSE)
124  {
125  $test_output = $this->getTestOutput($active_id, $pass, $is_postponed, $use_post_solutions);
126  $this->tpl->setVariable("QUESTION_OUTPUT", $test_output);
127  $this->tpl->setVariable("FORMACTION", $formaction);
128  }
129 
144  $active_id,
145  $pass = NULL,
146  $graphicalOutput = FALSE,
147  $result_output = FALSE,
148  $show_question_only = TRUE,
149  $show_feedback = FALSE,
150  $show_correct_solution = FALSE,
151  $show_manual_scoring = FALSE,
152  $show_question_text = TRUE
153  )
154  {
155  // get the solution of the user for the active pass or from the last pass if allowed
156  $solutions = array();
157  if (($active_id > 0) && (!$show_correct_solution))
158  {
159  $solutions =& $this->object->getSolutionValues($active_id, $pass);
160  }
161  else
162  {
163  $rank = array();
164  foreach ($this->object->answers as $answer)
165  {
166  if ($answer->getPoints() > 0)
167  {
168  if (!is_array($rank[$answer->getPoints()]))
169  {
170  $rank[$answer->getPoints()] = array();
171  }
172  array_push($rank[$answer->getPoints()], $answer->getAnswertext());
173  }
174  }
175  krsort($rank, SORT_NUMERIC);
176  foreach ($rank as $index => $bestsolutions)
177  {
178  array_push($solutions, array("value1" => join(",", $bestsolutions), "points" => $index));
179  }
180  }
181 
182  // generate the question output
183  include_once "./Services/UICore/classes/class.ilTemplate.php";
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  {
189  if ((!$test_id) && (strcmp($solutions[$i]["value1"], "") == 0))
190  {
191  }
192  else
193  {
194  if (($active_id > 0) && (!$show_correct_solution))
195  {
196  if ($graphicalOutput)
197  {
198  // output of ok/not ok icons for user entered solutions
199  $index = $this->object->isAnswerCorrect($available_answers, $solutions[$i]["value1"]);
200  $correct = FALSE;
201  if ($index !== FALSE)
202  {
203  unset($available_answers[$index]);
204  $correct = TRUE;
205  }
206  if ($correct)
207  {
208  $template->setCurrentBlock("icon_ok");
209  $template->setVariable("ICON_OK", ilUtil::getImagePath("icon_ok.png"));
210  $template->setVariable("TEXT_OK", $this->lng->txt("answer_is_right"));
211  $template->parseCurrentBlock();
212  }
213  else
214  {
215  $template->setCurrentBlock("icon_ok");
216  $template->setVariable("ICON_NOT_OK", ilUtil::getImagePath("icon_not_ok.png"));
217  $template->setVariable("TEXT_NOT_OK", $this->lng->txt("answer_is_wrong"));
218  $template->parseCurrentBlock();
219  }
220  }
221  }
222  $template->setCurrentBlock("textsubset_row");
223  $template->setVariable("SOLUTION", $solutions[$i]["value1"]);
224  $template->setVariable("COUNTER", $i+1);
225  if ($result_output)
226  {
227  $points = $solutions[$i]["points"];
228  $resulttext = ($points == 1) ? "(%s " . $this->lng->txt("point") . ")" : "(%s " . $this->lng->txt("points") . ")";
229  $template->setVariable("RESULT_OUTPUT", sprintf($resulttext, $points));
230  }
231  $template->parseCurrentBlock();
232  }
233  }
234  $questiontext = $this->object->getQuestion();
235  if ($show_question_text==true)
236  {
237  $template->setVariable("QUESTIONTEXT", $this->object->prepareTextareaOutput($questiontext, TRUE));
238  }
239  $questionoutput = $template->get();
240  $feedback = ($show_feedback) ? $this->getAnswerFeedbackOutput($active_id, $pass) : "";
241  if (strlen($feedback)) $solutiontemplate->setVariable("FEEDBACK", $this->object->prepareTextareaOutput( $feedback, true));
242  $solutiontemplate->setVariable("SOLUTION_OUTPUT", $questionoutput);
243 
244  $solutionoutput = $solutiontemplate->get();
245  if (!$show_question_only)
246  {
247  // get page object output
248  $solutionoutput = '<div class="ilc_question_Standard">'.$solutionoutput."</div>";
249  }
250  return $solutionoutput;
251  }
252 
253  function getPreview($show_question_only = FALSE)
254  {
255  // generate the question output
256  include_once "./Services/UICore/classes/class.ilTemplate.php";
257  $template = new ilTemplate("tpl.il_as_qpl_textsubset_output.html", TRUE, TRUE, "Modules/TestQuestionPool");
258  $width = $this->object->getMaxTextboxWidth();
259  for ($i = 0; $i < $this->object->getCorrectAnswers(); $i++)
260  {
261  $template->setCurrentBlock("textsubset_row");
262  $template->setVariable("COUNTER", $i+1);
263  $template->setVariable("TEXTFIELD_ID", sprintf("%02d", $i+1));
264  $template->setVariable("TEXTFIELD_SIZE", $width);
265  $template->parseCurrentBlock();
266  }
267  $questiontext = $this->object->getQuestion();
268  $template->setVariable("QUESTIONTEXT", $this->object->prepareTextareaOutput($questiontext, TRUE));
269  $questionoutput = $template->get();
270  if (!$show_question_only)
271  {
272  // get page object output
273  $questionoutput = $this->getILIASPage($questionoutput);
274  }
275  return $questionoutput;
276  }
277 
278  function getTestOutput($active_id, $pass = NULL, $is_postponed = FALSE, $use_post_solutions = FALSE)
279  {
280  // get the solution of the user for the active pass or from the last pass if allowed
281  $user_solution = "";
282  if ($active_id)
283  {
284  $solutions = NULL;
285  include_once "./Modules/Test/classes/class.ilObjTest.php";
286  if (!ilObjTest::_getUsePreviousAnswers($active_id, true))
287  {
288  if (is_null($pass)) $pass = ilObjTest::_getPass($active_id);
289  }
290  $solutions =& $this->object->getSolutionValues($active_id, $pass);
291  }
292 
293  // generate the question output
294  include_once "./Services/UICore/classes/class.ilTemplate.php";
295  $template = new ilTemplate("tpl.il_as_qpl_textsubset_output.html", TRUE, TRUE, "Modules/TestQuestionPool");
296  $width = $this->object->getMaxTextboxWidth();
297  for ($i = 0; $i < $this->object->getCorrectAnswers(); $i++)
298  {
299  $template->setCurrentBlock("textsubset_row");
300  foreach ($solutions as $idx => $solution_value)
301  {
302  if ($idx == $i)
303  {
304  $template->setVariable("TEXTFIELD_VALUE", " value=\"" . ilUtil::prepareFormOutput($solution_value["value1"])."\"");
305  }
306  }
307  $template->setVariable("COUNTER", $i+1);
308  $template->setVariable("TEXTFIELD_ID", sprintf("%02d", $i+1));
309  $template->setVariable("TEXTFIELD_SIZE", $width);
310  $template->parseCurrentBlock();
311  }
312  $questiontext = $this->object->getQuestion();
313  $template->setVariable("QUESTIONTEXT", $this->object->prepareTextareaOutput($questiontext, TRUE));
314  $questionoutput = $template->get();
315  $pageoutput = $this->outQuestionPage("", $is_postponed, $active_id, $questionoutput);
316  return $pageoutput;
317  }
318 
326  function setQuestionTabs()
327  {
328  global $rbacsystem, $ilTabs;
329 
330  $this->ctrl->setParameterByClass("ilAssQuestionPageGUI", "q_id", $_GET["q_id"]);
331  include_once "./Modules/TestQuestionPool/classes/class.assQuestion.php";
332  $q_type = $this->object->getQuestionType();
333 
334  if (strlen($q_type))
335  {
336  $classname = $q_type . "GUI";
337  $this->ctrl->setParameterByClass(strtolower($classname), "sel_question_types", $q_type);
338  $this->ctrl->setParameterByClass(strtolower($classname), "q_id", $_GET["q_id"]);
339  }
340 
341  if ($_GET["q_id"])
342  {
343  if ($rbacsystem->checkAccess('write', $_GET["ref_id"]))
344  {
345  // edit page
346  $ilTabs->addTarget("edit_page",
347  $this->ctrl->getLinkTargetByClass("ilAssQuestionPageGUI", "edit"),
348  array("edit", "insert", "exec_pg"),
349  "", "", $force_active);
350  }
351 
352  // edit page
353  $ilTabs->addTarget("preview",
354  $this->ctrl->getLinkTargetByClass("ilAssQuestionPageGUI", "preview"),
355  array("preview"),
356  "ilAssQuestionPageGUI", "", $force_active);
357  }
358 
359  $force_active = false;
360  if ($rbacsystem->checkAccess('write', $_GET["ref_id"]))
361  {
362  $url = "";
363  if ($classname) $url = $this->ctrl->getLinkTargetByClass($classname, "editQuestion");
364  // edit question properties
365  $ilTabs->addTarget("edit_question",
366  $url,
367  array("editQuestion", "save", "saveEdit", "addanswers", "removeanswers", "originalSyncForm"),
368  $classname, "", $force_active);
369  }
370 
371  // add tab for question feedback within common class assQuestionGUI
372  $this->addTab_QuestionFeedback($ilTabs);
373 
374  // add tab for question hint within common class assQuestionGUI
375  $this->addTab_QuestionHints($ilTabs);
376 
377  if ($_GET["q_id"])
378  {
379  $ilTabs->addTarget("solution_hint",
380  $this->ctrl->getLinkTargetByClass($classname, "suggestedsolution"),
381  array("suggestedsolution", "saveSuggestedSolution", "outSolutionExplorer", "cancel",
382  "addSuggestedSolution","cancelExplorer", "linkChilds", "removeSuggestedSolution"
383  ),
384  $classname,
385  ""
386  );
387  }
388 
389  // Assessment of questions sub menu entry
390  if ($_GET["q_id"])
391  {
392  $ilTabs->addTarget("statistics",
393  $this->ctrl->getLinkTargetByClass($classname, "assessment"),
394  array("assessment"),
395  $classname, "");
396  }
397 
398  if (($_GET["calling_test"] > 0) || ($_GET["test_ref_id"] > 0))
399  {
400  $ref_id = $_GET["calling_test"];
401  if (strlen($ref_id) == 0) $ref_id = $_GET["test_ref_id"];
402 
403  global $___test_express_mode;
404 
405  if (!$_GET['test_express_mode'] && !$___test_express_mode) {
406  $ilTabs->setBackTarget($this->lng->txt("backtocallingtest"), "ilias.php?baseClass=ilObjTestGUI&cmd=questions&ref_id=$ref_id");
407  }
408  else {
410  $ilTabs->setBackTarget($this->lng->txt("backtocallingtest"), $link);
411  }
412  }
413  else
414  {
415  $ilTabs->setBackTarget($this->lng->txt("qpl"), $this->ctrl->getLinkTargetByClass("ilobjquestionpoolgui", "questions"));
416  }
417  }
418 
419  function getSpecificFeedbackOutput($active_id, $pass)
420  {
421  $output = "";
422  return $this->object->prepareTextareaOutput($output, TRUE);
423  }
424 
425  public function writeQuestionSpecificPostData($always = true)
426  {
427  $this->object->setCorrectAnswers( $_POST["correctanswers"] );
428  $this->object->setTextRating( $_POST["text_rating"] );
429  }
430 
431  public function writeAnswerSpecificPostData($always = true)
432  {
433  // Delete all existing answers and create new answers from the form data
434  $this->object->flushAnswers();
435  foreach ($_POST['answers']['answer'] as $index => $answer)
436  {
437  $answertext = $answer;
438  $this->object->addAnswer( $answertext, $_POST['answers']['points'][$index], $index );
439  }
440  }
441 
443  {
444  // number of requested answers
445  $correctanswers = new ilNumberInputGUI($this->lng->txt( "nr_of_correct_answers" ), "correctanswers");
446  $correctanswers->setMinValue( 1 );
447  $correctanswers->setDecimals( 0 );
448  $correctanswers->setSize( 3 );
449  $correctanswers->setValue( $this->object->getCorrectAnswers() );
450  $correctanswers->setRequired( true );
451  $form->addItem( $correctanswers );
452 
453  // maximum available points
454  $points = new ilNumberInputGUI($this->lng->txt( "maximum_points" ), "points");
455  $points->setMinValue(0.0);
456  $points->setMinvalueShouldBeGreater(true);
457  $points->setSize( 6 );
458  $points->setDisabled( true );
459  $points->setValue( $this->object->getMaximumPoints() );
460  $points->setRequired( false );
461  $form->addItem( $points );
462 
463  // text rating
464  $textrating = new ilSelectInputGUI($this->lng->txt( "text_rating" ), "text_rating");
465  $text_options = array(
466  "ci" => $this->lng->txt( "cloze_textgap_case_insensitive" ),
467  "cs" => $this->lng->txt( "cloze_textgap_case_sensitive" )
468  );
469  if (!$this->object->getSelfAssessmentEditingMode())
470  {
471  $text_options["l1"] = sprintf( $this->lng->txt( "cloze_textgap_levenshtein_of" ), "1" );
472  $text_options["l2"] = sprintf( $this->lng->txt( "cloze_textgap_levenshtein_of" ), "2" );
473  $text_options["l3"] = sprintf( $this->lng->txt( "cloze_textgap_levenshtein_of" ), "3" );
474  $text_options["l4"] = sprintf( $this->lng->txt( "cloze_textgap_levenshtein_of" ), "4" );
475  $text_options["l5"] = sprintf( $this->lng->txt( "cloze_textgap_levenshtein_of" ), "5" );
476  }
477  $textrating->setOptions( $text_options );
478  $textrating->setValue( $this->object->getTextRating() );
479  $form->addItem( $textrating );
480  return $form;
481  }
482 
484  {
485  // Choices
486  include_once "./Modules/TestQuestionPool/classes/class.ilAnswerWizardInputGUI.php";
487  $choices = new ilAnswerWizardInputGUI($this->lng->txt( "answers" ), "answers");
488  $choices->setRequired( true );
489  $choices->setQuestionObject( $this->object );
490  $choices->setSingleline( true );
491  $choices->setAllowMove( false );
492  $choices->setMinValue(0.0);
493  if ($this->object->getAnswerCount() == 0)
494  $this->object->addAnswer( "", 0, 0 );
495  $choices->setValues( $this->object->getAnswers() );
496  $form->addItem( $choices );
497  return $form;
498  }
499 
500 
511  {
512  return array();
513  }
514 
525  {
526  return array('correctanswers');
527  }
528 
530  {
531  $element = $form->getItemByPostvar('correctanswers');
532  $_POST['correctanswers'] = $this->object->getCorrectAnswers();
533  $element->setValue( $this->object->getCorrectAnswers() );
534  }
535 
544  public function getAggregatedAnswersView($relevant_answers)
545  {
546  $passes = array();
547  foreach($relevant_answers as $pass)
548  {
549  $passes[$pass['active_fi'].'-'.$pass['pass']] = '-';
550  }
551  $passcount = count($passes);
552 
553  foreach($relevant_answers as $pass)
554  {
555  $actives[$pass['active_fi']] = $pass['active_fi'];
556  }
557  $usercount = count($actives);
558  $tpl = new ilTemplate('tpl.il_as_aggregated_answers_header.html', true, true, "Modules/TestQuestionPool");
559  $tpl->setVariable('HEADERTEXT', $this->lng->txt('overview'));
560  $tpl->setVariable('NUMBER_OF_USERS_INFO', $this->lng->txt('number_of_users'));
561  $tpl->setVariable('NUMBER_OF_USERS', $usercount);
562  $tpl->setVariable('NUMBER_OF_PASSES_INFO', $this->lng->txt('number_of_passes'));
563  $tpl->setVariable('NUMBER_OF_PASSES', $passcount);
564 
565  return $tpl->get() . $this->renderAggregateView(
566  $this->aggregateAnswers( $relevant_answers ) )->get();
567  }
568 
569  public function aggregateAnswers($relevant_answers_chosen)
570  {
571  $aggregate = array();
572 
573  foreach ($relevant_answers_chosen as $relevant_answer)
574  {
575  if ( array_key_exists($relevant_answer['value1'], $aggregate) )
576  {
577  $aggregate[$relevant_answer['value1']]++;
578  }
579  else
580  {
581  $aggregate[$relevant_answer['value1']] = 1;
582  }
583  }
584  return $aggregate;
585  }
586 
592  public function renderAggregateView($aggregate)
593  {
594  $tpl = new ilTemplate('tpl.il_as_aggregated_answers_table.html', true, true, "Modules/TestQuestionPool");
595  $tpl->setVariable( 'OPTION_HEADER', $this->lng->txt('answer') );
596  $tpl->setVariable( 'COUNT_HEADER', $this->lng->txt('count') );
597  $tpl->setVariable( 'AGGREGATION_HEADER', $this->lng->txt('aggregated_answers_header') );
598 
599  foreach ($aggregate as $key => $value)
600  {
601  $tpl->setCurrentBlock( 'aggregaterow' );
602  $tpl->setVariable( 'OPTION', $key );
603  $tpl->setVariable( 'COUNT', $value );
604  $tpl->parseCurrentBlock();
605  }
606  return $tpl;
607  }
608 }