ILIAS  release_7 Revision v7.30-3-g800a261c036
All Data Structures Namespaces Files Functions Variables Modules Pages
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  {
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';
56  if ($always || $this->validateUploadSubforms()) {
58  }
59  $this->saveTaxonomyAssignments();
60  return 0;
61  }
62  return 1;
63  }
64 
65  public function validateUploadSubforms()
66  {
67  include_once("./Services/Form/classes/class.ilPropertyFormGUI.php");
68  $form = new ilPropertyFormGUI();
69 
70  $form->setFormAction($this->ctrl->getFormAction($this));
71  $form->setTitle($this->outQuestionType());
72  $form->setMultipart(true);
73  $form->setTableWidth("100%");
74  $form->setId("matching");
75 
76  $this->populateAnswerSpecificFormPart($form);
77 
78  $form->setValuesByPost();
79 
80  return $form->checkInput();
81  }
82 
84  {
85  // Delete all existing answers and create new answers from the form data
86  $this->object->flushMatchingPairs();
87  $this->object->flushTerms();
88  $this->object->flushDefinitions();
89 
90  // add terms
91  require_once './Modules/TestQuestionPool/classes/class.assAnswerMatchingTerm.php';
92  foreach ($_POST['terms']['answer'] as $index => $answer) {
93  $filename = $_POST['terms']['imagename'][$index];
94  if (strlen($_FILES['terms']['name']['image'][$index])) {
95  // upload the new file
96  $name = $_FILES['terms']['name']['image'][$index];
97  if ($this->object->setImageFile(
98  $_FILES['terms']['tmp_name']['image'][$index],
99  $this->object->getEncryptedFilename($name)
100  )
101  ) {
102  $filename = $this->object->getEncryptedFilename($name);
103  } else {
104  $filename = "";
105  }
106  }
107  $this->object->addTerm(
108  new assAnswerMatchingTerm(htmlentities($answer), $filename, $_POST['terms']['identifier'][$index])
109  );
110  }
111  // add definitions
112  require_once './Modules/TestQuestionPool/classes/class.assAnswerMatchingDefinition.php';
113  foreach ($_POST['definitions']['answer'] as $index => $answer) {
114  $filename = $_POST['definitions']['imagename'][$index];
115  if (strlen($_FILES['definitions']['name']['image'][$index])) {
116  // upload the new file
117  $name = $_FILES['definitions']['name']['image'][$index];
118  if ($this->object->setImageFile(
119  $_FILES['definitions']['tmp_name']['image'][$index],
120  $this->object->getEncryptedFilename($name)
121  )
122  ) {
123  $filename = $this->object->getEncryptedFilename($name);
124  } else {
125  $filename = "";
126  }
127  }
128  $this->object->addDefinition(
129  new assAnswerMatchingDefinition(htmlentities($answer), $filename, $_POST['definitions']['identifier'][$index])
130  );
131  }
132 
133  // add matching pairs
134  if (is_array($_POST['pairs']['points'])) {
135  require_once './Modules/TestQuestionPool/classes/class.assAnswerMatchingPair.php';
136  foreach ($_POST['pairs']['points'] as $index => $points) {
137  $term_id = $_POST['pairs']['term'][$index];
138  $definition_id = $_POST['pairs']['definition'][$index];
139  $this->object->addMatchingPair(
140  $this->object->getTermWithIdentifier($term_id),
141  $this->object->getDefinitionWithIdentifier($definition_id),
142  $points
143  );
144  }
145  }
146  }
147 
149  {
150  if (!$this->object->getSelfAssessmentEditingMode()) {
151  $this->object->setShuffle($_POST["shuffle"]);
152  } else {
153  $this->object->setShuffle(1);
154  }
155  $this->object->setThumbGeometry($_POST["thumb_geometry"]);
156  $this->object->setMatchingMode($_POST['matching_mode']);
157  }
158 
159  public function uploadterms()
160  {
161  $this->writePostData(true);
162  $this->editQuestion();
163  }
164 
165  public function removeimageterms()
166  {
167  $this->writePostData(true);
168  $position = key($_POST['cmd']['removeimageterms']);
169  $this->object->removeTermImage($position);
170  $this->editQuestion();
171  }
172 
173  public function uploaddefinitions()
174  {
175  $this->writePostData(true);
176  $this->editQuestion();
177  }
178 
179  public function removeimagedefinitions()
180  {
181  $this->writePostData(true);
182  $position = key($_POST['cmd']['removeimagedefinitions']);
183  $this->object->removeDefinitionImage($position);
184  $this->editQuestion();
185  }
186 
187  public function addterms()
188  {
189  $this->writePostData(true);
190  $position = key($_POST["cmd"]["addterms"]);
191  $this->object->insertTerm($position + 1);
192  $this->editQuestion();
193  }
194 
195  public function removeterms()
196  {
197  $this->writePostData(true);
198  $position = key($_POST["cmd"]["removeterms"]);
199  $this->object->deleteTerm($position);
200  $this->editQuestion();
201  }
202 
203  public function adddefinitions()
204  {
205  $this->writePostData(true);
206  $position = key($_POST["cmd"]["adddefinitions"]);
207  $this->object->insertDefinition($position + 1);
208  $this->editQuestion();
209  }
210 
211  public function removedefinitions()
212  {
213  $this->writePostData(true);
214  $position = key($_POST["cmd"]["removedefinitions"]);
215  $this->object->deleteDefinition($position);
216  $this->editQuestion();
217  }
218 
219  public function addpairs()
220  {
221  $this->writePostData(true);
222  $position = key($_POST["cmd"]["addpairs"]);
223  $this->object->insertMatchingPair($position + 1);
224  $this->editQuestion();
225  }
226 
227  public function removepairs()
228  {
229  $this->writePostData(true);
230  $position = key($_POST["cmd"]["removepairs"]);
231  $this->object->deleteMatchingPair($position);
232  $this->editQuestion();
233  }
234 
235  public function editQuestion($checkonly = false)
236  {
237  $save = $this->isSaveCommand();
238  $this->getQuestionTemplate();
239 
240  include_once("./Services/Form/classes/class.ilPropertyFormGUI.php");
241  $form = new ilPropertyFormGUI();
242  $this->editForm = $form;
243 
244  $form->setFormAction($this->ctrl->getFormAction($this));
245  $form->setTitle($this->outQuestionType());
246  $form->setMultipart(true);
247  $form->setTableWidth("100%");
248  $form->setId("matching");
249 
250 
251  // title, author, description, question, working time (assessment mode)
252  $this->addBasicQuestionFormProperties($form);
253  $this->populateQuestionSpecificFormPart($form);
254  $this->populateAnswerSpecificFormPart($form);
255  $this->populateTaxonomyFormSection($form);
256  $this->addQuestionFormCommandButtons($form);
257 
258  $errors = false;
259  if ($save) {
260  $form->setValuesByPost();
261  $errors = !$form->checkInput();
262  $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
263  if (!$errors && !$this->isValidTermAndDefinitionAmount($form) && !$this->object->getSelfAssessmentEditingMode()) {
264  $errors = true;
265  $terms = $form->getItemByPostVar('terms');
266  $terms->setAlert($this->lng->txt("msg_number_of_terms_too_low"));
267  ilUtil::sendFailure($this->lng->txt('form_input_not_valid'));
268  }
269  if ($errors) {
270  $checkonly = false;
271  }
272  }
273 
274  if (!$checkonly) {
275  $this->tpl->setVariable("QUESTION_DATA", $form->getHTML());
276  }
277  return $errors;
278  }
279 
280  private function isDefImgUploadCommand()
281  {
282  return $this->ctrl->getCmd() == 'uploaddefinitions';
283  }
284 
285  private function isTermImgUploadCommand()
286  {
287  return $this->ctrl->getCmd() == 'uploadterms';
288  }
289 
298  {
299  $matchingMode = $form->getItemByPostVar('matching_mode')->getValue();
300 
301  if ($matchingMode == assMatchingQuestion::MATCHING_MODE_N_ON_N) {
302  return true;
303  }
304 
305  $numTerms = count($form->getItemByPostVar('terms')->getValues());
306  $numDefinitions = count($form->getItemByPostVar('definitions')->getValues());
307 
308  if ($numTerms >= $numDefinitions) {
309  return true;
310  }
311 
312  return false;
313  }
314 
316  {
317  // Definitions
318  include_once "./Modules/TestQuestionPool/classes/class.ilMatchingWizardInputGUI.php";
319  $definitions = new ilMatchingWizardInputGUI($this->lng->txt("definitions"), "definitions");
320  if ($this->object->getSelfAssessmentEditingMode()) {
321  $definitions->setHideImages(true);
322  }
323 
324  $stripHtmlEntitesFromValues = function (assAnswerMatchingTerm $value) {
325  $value->__set('text', html_entity_decode($value->__get('text')));
326  return $value;
327  };
328 
329  $definitions->setRequired(true);
330  $definitions->setQuestionObject($this->object);
331  $definitions->setTextName($this->lng->txt('definition_text'));
332  $definitions->setImageName($this->lng->txt('definition_image'));
333  include_once "./Modules/TestQuestionPool/classes/class.assAnswerMatchingDefinition.php";
334  if (!count($this->object->getDefinitions())) {
335  $this->object->addDefinition(new assAnswerMatchingDefinition());
336  }
337  $definitionvalues = array_map($stripHtmlEntitesFromValues, $this->object->getDefinitions());
338  $definitions->setValues($definitionvalues);
339  if ($this->isDefImgUploadCommand()) {
340  $definitions->checkInput();
341  }
342  $form->addItem($definitions);
343 
344  // Terms
345  include_once "./Modules/TestQuestionPool/classes/class.ilMatchingWizardInputGUI.php";
346  $terms = new ilMatchingWizardInputGUI($this->lng->txt("terms"), "terms");
347  if ($this->object->getSelfAssessmentEditingMode()) {
348  $terms->setHideImages(true);
349  }
350  $terms->setRequired(true);
351  $terms->setQuestionObject($this->object);
352  $terms->setTextName($this->lng->txt('term_text'));
353  $terms->setImageName($this->lng->txt('term_image'));
354  include_once "./Modules/TestQuestionPool/classes/class.assAnswerMatchingTerm.php";
355  if (!count($this->object->getTerms())) {
356  $this->object->addTerm(new assAnswerMatchingTerm());
357  }
358  $termvalues = array_map($stripHtmlEntitesFromValues, $this->object->getTerms());
359  $terms->setValues($termvalues);
360  if ($this->isTermImgUploadCommand()) {
361  $terms->checkInput();
362  }
363  $form->addItem($terms);
364 
365  // Matching Pairs
366  include_once "./Modules/TestQuestionPool/classes/class.ilMatchingPairWizardInputGUI.php";
367  $pairs = new ilMatchingPairWizardInputGUI($this->lng->txt('matching_pairs'), 'pairs');
368  $pairs->setRequired(true);
369  $pairs->setTerms($this->object->getTerms());
370  $pairs->setDefinitions($this->object->getDefinitions());
371  include_once "./Modules/TestQuestionPool/classes/class.assAnswerMatchingPair.php";
372  if (count($this->object->getMatchingPairs()) == 0) {
373  $this->object->addMatchingPair(new assAnswerMatchingPair($termvalues[0], $definitionvalues[0], 0));
374  }
375  $pairs->setPairs($this->object->getMatchingPairs());
376  $form->addItem($pairs);
377 
378  return $form;
379  }
380 
382  {
383  // Edit mode
384  $hidden = new ilHiddenInputGUI("matching_type");
385  $hidden->setValue($matchingtype);
386  $form->addItem($hidden);
387 
388  if (!$this->object->getSelfAssessmentEditingMode()) {
389  // shuffle
390  $shuffle = new ilSelectInputGUI($this->lng->txt("shuffle_answers"), "shuffle");
391  $shuffle_options = array(
392  0 => $this->lng->txt("no"),
393  1 => $this->lng->txt("matching_shuffle_terms_definitions"),
394  2 => $this->lng->txt("matching_shuffle_terms"),
395  3 => $this->lng->txt("matching_shuffle_definitions")
396  );
397  $shuffle->setOptions($shuffle_options);
398  $shuffle->setValue($this->object->getShuffle() != null ? $this->object->getShuffle() : 1);
399  $shuffle->setRequired(false);
400  $form->addItem($shuffle);
401 
402  $geometry = new ilNumberInputGUI($this->lng->txt("thumb_geometry"), "thumb_geometry");
403  $geometry->setValue($this->object->getThumbGeometry());
404  $geometry->setRequired(true);
405  $geometry->setMaxLength(6);
406  $geometry->setMinValue(20);
407  $geometry->setSize(6);
408  $geometry->setInfo($this->lng->txt("thumb_geometry_info"));
409  $form->addItem($geometry);
410  }
411 
412  // Matching Mode
413  $mode = new ilRadioGroupInputGUI($this->lng->txt('qpl_qst_inp_matching_mode'), 'matching_mode');
414  $mode->setRequired(true);
415 
416  $modeONEonONE = new ilRadioOption(
417  $this->lng->txt('qpl_qst_inp_matching_mode_one_on_one'),
419  );
420  $mode->addOption($modeONEonONE);
421 
422  $modeALLonALL = new ilRadioOption(
423  $this->lng->txt('qpl_qst_inp_matching_mode_all_on_all'),
425  );
426  $mode->addOption($modeALLonALL);
427 
428  $mode->setValue($this->object->getMatchingMode());
429 
430  $form->addItem($mode);
431  }
432 
439  {
440  return true;
441  }
442 
456  public function getSolutionOutput(
457  $active_id,
458  $pass = null,
459  $graphicalOutput = false,
460  $result_output = false,
461  $show_question_only = true,
462  $show_feedback = false,
463  $show_correct_solution = false,
464  $show_manual_scoring = false,
465  $show_question_text = true
466  ) {
467  // generate the question output
468  include_once "./Services/UICore/classes/class.ilTemplate.php";
469  $template = new ilTemplate("tpl.il_as_qpl_matching_output_solution.html", true, true, "Modules/TestQuestionPool");
470  $solutiontemplate = new ilTemplate("tpl.il_as_tst_solution_output.html", true, true, "Modules/TestQuestionPool");
471 
472  $solutions = array();
473  if (($active_id > 0) && (!$show_correct_solution)) {
474  include_once "./Modules/Test/classes/class.ilObjTest.php";
475  $solutions = $this->object->getSolutionValues($active_id, $pass, !$this->getUseIntermediateSolution());
476  $solution_script .= "";
477  } else {
478  foreach ($this->object->getMaximumScoringMatchingPairs() as $pair) {
479  $solutions[] = array(
480  "value1" => $pair->term->identifier,
481  "value2" => $pair->definition->identifier,
482  'points' => $pair->points
483  );
484  }
485  }
486 
487  $i = 0;
488 
489  foreach ($solutions as $solution) {
490  $definition = $this->object->getDefinitionWithIdentifier($solution['value2']);
491  $term = $this->object->getTermWithIdentifier($solution['value1']);
492  $points = $solution['points'];
493 
494  if (is_object($definition)) {
495  if (strlen($definition->picture)) {
496  if (strlen($definition->text)) {
497  $template->setCurrentBlock('definition_image_text');
498  $template->setVariable("TEXT_DEFINITION", ilUtil::prepareFormOutput($definition->text));
499  $template->parseCurrentBlock();
500  }
501 
502  $answerImageSrc = ilWACSignedPath::signFile(
503  $this->object->getImagePathWeb() . $this->object->getThumbPrefix() . $definition->picture
504  );
505 
506  $template->setCurrentBlock('definition_image');
507  $template->setVariable('ANSWER_IMAGE_URL', $answerImageSrc);
508  $template->setVariable('ANSWER_IMAGE_ALT', (strlen($definition->text)) ? ilUtil::prepareFormOutput($definition->text) : ilUtil::prepareFormOutput($definition->picture));
509  $template->setVariable('ANSWER_IMAGE_TITLE', (strlen($definition->text)) ? ilUtil::prepareFormOutput($definition->text) : ilUtil::prepareFormOutput($definition->picture));
510  $template->setVariable('URL_PREVIEW', $this->object->getImagePathWeb() . $definition->picture);
511  $template->setVariable("TEXT_PREVIEW", $this->lng->txt('preview'));
512  $template->setVariable("IMG_PREVIEW", ilUtil::getImagePath('enlarge.svg'));
513  $template->parseCurrentBlock();
514  } else {
515  $template->setCurrentBlock('definition_text');
516  $template->setVariable("DEFINITION", $this->object->prepareTextareaOutput($definition->text, true));
517  $template->parseCurrentBlock();
518  }
519  }
520  if (is_object($term)) {
521  if (strlen($term->picture)) {
522  if (strlen($term->text)) {
523  $template->setCurrentBlock('term_image_text');
524  $template->setVariable("TEXT_TERM", ilUtil::prepareFormOutput($term->text));
525  $template->parseCurrentBlock();
526  }
527 
528  $answerImageSrc = ilWACSignedPath::signFile(
529  $this->object->getImagePathWeb() . $this->object->getThumbPrefix() . $term->picture
530  );
531 
532  $template->setCurrentBlock('term_image');
533  $template->setVariable('ANSWER_IMAGE_URL', $answerImageSrc);
534  $template->setVariable('ANSWER_IMAGE_ALT', (strlen($term->text)) ? ilUtil::prepareFormOutput($term->text) : ilUtil::prepareFormOutput($term->picture));
535  $template->setVariable('ANSWER_IMAGE_TITLE', (strlen($term->text)) ? ilUtil::prepareFormOutput($term->text) : ilUtil::prepareFormOutput($term->picture));
536  $template->setVariable('URL_PREVIEW', $this->object->getImagePathWeb() . $term->picture);
537  $template->setVariable("TEXT_PREVIEW", $this->lng->txt('preview'));
538  $template->setVariable("IMG_PREVIEW", ilUtil::getImagePath('enlarge.svg'));
539  $template->parseCurrentBlock();
540  } else {
541  $template->setCurrentBlock('term_text');
542  $template->setVariable("TERM", $this->object->prepareTextareaOutput($term->text, true));
543  $template->parseCurrentBlock();
544  }
545  $i++;
546  }
547  if (($active_id > 0) && (!$show_correct_solution)) {
548  if ($graphicalOutput) {
549  // output of ok/not ok icons for user entered solutions
550  $ok = false;
551  foreach ($this->object->getMatchingPairs() as $pair) {
552  if ($this->isCorrectMatching($pair, $definition, $term)) {
553  $ok = true;
554  }
555  }
556 
557  if ($ok) {
558  $template->setCurrentBlock("icon_ok");
559  $template->setVariable("ICON_OK", ilUtil::getImagePath("icon_ok.svg"));
560  $template->setVariable("TEXT_OK", $this->lng->txt("answer_is_right"));
561  $template->parseCurrentBlock();
562  } else {
563  $template->setCurrentBlock("icon_ok");
564  $template->setVariable("ICON_NOT_OK", ilUtil::getImagePath("icon_not_ok.svg"));
565  $template->setVariable("TEXT_NOT_OK", $this->lng->txt("answer_is_wrong"));
566  $template->parseCurrentBlock();
567  }
568  }
569  }
570 
571  if ($result_output) {
572  $resulttext = ($points == 1) ? "(%s " . $this->lng->txt("point") . ")" : "(%s " . $this->lng->txt("points") . ")";
573  $template->setCurrentBlock("result_output");
574  $template->setVariable("RESULT_OUTPUT", sprintf($resulttext, $points));
575  $template->parseCurrentBlock();
576  }
577 
578  $template->setCurrentBlock("row");
579  $template->setVariable("TEXT_MATCHES", $this->lng->txt("matches"));
580  $template->parseCurrentBlock();
581  }
582 
583  if ($show_question_text == true) {
584  $template->setVariable("QUESTIONTEXT", $this->object->getQuestionForHTMLOutput());
585  }
586 
587  $questionoutput = $template->get();
588 
589  $feedback = '';
590  if ($show_feedback) {
591  if (!$this->isTestPresentationContext()) {
592  $fb = $this->getGenericFeedbackOutput($active_id, $pass);
593  $feedback .= strlen($fb) ? $fb : '';
594  }
595 
596  $fb = $this->getSpecificFeedbackOutput(array());
597  $feedback .= strlen($fb) ? $fb : '';
598  }
599  if (strlen($feedback)) {
600  $cssClass = (
601  $this->hasCorrectSolution($active_id, $pass) ?
603  );
604 
605  $solutiontemplate->setVariable("ILC_FB_CSS_CLASS", $cssClass);
606  $solutiontemplate->setVariable("FEEDBACK", $this->object->prepareTextareaOutput($feedback, true));
607  }
608 
609  $solutiontemplate->setVariable("SOLUTION_OUTPUT", $questionoutput);
610 
611  $solutionoutput = $solutiontemplate->get();
612  if (!$show_question_only) {
613  // get page object output
614  $solutionoutput = $this->getILIASPage($solutionoutput);
615  }
616  return $solutionoutput;
617  }
618 
619  public function getPreview($show_question_only = false, $showInlineFeedback = false)
620  {
621  $solutions = is_object($this->getPreviewSession()) ? (array) $this->getPreviewSession()->getParticipantsSolution() : array();
622 
623  global $DIC; /* @var ILIAS\DI\Container $DIC */
624  if ($DIC['ilBrowser']->isMobile() || $DIC['ilBrowser']->isIpad()) {
625  require_once 'Services/jQuery/classes/class.iljQueryUtil.php';
628  $this->tpl->addJavaScript('./node_modules/@andxor/jquery-ui-touch-punch-fix/jquery.ui.touch-punch.js');
629  }
630  $this->tpl->addJavaScript('Modules/TestQuestionPool/js/ilMatchingQuestion.js');
631  $this->tpl->addCss(ilUtil::getStyleSheetLocation('output', 'test_javascript.css', 'Modules/TestQuestionPool'));
632 
633  $template = new ilTemplate("tpl.il_as_qpl_matching_output.html", true, true, "Modules/TestQuestionPool");
634 
635  foreach ($solutions as $defId => $terms) {
636  foreach ($terms as $termId) {
637  $template->setCurrentBlock("matching_data");
638  $template->setVariable("DEFINITION_ID", $defId);
639  $template->setVariable("TERM_ID", $termId);
640  $template->parseCurrentBlock();
641  }
642  }
643 
644  // shuffle output
645  $terms = $this->object->getTerms();
646  $definitions = $this->object->getDefinitions();
647  switch ($this->object->getShuffle()) {
648  case 1:
649  $seed = $this->object->getShuffler()->getSeed();
650  $this->object->getShuffler()->setSeed($seed . '1');
651  $terms = $this->object->getShuffler()->shuffle($terms);
652  $this->object->getShuffler()->setSeed($seed . '2');
653  $definitions = $this->object->getShuffler()->shuffle($definitions);
654  $this->object->getShuffler()->setSeed($seed);
655  break;
656  case 2:
657  $terms = $this->object->getShuffler()->shuffle($terms);
658  break;
659  case 3:
660  $definitions = $this->object->getShuffler()->shuffle($definitions);
661  break;
662  }
663 
664  // create definitions
665  $counter = 0;
666  foreach ($definitions as $definition) {
667  if (strlen($definition->picture)) {
668  $template->setCurrentBlock("definition_picture");
669  $template->setVariable("DEFINITION_ID", $definition->identifier);
670  $template->setVariable("IMAGE_HREF", $this->object->getImagePathWeb() . $definition->picture);
671  $thumbweb = $this->object->getImagePathWeb() . $this->object->getThumbPrefix() . $definition->picture;
672  $thumb = $this->object->getImagePath() . $this->object->getThumbPrefix() . $definition->picture;
673  if (!@file_exists($thumb)) {
674  $this->object->rebuildThumbnails();
675  }
676  $template->setVariable("THUMBNAIL_HREF", $thumbweb);
677  $template->setVariable("THUMB_ALT", $this->lng->txt("image"));
678  $template->setVariable("THUMB_TITLE", $this->lng->txt("image"));
679  $template->setVariable("TEXT_DEFINITION", (strlen($definition->text)) ? $this->object->prepareTextareaOutput($definition->text, true, true) : '');
680  $template->setVariable("TEXT_PREVIEW", $this->lng->txt('preview'));
681  $template->setVariable("IMG_PREVIEW", ilUtil::getImagePath('enlarge.svg'));
682  $template->parseCurrentBlock();
683  } else {
684  $template->setCurrentBlock("definition_text");
685  $template->setVariable("DEFINITION", $this->object->prepareTextareaOutput($definition->text, true, true));
686  $template->parseCurrentBlock();
687  }
688 
689  $template->setCurrentBlock("droparea");
690  $template->setVariable("ID_DROPAREA", $definition->identifier);
691  $template->setVariable("QUESTION_ID", $this->object->getId());
692  $template->parseCurrentBlock();
693 
694  $template->setCurrentBlock("definition_data");
695  $template->setVariable("DEFINITION_ID", $definition->identifier);
696  $template->parseCurrentBlock();
697  }
698 
699  // create terms
700  $counter = 0;
701  foreach ($terms as $term) {
702  if (strlen($term->picture)) {
703  $template->setCurrentBlock("term_picture");
704  $template->setVariable("TERM_ID", $term->identifier);
705  $template->setVariable("IMAGE_HREF", $this->object->getImagePathWeb() . $term->picture);
706  $thumbweb = $this->object->getImagePathWeb() . $this->object->getThumbPrefix() . $term->picture;
707  $thumb = $this->object->getImagePath() . $this->object->getThumbPrefix() . $term->picture;
708  if (!@file_exists($thumb)) {
709  $this->object->rebuildThumbnails();
710  }
711  $template->setVariable("THUMBNAIL_HREF", $thumbweb);
712  $template->setVariable("THUMB_ALT", $this->lng->txt("image"));
713  $template->setVariable("THUMB_TITLE", $this->lng->txt("image"));
714  $template->setVariable("TEXT_PREVIEW", $this->lng->txt('preview'));
715  $template->setVariable("TEXT_TERM", (strlen($term->text)) ? $this->object->prepareTextareaOutput($term->text, true, true) : '');
716  $template->setVariable("IMG_PREVIEW", ilUtil::getImagePath('enlarge.svg'));
717  $template->parseCurrentBlock();
718  } else {
719  $template->setCurrentBlock("term_text");
720  $template->setVariable("TERM_TEXT", $this->object->prepareTextareaOutput($term->text, true, true));
721  $template->parseCurrentBlock();
722  }
723  $template->setCurrentBlock("draggable");
724  $template->setVariable("ID_DRAGGABLE", $term->identifier);
725  $template->parseCurrentBlock();
726 
727  $template->setCurrentBlock("term_data");
728  $template->setVariable("TERM_ID", $term->identifier);
729  $template->parseCurrentBlock();
730  }
731 
732  $template->setVariable('MATCHING_MODE', $this->object->getMatchingMode());
733 
734  $template->setVariable("RESET_BUTTON", $this->lng->txt("reset_terms"));
735 
736  $template->setVariable("QUESTIONTEXT", $this->object->getQuestionForHTMLOutput());
737 
738  $questionoutput = $template->get();
739 
740  if (!$show_question_only) {
741  // get page object output
742  $questionoutput = $this->getILIASPage($questionoutput);
743  }
744 
745  return $questionoutput;
746  }
747 
753  protected function sortDefinitionsBySolution(array $solution, array $definitions)
754  {
755  $neworder = array();
756  $handled_defintions = array();
757  foreach ($solution as $solution_values) {
758  $id = $solution_values['value2'];
759  if (!isset($handled_defintions[$id])) {
760  $neworder[] = $this->object->getDefinitionWithIdentifier($id);
761  $handled_defintions[$id] = $id;
762  }
763  }
764 
765  foreach ($definitions as $definition) {
769  if (!isset($handled_defintions[$definition->identifier])) {
770  $neworder[] = $definition;
771  }
772  }
773 
774  return $neworder;
775  }
776 
777  public function getPresentationJavascripts()
778  {
779  global $DIC; /* @var ILIAS\DI\Container $DIC */
780 
781  $files = array();
782 
783  if ($DIC['ilBrowser']->isMobile() || $DIC['ilBrowser']->isIpad()) {
784  $files[] = './node_modules/@andxor/jquery-ui-touch-punch-fix/jquery.ui.touch-punch.js';
785  }
786 
787  $files[] = 'Modules/TestQuestionPool/js/ilMatchingQuestion.js';
788 
789  return $files;
790  }
791 
792  // hey: prevPassSolutions - pass will be always available from now on
793  public function getTestOutput($active_id, $pass, $is_postponed = false, $user_post_solution = false, $inlineFeedback = false)
794  // hey.
795  {
796  global $DIC; /* @var ILIAS\DI\Container $DIC */
797  if ($DIC['ilBrowser']->isMobile() || $DIC['ilBrowser']->isIpad()) {
798  require_once 'Services/jQuery/classes/class.iljQueryUtil.php';
801  $this->tpl->addJavaScript('./node_modules/@andxor/jquery-ui-touch-punch-fix/jquery.ui.touch-punch.js');
802  }
803  $this->tpl->addJavaScript('Modules/TestQuestionPool/js/ilMatchingQuestion.js');
804  $this->tpl->addCss(ilUtil::getStyleSheetLocation('output', 'test_javascript.css', 'Modules/TestQuestionPool'));
805 
806  $template = new ilTemplate("tpl.il_as_qpl_matching_output.html", true, true, "Modules/TestQuestionPool");
807 
808  if ($active_id) {
809  // hey: prevPassSolutions - obsolete due to central check
810  #$solutions = NULL;
811  #include_once "./Modules/Test/classes/class.ilObjTest.php";
812  #if (!ilObjTest::_getUsePreviousAnswers($active_id, true))
813  #{
814  # if (is_null($pass)) $pass = ilObjTest::_getPass($active_id);
815  #}
816  // hey.
817  if (is_array($user_post_solution)) {
818  $solutions = array();
819  foreach ($user_post_solution['matching'][$this->object->getId()] as $definition => $term) {
820  array_push($solutions, array("value1" => $term, "value2" => $definition));
821  }
822  } else {
823  // hey: prevPassSolutions - obsolete due to central check
824  $solutions = $this->object->getTestOutputSolutions($active_id, $pass);
825  // hey.
826  }
827 
828  $counter = 0;
829  foreach ($solutions as $idx => $solution_value) {
830  if (($solution_value["value2"] > -1) && ($solution_value["value1"] > -1)) {
831  $template->setCurrentBlock("matching_data");
832  $template->setVariable("TERM_ID", $solution_value["value1"]);
833  $template->setVariable("DEFINITION_ID", $solution_value["value2"]);
834  $template->parseCurrentBlock();
835  }
836 
837  $counter++;
838  }
839  }
840 
841  $terms = $this->object->getTerms();
842  $definitions = $this->object->getDefinitions();
843  switch ($this->object->getShuffle()) {
844  case 1:
845  $seed = $this->object->getShuffler()->getSeed();
846  $this->object->getShuffler()->setSeed($seed . '1');
847  $terms = $this->object->getShuffler()->shuffle($terms);
848  if (count($solutions)) {
849  $definitions = $this->sortDefinitionsBySolution($solutions, $definitions);
850  } else {
851  $this->object->getShuffler()->setSeed($seed . '2');
852  $definitions = $this->object->getShuffler()->shuffle($definitions);
853  }
854  $this->object->getShuffler()->setSeed($seed);
855  break;
856  case 2:
857  $terms = $this->object->getShuffler()->shuffle($terms);
858  break;
859  case 3:
860  if (count($solutions)) {
861  $definitions = $this->sortDefinitionsBySolution($solutions, $definitions);
862  } else {
863  $definitions = $this->object->getShuffler()->shuffle($definitions);
864  }
865  break;
866  }
867 
868  // create definitions
869  $counter = 0;
870  foreach ($definitions as $definition) {
871  if (strlen($definition->picture)) {
872  $template->setCurrentBlock("definition_picture");
873  $template->setVariable("DEFINITION_ID", $definition->identifier);
874  $template->setVariable("IMAGE_HREF", $this->object->getImagePathWeb() . $definition->picture);
875  $thumbweb = $this->object->getImagePathWeb() . $this->object->getThumbPrefix() . $definition->picture;
876  $thumb = $this->object->getImagePath() . $this->object->getThumbPrefix() . $definition->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_DEFINITION", (strlen($definition->text)) ? $this->object->prepareTextareaOutput($definition->text, true, true) : '');
884  $template->setVariable("TEXT_PREVIEW", $this->lng->txt('preview'));
885  $template->setVariable("IMG_PREVIEW", ilUtil::getImagePath('enlarge.svg'));
886  $template->parseCurrentBlock();
887  } else {
888  $template->setCurrentBlock("definition_text");
889  $template->setVariable("DEFINITION", $this->object->prepareTextareaOutput($definition->text, true, true));
890  $template->parseCurrentBlock();
891  }
892 
893  $template->setCurrentBlock("droparea");
894  $template->setVariable("ID_DROPAREA", $definition->identifier);
895  $template->setVariable("QUESTION_ID", $this->object->getId());
896  $template->parseCurrentBlock();
897 
898  $template->setCurrentBlock("definition_data");
899  $template->setVariable("DEFINITION_ID", $definition->identifier);
900  $template->parseCurrentBlock();
901  }
902 
903  // create terms
904  $counter = 0;
905  foreach ($terms as $term) {
906  if (strlen($term->picture)) {
907  $template->setCurrentBlock("term_picture");
908  $template->setVariable("TERM_ID", $term->identifier);
909  $template->setVariable("IMAGE_HREF", $this->object->getImagePathWeb() . $term->picture);
910  $thumbweb = $this->object->getImagePathWeb() . $this->object->getThumbPrefix() . $term->picture;
911  $thumb = $this->object->getImagePath() . $this->object->getThumbPrefix() . $term->picture;
912  if (!@file_exists($thumb)) {
913  $this->object->rebuildThumbnails();
914  }
915  $template->setVariable("THUMBNAIL_HREF", $thumbweb);
916  $template->setVariable("THUMB_ALT", $this->lng->txt("image"));
917  $template->setVariable("THUMB_TITLE", $this->lng->txt("image"));
918  $template->setVariable("TEXT_PREVIEW", $this->lng->txt('preview'));
919  $template->setVariable("TEXT_TERM", (strlen($term->text)) ? $this->object->prepareTextareaOutput($term->text, true, true) : '');
920  $template->setVariable("IMG_PREVIEW", ilUtil::getImagePath('enlarge.svg'));
921  $template->parseCurrentBlock();
922  } else {
923  $template->setCurrentBlock("term_text");
924  $template->setVariable("TERM_TEXT", $this->object->prepareTextareaOutput($term->text, true, true));
925  $template->parseCurrentBlock();
926  }
927  $template->setCurrentBlock("draggable");
928  $template->setVariable("ID_DRAGGABLE", $term->identifier);
929  $template->parseCurrentBlock();
930 
931  $template->setCurrentBlock('term_data');
932  $template->setVariable('TERM_ID', $term->identifier);
933  $template->parseCurrentBlock();
934  }
935 
936  $template->setVariable('MATCHING_MODE', $this->object->getMatchingMode());
937 
938  $template->setVariable("RESET_BUTTON", $this->lng->txt("reset_terms"));
939 
940  $template->setVariable("QUESTIONTEXT", $this->object->getQuestionForHTMLOutput());
941 
942  return $this->outQuestionPage("", $is_postponed, $active_id, $template->get());
943  }
944 
948  public function checkInput()
949  {
950  if ((!$_POST["title"]) or (!$_POST["author"]) or (!$_POST["question"])) {
951  return false;
952  }
953  return true;
954  }
955 
956  public function getSpecificFeedbackOutput($userSolution)
957  {
958  $matches = array_values($this->object->matchingpairs);
959 
960  if (!$this->object->feedbackOBJ->specificAnswerFeedbackExists()) {
961  return '';
962  }
963 
964  $feedback = '<table class="test_specific_feedback"><tbody>';
965 
966  foreach ($matches as $idx => $ans) {
967  if (!isset($userSolution[$ans->definition->identifier])) {
968  continue;
969  }
970 
971  if (!is_array($userSolution[$ans->definition->identifier])) {
972  continue;
973  }
974 
975  if (!in_array($ans->term->identifier, $userSolution[$ans->definition->identifier])) {
976  continue;
977  }
978 
979  $fb = $this->object->feedbackOBJ->getSpecificAnswerFeedbackTestPresentation(
980  $this->object->getId(),
981  0,
982  $idx
983  );
984  $feedback .= '<tr><td>"' . $ans->definition->text . '"&nbsp;' . $this->lng->txt("matches") . '&nbsp;"';
985  $feedback .= $ans->term->text . '"</td><td>';
986  $feedback .= $fb . '</td> </tr>';
987  }
988 
989  $feedback .= '</tbody></table>';
990  return $this->object->prepareTextareaOutput($feedback, true);
991  }
992 
1003  {
1004  return array();
1005  }
1006 
1017  {
1018  return array();
1019  }
1020 
1029  public function getAggregatedAnswersView($relevant_answers)
1030  {
1031  return ''; //print_r($relevant_answers,true);
1032  }
1033 
1034  private function isCorrectMatching($pair, $definition, $term)
1035  {
1036  if (!($pair->points > 0)) {
1037  return false;
1038  }
1039 
1040  if (!is_object($term)) {
1041  return false;
1042  }
1043 
1044  if ($pair->definition->identifier != $definition->identifier) {
1045  return false;
1046  }
1047 
1048  if ($pair->term->identifier != $term->identifier) {
1049  return false;
1050  }
1051 
1052  return true;
1053  }
1054 
1055  protected function getAnswerStatisticImageHtml($picture)
1056  {
1057  $thumbweb = $this->object->getImagePathWeb() . $this->object->getThumbPrefix() . $picture;
1058  return '<img src="' . $thumbweb . '" alt="' . $picture . '" title="' . $picture . '"/>';
1059  }
1060 
1061  protected function getAnswerStatisticMatchingElemHtml($elem)
1062  {
1063  $html = '';
1064 
1065  if (strlen($elem->text)) {
1066  $html .= $elem->text;
1067  }
1068 
1069  if (strlen($elem->picture)) {
1070  $html .= $this->getAnswerStatisticImageHtml($elem->picture);
1071  }
1072 
1073  return $html;
1074  }
1075 
1076  public function getAnswersFrequency($relevantAnswers, $questionIndex)
1077  {
1078  $answersByActiveAndPass = array();
1079 
1080  foreach ($relevantAnswers as $row) {
1081  $key = $row['active_fi'] . ':' . $row['pass'];
1082 
1083  if (!isset($answersByActiveAndPass[$key])) {
1084  $answersByActiveAndPass[$key] = array();
1085  }
1086 
1087  $answersByActiveAndPass[$key][$row['value1']] = $row['value2'];
1088  }
1089 
1090  $answers = array();
1091 
1092  foreach ($answersByActiveAndPass as $key => $matchingPairs) {
1093  foreach ($matchingPairs as $termId => $defId) {
1094  $hash = md5($termId . ':' . $defId);
1095 
1096  if (!isset($answers[$hash])) {
1097  $termHtml = $this->getAnswerStatisticMatchingElemHtml(
1098  $this->object->getTermWithIdentifier($termId)
1099  );
1100 
1101  $defHtml = $this->getAnswerStatisticMatchingElemHtml(
1102  $this->object->getDefinitionWithIdentifier($defId)
1103  );
1104 
1105  $answers[$hash] = array(
1106  'answer' => $termHtml . $defHtml,
1107  'term' => $termHtml,
1108  'definition' => $defHtml,
1109  'frequency' => 0
1110  );
1111  }
1112 
1113  $answers[$hash]['frequency']++;
1114  }
1115  }
1116 
1117  return $answers;
1118  }
1119 
1127  public function getAnswerFrequencyTableGUI($parentGui, $parentCmd, $relevantAnswers, $questionIndex)
1128  {
1129  require_once 'Modules/TestQuestionPool/classes/tables/class.ilMatchingQuestionAnswerFreqStatTableGUI.php';
1130 
1131  $table = new ilMatchingQuestionAnswerFreqStatTableGUI($parentGui, $parentCmd, $this->object);
1132  $table->setQuestionIndex($questionIndex);
1133  $table->setData($this->getAnswersFrequency($relevantAnswers, $questionIndex));
1134  $table->initColumns();
1135 
1136  return $table;
1137  }
1138 
1140  {
1141  require_once 'Modules/TestQuestionPool/classes/forms/class.ilAssMatchingPairCorrectionsInputGUI.php';
1142  $pairs = new ilAssMatchingPairCorrectionsInputGUI($this->lng->txt('matching_pairs'), 'pairs');
1143  $pairs->setRequired(true);
1144  $pairs->setTerms($this->object->getTerms());
1145  $pairs->setDefinitions($this->object->getDefinitions());
1146  $pairs->setPairs($this->object->getMatchingPairs());
1147  $form->addItem($pairs);
1148  }
1149 
1154  {
1155  $pairs = $form->getItemByPostVar('pairs')->getPairs();
1156 
1157  foreach ($this->object->getMatchingPairs() as $idx => $matchingPair) {
1158  $matchingPair->points = (float) $pairs[$idx]->points;
1159  }
1160  }
1161 }
Class for matching question terms.
static prepareFormOutput($a_str, $a_strip=false)
prepares string output for html forms public
hasCorrectSolution($activeId, $passIndex)
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.
setHideImages($a_hide)
Set hide images.
saveCorrectionsFormProperties(ilPropertyFormGUI $form)
$errors
Definition: imgupload.php:49
This class represents a property form user interface.
static getStyleSheetLocation($mode="output", $a_css_name="", $a_css_location="")
get full style sheet file name (path inclusive) of current user
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...
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).
getQuestionTemplate()
get question template
Matching question GUI representation.
populateTaxonomyFormSection(ilPropertyFormGUI $form)
getUseIntermediateSolution()
Get if intermediate solution should be used for solution output.
$index
Definition: metadata.php:128
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
writeAnswerSpecificPostData(ilPropertyFormGUI $form)
Extracts the answer specific values from $_POST and applies them to the data object.
if($format !==null) $name
Definition: metadata.php:230
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
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.
global $DIC
Definition: goto.php:24
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)
static signFile($path_to_file)
getPreview($show_question_only=false, $showInlineFeedback=false)
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
static initjQueryUI($a_tpl=null)
inits and adds the jQuery-UI JS-File to the global template (see included_components.txt for included components)
outQuestionPage($a_temp_var, $a_postponed=false, $active_id="", $html="", $inlineFeedbackEnabled=false)
output question page
static initjQuery(ilGlobalTemplateInterface $a_tpl=null)
inits and adds the jQuery JS-File to the global or a passed template
__construct(Container $dic, ilPlugin $plugin)
getAnswersFrequency($relevantAnswers, $questionIndex)
Class for matching question definitions.
Interface ilGuiAnswerScoringAdjustable.
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...
getGenericFeedbackOutput($active_id, $pass)
Returns the answer specific feedback for the question.
Interface ilGuiQuestionScoringAdjustable.
$_POST["username"]
setRequired($a_required)
Set Required.
$i
Definition: metadata.php:24
This class represents a key value pair wizard property in a property form.
addQuestionFormCommandButtons($form)
Add the command buttons of a question properties form.