ILIAS  release_5-4 Revision v5.4.26-12-gabc799a52e6
class.assMatchingQuestionGUI.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 {
35  public function __construct($id = -1)
36  {
37  parent::__construct();
38  include_once "./Modules/TestQuestionPool/classes/class.assMatchingQuestion.php";
39  $this->object = new assMatchingQuestion();
40  $this->setErrorMessage($this->lng->txt("msg_form_save_error"));
41  if ($id >= 0) {
42  $this->object->loadFromDb($id);
43  }
44  }
45 
49  protected function writePostData($always = false)
50  {
51  $hasErrors = (!$always) ? $this->editQuestion(true) : false;
52  if (!$hasErrors) {
53  require_once 'Services/Form/classes/class.ilPropertyFormGUI.php';
57  $this->saveTaxonomyAssignments();
58  return 0;
59  }
60  return 1;
61  }
62 
64  {
65  // Delete all existing answers and create new answers from the form data
66  $this->object->flushMatchingPairs();
67  $this->object->flushTerms();
68  $this->object->flushDefinitions();
69 
70  // add terms
71  require_once './Modules/TestQuestionPool/classes/class.assAnswerMatchingTerm.php';
72  foreach ($_POST['terms']['answer'] as $index => $answer) {
73  $filename = $_POST['terms']['imagename'][$index];
74  if (strlen($_FILES['terms']['name']['image'][$index])) {
75  // upload the new file
76  $name = $_FILES['terms']['name']['image'][$index];
77  if ($this->object->setImageFile(
78  $_FILES['terms']['tmp_name']['image'][$index],
79  $this->object->getEncryptedFilename($name)
80  )
81  ) {
82  $filename = $this->object->getEncryptedFilename($name);
83  } else {
84  $filename = "";
85  }
86  }
87  $this->object->addTerm(
88  new assAnswerMatchingTerm($answer, $filename, $_POST['terms']['identifier'][$index])
89  );
90  }
91  // add definitions
92  require_once './Modules/TestQuestionPool/classes/class.assAnswerMatchingDefinition.php';
93  foreach ($_POST['definitions']['answer'] as $index => $answer) {
94  $filename = $_POST['definitions']['imagename'][$index];
95  if (strlen($_FILES['definitions']['name']['image'][$index])) {
96  // upload the new file
97  $name = $_FILES['definitions']['name']['image'][$index];
98  if ($this->object->setImageFile(
99  $_FILES['definitions']['tmp_name']['image'][$index],
100  $this->object->getEncryptedFilename($name)
101  )
102  ) {
103  $filename = $this->object->getEncryptedFilename($name);
104  } else {
105  $filename = "";
106  }
107  }
108  $this->object->addDefinition(
109  new assAnswerMatchingDefinition($answer, $filename, $_POST['definitions']['identifier'][$index])
110  );
111  }
112 
113  // add matching pairs
114  if (is_array($_POST['pairs']['points'])) {
115  require_once './Modules/TestQuestionPool/classes/class.assAnswerMatchingPair.php';
116  foreach ($_POST['pairs']['points'] as $index => $points) {
117  $term_id = $_POST['pairs']['term'][$index];
118  $definition_id = $_POST['pairs']['definition'][$index];
119  $this->object->addMatchingPair(
120  $this->object->getTermWithIdentifier($term_id),
121  $this->object->getDefinitionWithIdentifier($definition_id),
122  $points
123  );
124  }
125  }
126  }
127 
129  {
130  if (!$this->object->getSelfAssessmentEditingMode()) {
131  $this->object->setShuffle($_POST["shuffle"]);
132  } else {
133  $this->object->setShuffle(1);
134  }
135  $this->object->setThumbGeometry($_POST["thumb_geometry"]);
136  $this->object->setMatchingMode($_POST['matching_mode']);
137  }
138 
139  public function uploadterms()
140  {
141  $this->writePostData(true);
142  $this->editQuestion();
143  }
144 
145  public function removeimageterms()
146  {
147  $this->writePostData(true);
148  $position = key($_POST['cmd']['removeimageterms']);
149  $this->object->removeTermImage($position);
150  $this->editQuestion();
151  }
152 
153  public function uploaddefinitions()
154  {
155  $this->writePostData(true);
156  $this->editQuestion();
157  }
158 
159  public function removeimagedefinitions()
160  {
161  $this->writePostData(true);
162  $position = key($_POST['cmd']['removeimagedefinitions']);
163  $this->object->removeDefinitionImage($position);
164  $this->editQuestion();
165  }
166 
167  public function addterms()
168  {
169  $this->writePostData();
170  $position = key($_POST["cmd"]["addterms"]);
171  $this->object->insertTerm($position + 1);
172  $this->editQuestion();
173  }
174 
175  public function removeterms()
176  {
177  $this->writePostData();
178  $position = key($_POST["cmd"]["removeterms"]);
179  $this->object->deleteTerm($position);
180  $this->editQuestion();
181  }
182 
183  public function adddefinitions()
184  {
185  $this->writePostData();
186  $position = key($_POST["cmd"]["adddefinitions"]);
187  $this->object->insertDefinition($position + 1);
188  $this->editQuestion();
189  }
190 
191  public function removedefinitions()
192  {
193  $this->writePostData();
194  $position = key($_POST["cmd"]["removedefinitions"]);
195  $this->object->deleteDefinition($position);
196  $this->editQuestion();
197  }
198 
199  public function addpairs()
200  {
201  $this->writePostData();
202  $position = key($_POST["cmd"]["addpairs"]);
203  $this->object->insertMatchingPair($position + 1);
204  $this->editQuestion();
205  }
206 
207  public function removepairs()
208  {
209  $this->writePostData();
210  $position = key($_POST["cmd"]["removepairs"]);
211  $this->object->deleteMatchingPair($position);
212  $this->editQuestion();
213  }
214 
215  public function editQuestion($checkonly = false)
216  {
217  $save = $this->isSaveCommand();
218  $this->getQuestionTemplate();
219 
220  include_once("./Services/Form/classes/class.ilPropertyFormGUI.php");
221  $form = new ilPropertyFormGUI();
222  $this->editForm = $form;
223 
224  $form->setFormAction($this->ctrl->getFormAction($this));
225  $form->setTitle($this->outQuestionType());
226  $form->setMultipart(true);
227  $form->setTableWidth("100%");
228  $form->setId("matching");
229 
230 
231  // title, author, description, question, working time (assessment mode)
237 
238  $errors = false;
239  if ($save) {
240  $form->setValuesByPost();
241  $errors = !$form->checkInput();
242  $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
243  if (!$errors && !$this->isValidTermAndDefinitionAmount($form) && !$this->object->getSelfAssessmentEditingMode()) {
244  $errors = true;
245  $terms = $form->getItemByPostVar('terms');
246  $terms->setAlert($this->lng->txt("msg_number_of_terms_too_low"));
247  ilUtil::sendFailure($this->lng->txt('form_input_not_valid'));
248  }
249  if ($errors) {
250  $checkonly = false;
251  }
252  }
253 
254  if (!$checkonly) {
255  $this->tpl->setVariable("QUESTION_DATA", $form->getHTML());
256  }
257  return $errors;
258  }
259 
260  private function isDefImgUploadCommand()
261  {
262  return $this->ctrl->getCmd() == 'uploaddefinitions';
263  }
264 
265  private function isTermImgUploadCommand()
266  {
267  return $this->ctrl->getCmd() == 'uploadterms';
268  }
269 
278  {
279  $matchingMode = $form->getItemByPostVar('matching_mode')->getValue();
280 
281  if ($matchingMode == assMatchingQuestion::MATCHING_MODE_N_ON_N) {
282  return true;
283  }
284 
285  $numTerms = count($form->getItemByPostVar('terms')->getValues());
286  $numDefinitions = count($form->getItemByPostVar('definitions')->getValues());
287 
288  if ($numTerms >= $numDefinitions) {
289  return true;
290  }
291 
292  return false;
293  }
294 
296  {
297  // Definitions
298  include_once "./Modules/TestQuestionPool/classes/class.ilMatchingWizardInputGUI.php";
299  $definitions = new ilMatchingWizardInputGUI($this->lng->txt("definitions"), "definitions");
300  if ($this->object->getSelfAssessmentEditingMode()) {
301  $definitions->setHideImages(true);
302  }
303 
304  $definitions->setRequired(true);
305  $definitions->setQuestionObject($this->object);
306  $definitions->setTextName($this->lng->txt('definition_text'));
307  $definitions->setImageName($this->lng->txt('definition_image'));
308  include_once "./Modules/TestQuestionPool/classes/class.assAnswerMatchingDefinition.php";
309  if (!count($this->object->getDefinitions())) {
310  $this->object->addDefinition(new assAnswerMatchingDefinition());
311  }
312  $definitionvalues = $this->object->getDefinitions();
313  $definitions->setValues($definitionvalues);
314  if ($this->isDefImgUploadCommand()) {
315  $definitions->checkInput();
316  }
317  $form->addItem($definitions);
318 
319  // Terms
320  include_once "./Modules/TestQuestionPool/classes/class.ilMatchingWizardInputGUI.php";
321  $terms = new ilMatchingWizardInputGUI($this->lng->txt("terms"), "terms");
322  if ($this->object->getSelfAssessmentEditingMode()) {
323  $terms->setHideImages(true);
324  }
325  $terms->setRequired(true);
326  $terms->setQuestionObject($this->object);
327  $terms->setTextName($this->lng->txt('term_text'));
328  $terms->setImageName($this->lng->txt('term_image'));
329  include_once "./Modules/TestQuestionPool/classes/class.assAnswerMatchingTerm.php";
330  if (!count($this->object->getTerms())) {
331  $this->object->addTerm(new assAnswerMatchingTerm());
332  }
333  $termvalues = $this->object->getTerms();
334  $terms->setValues($termvalues);
335  if ($this->isTermImgUploadCommand()) {
336  $terms->checkInput();
337  }
338  $form->addItem($terms);
339 
340  // Matching Pairs
341  include_once "./Modules/TestQuestionPool/classes/class.ilMatchingPairWizardInputGUI.php";
342  $pairs = new ilMatchingPairWizardInputGUI($this->lng->txt('matching_pairs'), 'pairs');
343  $pairs->setRequired(true);
344  $pairs->setTerms($this->object->getTerms());
345  $pairs->setDefinitions($this->object->getDefinitions());
346  include_once "./Modules/TestQuestionPool/classes/class.assAnswerMatchingPair.php";
347  if (count($this->object->getMatchingPairs()) == 0) {
348  $this->object->addMatchingPair(new assAnswerMatchingPair($termvalues[0], $definitionvalues[0], 0));
349  }
350  $pairs->setPairs($this->object->getMatchingPairs());
351  $form->addItem($pairs);
352 
353  return $form;
354  }
355 
357  {
358  // Edit mode
359  $hidden = new ilHiddenInputGUI("matching_type");
360  $hidden->setValue($matchingtype);
361  $form->addItem($hidden);
362 
363  if (!$this->object->getSelfAssessmentEditingMode()) {
364  // shuffle
365  $shuffle = new ilSelectInputGUI($this->lng->txt("shuffle_answers"), "shuffle");
366  $shuffle_options = array(
367  0 => $this->lng->txt("no"),
368  1 => $this->lng->txt("matching_shuffle_terms_definitions"),
369  2 => $this->lng->txt("matching_shuffle_terms"),
370  3 => $this->lng->txt("matching_shuffle_definitions")
371  );
372  $shuffle->setOptions($shuffle_options);
373  $shuffle->setValue($this->object->getShuffle() != null ? $this->object->getShuffle() : 1);
374  $shuffle->setRequired(false);
375  $form->addItem($shuffle);
376 
377  $geometry = new ilNumberInputGUI($this->lng->txt("thumb_geometry"), "thumb_geometry");
378  $geometry->setValue($this->object->getThumbGeometry());
379  $geometry->setRequired(true);
380  $geometry->setMaxLength(6);
381  $geometry->setMinValue(20);
382  $geometry->setSize(6);
383  $geometry->setInfo($this->lng->txt("thumb_geometry_info"));
384  $form->addItem($geometry);
385  }
386 
387  // Matching Mode
388  $mode = new ilRadioGroupInputGUI($this->lng->txt('qpl_qst_inp_matching_mode'), 'matching_mode');
389  $mode->setRequired(true);
390 
391  $modeONEonONE = new ilRadioOption(
392  $this->lng->txt('qpl_qst_inp_matching_mode_one_on_one'),
394  );
395  $mode->addOption($modeONEonONE);
396 
397  $modeALLonALL = new ilRadioOption(
398  $this->lng->txt('qpl_qst_inp_matching_mode_all_on_all'),
400  );
401  $mode->addOption($modeALLonALL);
402 
403  $mode->setValue($this->object->getMatchingMode());
404 
405  $form->addItem($mode);
406  }
407 
414  {
415  return true;
416  }
417 
431  public function getSolutionOutput(
432  $active_id,
433  $pass = null,
434  $graphicalOutput = false,
435  $result_output = false,
436  $show_question_only = true,
437  $show_feedback = false,
438  $show_correct_solution = false,
439  $show_manual_scoring = false,
440  $show_question_text = true
441  ) {
442  // generate the question output
443  include_once "./Services/UICore/classes/class.ilTemplate.php";
444  $template = new ilTemplate("tpl.il_as_qpl_matching_output_solution.html", true, true, "Modules/TestQuestionPool");
445  $solutiontemplate = new ilTemplate("tpl.il_as_tst_solution_output.html", true, true, "Modules/TestQuestionPool");
446 
447  $solutions = array();
448  if (($active_id > 0) && (!$show_correct_solution)) {
449  include_once "./Modules/Test/classes/class.ilObjTest.php";
450  $solutions = $this->object->getSolutionValues($active_id, $pass, !$this->getUseIntermediateSolution());
451  $solution_script .= "";
452  } else {
453  foreach ($this->object->getMaximumScoringMatchingPairs() as $pair) {
454  $solutions[] = array(
455  "value1" => $pair->term->identifier,
456  "value2" => $pair->definition->identifier,
457  'points' => $pair->points
458  );
459  }
460  }
461 
462  $i = 0;
463 
464  foreach ($solutions as $solution) {
465  $definition = $this->object->getDefinitionWithIdentifier($solution['value2']);
466  $term = $this->object->getTermWithIdentifier($solution['value1']);
467  $points = $solution['points'];
468 
469  if (is_object($definition)) {
470  if (strlen($definition->picture)) {
471  if (strlen($definition->text)) {
472  $template->setCurrentBlock('definition_image_text');
473  $template->setVariable("TEXT_DEFINITION", ilUtil::prepareFormOutput($definition->text));
474  $template->parseCurrentBlock();
475  }
476 
477  $answerImageSrc = ilWACSignedPath::signFile(
478  $this->object->getImagePathWeb() . $this->object->getThumbPrefix() . $definition->picture
479  );
480 
481  $template->setCurrentBlock('definition_image');
482  $template->setVariable('ANSWER_IMAGE_URL', $answerImageSrc);
483  $template->setVariable('ANSWER_IMAGE_ALT', (strlen($definition->text)) ? ilUtil::prepareFormOutput($definition->text) : ilUtil::prepareFormOutput($definition->picture));
484  $template->setVariable('ANSWER_IMAGE_TITLE', (strlen($definition->text)) ? ilUtil::prepareFormOutput($definition->text) : ilUtil::prepareFormOutput($definition->picture));
485  $template->setVariable('URL_PREVIEW', $this->object->getImagePathWeb() . $definition->picture);
486  $template->setVariable("TEXT_PREVIEW", $this->lng->txt('preview'));
487  $template->setVariable("IMG_PREVIEW", ilUtil::getImagePath('enlarge.svg'));
488  $template->parseCurrentBlock();
489  } else {
490  $template->setCurrentBlock('definition_text');
491  $template->setVariable("DEFINITION", $this->object->prepareTextareaOutput($definition->text, true));
492  $template->parseCurrentBlock();
493  }
494  }
495  if (is_object($term)) {
496  if (strlen($term->picture)) {
497  if (strlen($term->text)) {
498  $template->setCurrentBlock('term_image_text');
499  $template->setVariable("TEXT_TERM", ilUtil::prepareFormOutput($term->text));
500  $template->parseCurrentBlock();
501  }
502 
503  $answerImageSrc = ilWACSignedPath::signFile(
504  $this->object->getImagePathWeb() . $this->object->getThumbPrefix() . $term->picture
505  );
506 
507  $template->setCurrentBlock('term_image');
508  $template->setVariable('ANSWER_IMAGE_URL', $answerImageSrc);
509  $template->setVariable('ANSWER_IMAGE_ALT', (strlen($term->text)) ? ilUtil::prepareFormOutput($term->text) : ilUtil::prepareFormOutput($term->picture));
510  $template->setVariable('ANSWER_IMAGE_TITLE', (strlen($term->text)) ? ilUtil::prepareFormOutput($term->text) : ilUtil::prepareFormOutput($term->picture));
511  $template->setVariable('URL_PREVIEW', $this->object->getImagePathWeb() . $term->picture);
512  $template->setVariable("TEXT_PREVIEW", $this->lng->txt('preview'));
513  $template->setVariable("IMG_PREVIEW", ilUtil::getImagePath('enlarge.svg'));
514  $template->parseCurrentBlock();
515  } else {
516  $template->setCurrentBlock('term_text');
517  $template->setVariable("TERM", $this->object->prepareTextareaOutput($term->text, true));
518  $template->parseCurrentBlock();
519  }
520  $i++;
521  }
522  if (($active_id > 0) && (!$show_correct_solution)) {
523  if ($graphicalOutput) {
524  // output of ok/not ok icons for user entered solutions
525  $ok = false;
526  foreach ($this->object->getMatchingPairs() as $pair) {
527  if ($this->isCorrectMatching($pair, $definition, $term)) {
528  $ok = true;
529  }
530  }
531 
532  if ($ok) {
533  $template->setCurrentBlock("icon_ok");
534  $template->setVariable("ICON_OK", ilUtil::getImagePath("icon_ok.svg"));
535  $template->setVariable("TEXT_OK", $this->lng->txt("answer_is_right"));
536  $template->parseCurrentBlock();
537  } else {
538  $template->setCurrentBlock("icon_ok");
539  $template->setVariable("ICON_NOT_OK", ilUtil::getImagePath("icon_not_ok.svg"));
540  $template->setVariable("TEXT_NOT_OK", $this->lng->txt("answer_is_wrong"));
541  $template->parseCurrentBlock();
542  }
543  }
544  }
545 
546  if ($result_output) {
547  $resulttext = ($points == 1) ? "(%s " . $this->lng->txt("point") . ")" : "(%s " . $this->lng->txt("points") . ")";
548  $template->setCurrentBlock("result_output");
549  $template->setVariable("RESULT_OUTPUT", sprintf($resulttext, $points));
550  $template->parseCurrentBlock();
551  }
552 
553  $template->setCurrentBlock("row");
554  $template->setVariable("TEXT_MATCHES", $this->lng->txt("matches"));
555  $template->parseCurrentBlock();
556  }
557 
558  $questiontext = $this->object->getQuestion();
559  if ($show_question_text == true) {
560  $template->setVariable("QUESTIONTEXT", $this->object->prepareTextareaOutput($questiontext, true));
561  }
562 
563  $questionoutput = $template->get();
564 
565  $feedback = '';
566  if ($show_feedback) {
567  if (!$this->isTestPresentationContext()) {
568  $fb = $this->getGenericFeedbackOutput($active_id, $pass);
569  $feedback .= strlen($fb) ? $fb : '';
570  }
571 
572  $fb = $this->getSpecificFeedbackOutput(array());
573  $feedback .= strlen($fb) ? $fb : '';
574  }
575  if (strlen($feedback)) {
576  $cssClass = (
577  $this->hasCorrectSolution($active_id, $pass) ?
579  );
580 
581  $solutiontemplate->setVariable("ILC_FB_CSS_CLASS", $cssClass);
582  $solutiontemplate->setVariable("FEEDBACK", $this->object->prepareTextareaOutput($feedback, true));
583  }
584 
585  $solutiontemplate->setVariable("SOLUTION_OUTPUT", $questionoutput);
586 
587  $solutionoutput = $solutiontemplate->get();
588  if (!$show_question_only) {
589  // get page object output
590  $solutionoutput = $this->getILIASPage($solutionoutput);
591  }
592  return $solutionoutput;
593  }
594 
595  public function getPreview($show_question_only = false, $showInlineFeedback = false)
596  {
597  $solutions = is_object($this->getPreviewSession()) ? (array) $this->getPreviewSession()->getParticipantsSolution() : array();
598 
599  global $DIC; /* @var ILIAS\DI\Container $DIC */
600  if ($DIC['ilBrowser']->isMobile() || $DIC['ilBrowser']->isIpad()) {
601  require_once 'Services/jQuery/classes/class.iljQueryUtil.php';
604  $this->tpl->addJavaScript('./libs/bower/bower_components/jqueryui-touch-punch/jquery.ui.touch-punch.min.js');
605  } else {
606  $this->tpl->addJavaScript('Modules/TestQuestionPool/js/jquery-ui-1-10-3-fixed.js');
607  }
608  $this->tpl->addJavaScript('Modules/TestQuestionPool/js/ilMatchingQuestion.js');
609  $this->tpl->addCss(ilUtil::getStyleSheetLocation('output', 'test_javascript.css', 'Modules/TestQuestionPool'));
610 
611  $template = new ilTemplate("tpl.il_as_qpl_matching_output.html", true, true, "Modules/TestQuestionPool");
612 
613  foreach ($solutions as $defId => $terms) {
614  foreach ($terms as $termId) {
615  $template->setCurrentBlock("matching_data");
616  $template->setVariable("DEFINITION_ID", $defId);
617  $template->setVariable("TERM_ID", $termId);
618  $template->parseCurrentBlock();
619  }
620  }
621 
622  // shuffle output
623  $terms = $this->object->getTerms();
624  $definitions = $this->object->getDefinitions();
625  switch ($this->object->getShuffle()) {
626  case 1:
627  $seed = $this->object->getShuffler()->getSeed();
628  $this->object->getShuffler()->setSeed($seed . '1');
629  $terms = $this->object->getShuffler()->shuffle($terms);
630  $this->object->getShuffler()->setSeed($seed . '2');
631  $definitions = $this->object->getShuffler()->shuffle($definitions);
632  $this->object->getShuffler()->setSeed($seed);
633  break;
634  case 2:
635  $terms = $this->object->getShuffler()->shuffle($terms);
636  break;
637  case 3:
638  $definitions = $this->object->getShuffler()->shuffle($definitions);
639  break;
640  }
641 
642  // create definitions
643  $counter = 0;
644  foreach ($definitions as $definition) {
645  if (strlen($definition->picture)) {
646  $template->setCurrentBlock("definition_picture");
647  $template->setVariable("DEFINITION_ID", $definition->identifier);
648  $template->setVariable("IMAGE_HREF", $this->object->getImagePathWeb() . $definition->picture);
649  $thumbweb = $this->object->getImagePathWeb() . $this->object->getThumbPrefix() . $definition->picture;
650  $thumb = $this->object->getImagePath() . $this->object->getThumbPrefix() . $definition->picture;
651  if (!@file_exists($thumb)) {
652  $this->object->rebuildThumbnails();
653  }
654  $template->setVariable("THUMBNAIL_HREF", $thumbweb);
655  $template->setVariable("THUMB_ALT", $this->lng->txt("image"));
656  $template->setVariable("THUMB_TITLE", $this->lng->txt("image"));
657  $template->setVariable("TEXT_DEFINITION", (strlen($definition->text)) ? $this->object->prepareTextareaOutput($definition->text, true, true) : '');
658  $template->setVariable("TEXT_PREVIEW", $this->lng->txt('preview'));
659  $template->setVariable("IMG_PREVIEW", ilUtil::getImagePath('enlarge.svg'));
660  $template->parseCurrentBlock();
661  } else {
662  $template->setCurrentBlock("definition_text");
663  $template->setVariable("DEFINITION", $this->object->prepareTextareaOutput($definition->text, true, true));
664  $template->parseCurrentBlock();
665  }
666 
667  $template->setCurrentBlock("droparea");
668  $template->setVariable("ID_DROPAREA", $definition->identifier);
669  $template->setVariable("QUESTION_ID", $this->object->getId());
670  $template->parseCurrentBlock();
671 
672  $template->setCurrentBlock("definition_data");
673  $template->setVariable("DEFINITION_ID", $definition->identifier);
674  $template->parseCurrentBlock();
675  }
676 
677  // create terms
678  $counter = 0;
679  foreach ($terms as $term) {
680  if (strlen($term->picture)) {
681  $template->setCurrentBlock("term_picture");
682  $template->setVariable("TERM_ID", $term->identifier);
683  $template->setVariable("IMAGE_HREF", $this->object->getImagePathWeb() . $term->picture);
684  $thumbweb = $this->object->getImagePathWeb() . $this->object->getThumbPrefix() . $term->picture;
685  $thumb = $this->object->getImagePath() . $this->object->getThumbPrefix() . $term->picture;
686  if (!@file_exists($thumb)) {
687  $this->object->rebuildThumbnails();
688  }
689  $template->setVariable("THUMBNAIL_HREF", $thumbweb);
690  $template->setVariable("THUMB_ALT", $this->lng->txt("image"));
691  $template->setVariable("THUMB_TITLE", $this->lng->txt("image"));
692  $template->setVariable("TEXT_PREVIEW", $this->lng->txt('preview'));
693  $template->setVariable("TEXT_TERM", (strlen($term->text)) ? $this->object->prepareTextareaOutput($term->text, true, true) : '');
694  $template->setVariable("IMG_PREVIEW", ilUtil::getImagePath('enlarge.svg'));
695  $template->parseCurrentBlock();
696  } else {
697  $template->setCurrentBlock("term_text");
698  $template->setVariable("TERM_TEXT", $this->object->prepareTextareaOutput($term->text, true, true));
699  $template->parseCurrentBlock();
700  }
701  $template->setCurrentBlock("draggable");
702  $template->setVariable("ID_DRAGGABLE", $term->identifier);
703  $template->parseCurrentBlock();
704 
705  $template->setCurrentBlock("term_data");
706  $template->setVariable("TERM_ID", $term->identifier);
707  $template->parseCurrentBlock();
708  }
709 
710  $template->setVariable('MATCHING_MODE', $this->object->getMatchingMode());
711 
712  $template->setVariable("RESET_BUTTON", $this->lng->txt("reset_terms"));
713 
714  $template->setVariable("QUESTIONTEXT", $this->object->prepareTextareaOutput($this->object->getQuestion(), true));
715 
716  $questionoutput = $template->get();
717 
718  if (!$show_question_only) {
719  // get page object output
720  $questionoutput = $this->getILIASPage($questionoutput);
721  }
722 
723  return $questionoutput;
724  }
725 
731  protected function sortDefinitionsBySolution(array $solution, array $definitions)
732  {
733  $neworder = array();
734  $handled_defintions = array();
735  foreach ($solution as $solution_values) {
736  $id = $solution_values['value2'];
737  if (!isset($handled_defintions[$id])) {
738  $neworder[] = $this->object->getDefinitionWithIdentifier($id);
739  $handled_defintions[$id] = $id;
740  }
741  }
742 
743  foreach ($definitions as $definition) {
747  if (!isset($handled_defintions[$definition->identifier])) {
748  $neworder[] = $definition;
749  }
750  }
751 
752  return $neworder;
753  }
754 
755  // hey: prevPassSolutions - pass will be always available from now on
756  public function getTestOutput($active_id, $pass, $is_postponed = false, $user_post_solution = false, $inlineFeedback = false)
757  // hey.
758  {
759  global $DIC; /* @var ILIAS\DI\Container $DIC */
760  if ($DIC['ilBrowser']->isMobile() || $DIC['ilBrowser']->isIpad()) {
761  require_once 'Services/jQuery/classes/class.iljQueryUtil.php';
764  $this->tpl->addJavaScript('./libs/bower/bower_components/jqueryui-touch-punch/jquery.ui.touch-punch.min.js');
765  } else {
766  $this->tpl->addJavaScript('Modules/TestQuestionPool/js/jquery-ui-1-10-3-fixed.js');
767  }
768  $this->tpl->addJavaScript('Modules/TestQuestionPool/js/ilMatchingQuestion.js');
769  $this->tpl->addCss(ilUtil::getStyleSheetLocation('output', 'test_javascript.css', 'Modules/TestQuestionPool'));
770 
771  $template = new ilTemplate("tpl.il_as_qpl_matching_output.html", true, true, "Modules/TestQuestionPool");
772 
773  if ($active_id) {
774  // hey: prevPassSolutions - obsolete due to central check
775  #$solutions = NULL;
776  #include_once "./Modules/Test/classes/class.ilObjTest.php";
777  #if (!ilObjTest::_getUsePreviousAnswers($active_id, true))
778  #{
779  # if (is_null($pass)) $pass = ilObjTest::_getPass($active_id);
780  #}
781  // hey.
782  if (is_array($user_post_solution)) {
783  $solutions = array();
784  foreach ($user_post_solution['matching'][$this->object->getId()] as $definition => $term) {
785  array_push($solutions, array("value1" => $term, "value2" => $definition));
786  }
787  } else {
788  // hey: prevPassSolutions - obsolete due to central check
789  $solutions = $this->object->getTestOutputSolutions($active_id, $pass);
790  // hey.
791  }
792 
793  $counter = 0;
794  foreach ($solutions as $idx => $solution_value) {
795  if (($solution_value["value2"] > -1) && ($solution_value["value1"] > -1)) {
796  $template->setCurrentBlock("matching_data");
797  $template->setVariable("TERM_ID", $solution_value["value1"]);
798  $template->setVariable("DEFINITION_ID", $solution_value["value2"]);
799  $template->parseCurrentBlock();
800  }
801 
802  $counter++;
803  }
804  }
805 
806  $terms = $this->object->getTerms();
807  $definitions = $this->object->getDefinitions();
808  switch ($this->object->getShuffle()) {
809  case 1:
810  $seed = $this->object->getShuffler()->getSeed();
811  $this->object->getShuffler()->setSeed($seed . '1');
812  $terms = $this->object->getShuffler()->shuffle($terms);
813  if (count($solutions)) {
814  $definitions = $this->sortDefinitionsBySolution($solutions, $definitions);
815  } else {
816  $this->object->getShuffler()->setSeed($seed . '2');
817  $definitions = $this->object->getShuffler()->shuffle($definitions);
818  }
819  $this->object->getShuffler()->setSeed($seed);
820  break;
821  case 2:
822  $terms = $this->object->getShuffler()->shuffle($terms);
823  break;
824  case 3:
825  if (count($solutions)) {
826  $definitions = $this->sortDefinitionsBySolution($solutions, $definitions);
827  } else {
828  $definitions = $this->object->getShuffler()->shuffle($definitions);
829  }
830  break;
831  }
832 
833  // create definitions
834  $counter = 0;
835  foreach ($definitions as $definition) {
836  if (strlen($definition->picture)) {
837  $template->setCurrentBlock("definition_picture");
838  $template->setVariable("DEFINITION_ID", $definition->identifier);
839  $template->setVariable("IMAGE_HREF", $this->object->getImagePathWeb() . $definition->picture);
840  $thumbweb = $this->object->getImagePathWeb() . $this->object->getThumbPrefix() . $definition->picture;
841  $thumb = $this->object->getImagePath() . $this->object->getThumbPrefix() . $definition->picture;
842  if (!@file_exists($thumb)) {
843  $this->object->rebuildThumbnails();
844  }
845  $template->setVariable("THUMBNAIL_HREF", $thumbweb);
846  $template->setVariable("THUMB_ALT", $this->lng->txt("image"));
847  $template->setVariable("THUMB_TITLE", $this->lng->txt("image"));
848  $template->setVariable("TEXT_DEFINITION", (strlen($definition->text)) ? $this->object->prepareTextareaOutput($definition->text, true, true) : '');
849  $template->setVariable("TEXT_PREVIEW", $this->lng->txt('preview'));
850  $template->setVariable("IMG_PREVIEW", ilUtil::getImagePath('enlarge.svg'));
851  $template->parseCurrentBlock();
852  } else {
853  $template->setCurrentBlock("definition_text");
854  $template->setVariable("DEFINITION", $this->object->prepareTextareaOutput($definition->text, true, true));
855  $template->parseCurrentBlock();
856  }
857 
858  $template->setCurrentBlock("droparea");
859  $template->setVariable("ID_DROPAREA", $definition->identifier);
860  $template->setVariable("QUESTION_ID", $this->object->getId());
861  $template->parseCurrentBlock();
862 
863  $template->setCurrentBlock("definition_data");
864  $template->setVariable("DEFINITION_ID", $definition->identifier);
865  $template->parseCurrentBlock();
866  }
867 
868  // create terms
869  $counter = 0;
870  foreach ($terms as $term) {
871  if (strlen($term->picture)) {
872  $template->setCurrentBlock("term_picture");
873  $template->setVariable("TERM_ID", $term->identifier);
874  $template->setVariable("IMAGE_HREF", $this->object->getImagePathWeb() . $term->picture);
875  $thumbweb = $this->object->getImagePathWeb() . $this->object->getThumbPrefix() . $term->picture;
876  $thumb = $this->object->getImagePath() . $this->object->getThumbPrefix() . $term->picture;
877  if (!@file_exists($thumb)) {
878  $this->object->rebuildThumbnails();
879  }
880  $template->setVariable("THUMBNAIL_HREF", $thumbweb);
881  $template->setVariable("THUMB_ALT", $this->lng->txt("image"));
882  $template->setVariable("THUMB_TITLE", $this->lng->txt("image"));
883  $template->setVariable("TEXT_PREVIEW", $this->lng->txt('preview'));
884  $template->setVariable("TEXT_TERM", (strlen($term->text)) ? $this->object->prepareTextareaOutput($term->text, true, true) : '');
885  $template->setVariable("IMG_PREVIEW", ilUtil::getImagePath('enlarge.svg'));
886  $template->parseCurrentBlock();
887  } else {
888  $template->setCurrentBlock("term_text");
889  $template->setVariable("TERM_TEXT", $this->object->prepareTextareaOutput($term->text, true, true));
890  $template->parseCurrentBlock();
891  }
892  $template->setCurrentBlock("draggable");
893  $template->setVariable("ID_DRAGGABLE", $term->identifier);
894  $template->parseCurrentBlock();
895 
896  $template->setCurrentBlock('term_data');
897  $template->setVariable('TERM_ID', $term->identifier);
898  $template->parseCurrentBlock();
899  }
900 
901  $template->setVariable('MATCHING_MODE', $this->object->getMatchingMode());
902 
903  $template->setVariable("RESET_BUTTON", $this->lng->txt("reset_terms"));
904 
905  $template->setVariable("QUESTIONTEXT", $this->object->prepareTextareaOutput($this->object->getQuestion(), true));
906 
907  return $this->outQuestionPage("", $is_postponed, $active_id, $template->get());
908  }
909 
913  public function checkInput()
914  {
915  if ((!$_POST["title"]) or (!$_POST["author"]) or (!$_POST["question"])) {
916  return false;
917  }
918  return true;
919  }
920 
928  public function setQuestionTabs()
929  {
930  global $DIC;
931  $rbacsystem = $DIC['rbacsystem'];
932  $ilTabs = $DIC['ilTabs'];
933 
934  $ilTabs->clearTargets();
935 
936  $this->ctrl->setParameterByClass("ilAssQuestionPageGUI", "q_id", $_GET["q_id"]);
937  include_once "./Modules/TestQuestionPool/classes/class.assQuestion.php";
938  $q_type = $this->object->getQuestionType();
939 
940  if (strlen($q_type)) {
941  $classname = $q_type . "GUI";
942  $this->ctrl->setParameterByClass(strtolower($classname), "sel_question_types", $q_type);
943  $this->ctrl->setParameterByClass(strtolower($classname), "q_id", $_GET["q_id"]);
944  }
945 
946  if ($_GET["q_id"]) {
947  if ($rbacsystem->checkAccess('write', $_GET["ref_id"])) {
948  // edit page
949  $ilTabs->addTarget(
950  "edit_page",
951  $this->ctrl->getLinkTargetByClass("ilAssQuestionPageGUI", "edit"),
952  array("edit", "insert", "exec_pg"),
953  "",
954  "",
955  $force_active
956  );
957  }
958 
959  $this->addTab_QuestionPreview($ilTabs);
960  }
961 
962  $force_active = false;
963  if ($rbacsystem->checkAccess('write', $_GET["ref_id"])) {
964  $url = "";
965  if ($classname) {
966  $url = $this->ctrl->getLinkTargetByClass($classname, "editQuestion");
967  }
968  // edit question properties
969  $ilTabs->addTarget(
970  "edit_question",
971  $url,
972  array("editQuestion", "save", "saveEdit", "removeimageterms", "uploadterms", "removeimagedefinitions", "uploaddefinitions",
973  "addpairs", "removepairs", "addterms", "removeterms", "adddefinitions", "removedefinitions", "originalSyncForm"),
974  $classname,
975  "",
976  $force_active
977  );
978  }
979 
980  // add tab for question feedback within common class assQuestionGUI
981  $this->addTab_QuestionFeedback($ilTabs);
982 
983  // add tab for question hint within common class assQuestionGUI
984  $this->addTab_QuestionHints($ilTabs);
985 
986  // add tab for question's suggested solution within common class assQuestionGUI
987  $this->addTab_SuggestedSolution($ilTabs, $classname);
988 
989  // Assessment of questions sub menu entry
990  if ($_GET["q_id"]) {
991  $ilTabs->addTarget(
992  "statistics",
993  $this->ctrl->getLinkTargetByClass($classname, "assessment"),
994  array("assessment"),
995  $classname,
996  ""
997  );
998  }
999 
1000  $this->addBackTab($ilTabs);
1001  }
1002 
1003  public function getSpecificFeedbackOutput($userSolution)
1004  {
1005  $matches = array_values($this->object->matchingpairs);
1006 
1007  if (!$this->object->feedbackOBJ->specificAnswerFeedbackExists()) {
1008  return '';
1009  }
1010 
1011  $feedback = '<table class="test_specific_feedback"><tbody>';
1012 
1013  foreach ($matches as $idx => $ans) {
1014  if (!isset($userSolution[$ans->definition->identifier])) {
1015  continue;
1016  }
1017 
1018  if (!is_array($userSolution[$ans->definition->identifier])) {
1019  continue;
1020  }
1021 
1022  if (!in_array($ans->term->identifier, $userSolution[$ans->definition->identifier])) {
1023  continue;
1024  }
1025 
1026  $fb = $this->object->feedbackOBJ->getSpecificAnswerFeedbackTestPresentation(
1027  $this->object->getId(),
1028  0,
1029  $idx
1030  );
1031  $feedback .= '<tr><td>"' . $ans->definition->text . '"&nbsp;' . $this->lng->txt("matches") . '&nbsp;"';
1032  $feedback .= $ans->term->text . '"</td><td>';
1033  $feedback .= $fb . '</td> </tr>';
1034  }
1035 
1036  $feedback .= '</tbody></table>';
1037  return $this->object->prepareTextareaOutput($feedback, true);
1038  }
1039 
1050  {
1051  return array();
1052  }
1053 
1064  {
1065  return array();
1066  }
1067 
1076  public function getAggregatedAnswersView($relevant_answers)
1077  {
1078  return ''; //print_r($relevant_answers,true);
1079  }
1080 
1081  private function isCorrectMatching($pair, $definition, $term)
1082  {
1083  if (!($pair->points > 0)) {
1084  return false;
1085  }
1086 
1087  if (!is_object($term)) {
1088  return false;
1089  }
1090 
1091  if ($pair->definition->identifier != $definition->identifier) {
1092  return false;
1093  }
1094 
1095  if ($pair->term->identifier != $term->identifier) {
1096  return false;
1097  }
1098 
1099  return true;
1100  }
1101 
1102  protected function getAnswerStatisticImageHtml($picture)
1103  {
1104  $thumbweb = $this->object->getImagePathWeb() . $this->object->getThumbPrefix() . $picture;
1105  return '<img src="' . $thumbweb . '" alt="' . $picture . '" title="' . $picture . '"/>';
1106  }
1107 
1108  protected function getAnswerStatisticMatchingElemHtml($elem)
1109  {
1110  $html = '';
1111 
1112  if (strlen($elem->text)) {
1113  $html .= $elem->text;
1114  }
1115 
1116  if (strlen($elem->picture)) {
1117  $html .= $this->getAnswerStatisticImageHtml($elem->picture);
1118  }
1119 
1120  return $html;
1121  }
1122 
1123  public function getAnswersFrequency($relevantAnswers, $questionIndex)
1124  {
1125  $answersByActiveAndPass = array();
1126 
1127  foreach ($relevantAnswers as $row) {
1128  $key = $row['active_fi'] . ':' . $row['pass'];
1129 
1130  if (!isset($answersByActiveAndPass[$key])) {
1131  $answersByActiveAndPass[$key] = array();
1132  }
1133 
1134  $answersByActiveAndPass[$key][$row['value1']] = $row['value2'];
1135  }
1136 
1137  $answers = array();
1138 
1139  foreach ($answersByActiveAndPass as $key => $matchingPairs) {
1140  foreach ($matchingPairs as $termId => $defId) {
1141  $hash = md5($termId . ':' . $defId);
1142 
1143  if (!isset($answers[$hash])) {
1144  $termHtml = $this->getAnswerStatisticMatchingElemHtml(
1145  $this->object->getTermWithIdentifier($termId)
1146  );
1147 
1148  $defHtml = $this->getAnswerStatisticMatchingElemHtml(
1149  $this->object->getDefinitionWithIdentifier($defId)
1150  );
1151 
1152  $answers[$hash] = array(
1153  'answer' => $termHtml . $defHtml,
1154  'term' => $termHtml,
1155  'definition' => $defHtml,
1156  'frequency' => 0
1157  );
1158  }
1159 
1160  $answers[$hash]['frequency']++;
1161  }
1162  }
1163 
1164  return $answers;
1165  }
1166 
1174  public function getAnswerFrequencyTableGUI($parentGui, $parentCmd, $relevantAnswers, $questionIndex)
1175  {
1176  require_once 'Modules/TestQuestionPool/classes/tables/class.ilMatchingQuestionAnswerFreqStatTableGUI.php';
1177 
1178  $table = new ilMatchingQuestionAnswerFreqStatTableGUI($parentGui, $parentCmd, $this->object);
1179  $table->setQuestionIndex($questionIndex);
1180  $table->setData($this->getAnswersFrequency($relevantAnswers, $questionIndex));
1181  $table->initColumns();
1182 
1183  return $table;
1184  }
1185 
1187  {
1188  require_once 'Modules/TestQuestionPool/classes/forms/class.ilAssMatchingPairCorrectionsInputGUI.php';
1189  $pairs = new ilAssMatchingPairCorrectionsInputGUI($this->lng->txt('matching_pairs'), 'pairs');
1190  $pairs->setRequired(true);
1191  $pairs->setTerms($this->object->getTerms());
1192  $pairs->setDefinitions($this->object->getDefinitions());
1193  $pairs->setPairs($this->object->getMatchingPairs());
1194  $form->addItem($pairs);
1195  }
1196 
1201  {
1202  $pairs = $form->getItemByPostVar('pairs')->getPairs();
1203 
1204  foreach ($this->object->getMatchingPairs() as $idx => $matchingPair) {
1205  $matchingPair->points = (float) $pairs[$idx]->points;
1206  }
1207  }
1208 }
Class for matching question terms.
static prepareFormOutput($a_str, $a_strip=false)
prepares string output for html forms public
hasCorrectSolution($activeId, $passIndex)
addTab_QuestionPreview(ilTabsGUI $tabsGUI)
This class represents an option in a radio group.
Class for matching question pairs.
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.
This class represents a single choice wizard property in a property form.
This class represents a selection list property in a property form.
addTab_QuestionHints(ilTabsGUI $tabs)
adds the hints tab to ilTabsGUI
setHideImages($a_hide)
Set hide images.
saveCorrectionsFormProperties(ilPropertyFormGUI $form)
$template
This class represents a property form user interface.
global $DIC
Definition: saml.php:7
static getStyleSheetLocation($mode="output", $a_css_name="", $a_css_location="")
get full style sheet file name (path inclusive) of current user
$_GET["client_id"]
getTestOutput($active_id, $pass, $is_postponed=false, $user_post_solution=false, $inlineFeedback=false)
supportsIntermediateSolutionOutput()
Question type specific support of intermediate solution output The function getSolutionOutput respect...
if(!array_key_exists('StateId', $_REQUEST)) $id
isValidTermAndDefinitionAmount(ilPropertyFormGUI $form)
for mode 1:1 terms count must not be less than definitions count for mode n:n this limitation is canc...
populateCorrectionsFormProperties(ilPropertyFormGUI $form)
addItem($a_item)
Add Item (Property, SectionHeader).
$index
Definition: metadata.php:60
getQuestionTemplate()
get question template
Matching question GUI representation.
populateTaxonomyFormSection(ilPropertyFormGUI $form)
getUseIntermediateSolution()
Get if intermediate solution should be used for solution output.
Class for matching questions.
writeAnswerSpecificPostData(ilPropertyFormGUI $form)
Extracts the answer specific values from $_POST and applies them to the data object.
populateQuestionSpecificFormPart(\ilPropertyFormGUI $form)
This class represents a hidden form property in a property form.
This class represents a property in a property form.
setValue($a_value)
Set Value.
__construct($id=-1)
assMatchingQuestionGUI constructor
if(isset($_POST['submit'])) $form
getAggregatedAnswersView($relevant_answers)
Returns an html string containing a question specific representation of the answers so far given in t...
getILIASPage($html="")
Returns the ILIAS Page around a question.
static getImagePath($img, $module_path="", $mode="output", $offline=false)
get image path (for images located in a template directory)
This class represents a number property in a property form.
writeQuestionSpecificPostData(ilPropertyFormGUI $form)
Extracts the question specific values from $_POST and applies them to the data object.
special template class to simplify handling of ITX/PEAR
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.
isCorrectMatching($pair, $definition, $term)
getAnswerFrequencyTableGUI($parentGui, $parentCmd, $relevantAnswers, $questionIndex)
addTab_QuestionFeedback(ilTabsGUI $tabs)
adds the feedback tab to ilTabsGUI
static signFile($path_to_file)
getPreview($show_question_only=false, $showInlineFeedback=false)
setOptions($a_options)
Set Options.
Basic GUI class for assessment questions.
setErrorMessage($errormessage)
populateAnswerSpecificFormPart(\ilPropertyFormGUI $form)
static sendFailure($a_info="", $a_keep=false)
Send Failure Message to Screen.
$filename
Definition: buildRTE.php:89
setQuestionTabs()
Sets the ILIAS tabs for this question type.
$row
static initjQueryUI($a_tpl=null)
inits and adds the jQuery-UI JS-File to the global template (see included_components.txt for included components)
$errors
Definition: index.php:6
outQuestionPage($a_temp_var, $a_postponed=false, $active_id="", $html="", $inlineFeedbackEnabled=false)
output question page
getAnswersFrequency($relevantAnswers, $questionIndex)
addBackTab(ilTabsGUI $ilTabs)
$i
Definition: disco.tpl.php:19
Class for matching question definitions.
static initjQuery($a_tpl=null)
inits and adds the jQuery JS-File to the global or a passed template
Interface ilGuiAnswerScoringAdjustable.
$url
getAfterParticipationSuppressionQuestionPostVars()
Returns a list of postvars which will be suppressed in the form output when used in scoring adjustmen...
getAfterParticipationSuppressionAnswerPostVars()
Returns a list of postvars which will be suppressed in the form output when used in scoring adjustmen...
if(empty($password)) $table
Definition: pwgen.php:24
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
setRequired($a_required)
Set Required.
addTab_SuggestedSolution(ilTabsGUI $tabs, $classname)
This class represents a key value pair wizard property in a property form.
addQuestionFormCommandButtons($form)
Add the command buttons of a question properties form.