ILIAS  release_7 Revision v7.30-3-g800a261c036
class.assClozeTestGUI.php
Go to the documentation of this file.
1<?php
2/* Copyright (c) 1998-2013 ILIAS open source, Extended GPL, see docs/LICENSE */
3
4require_once './Modules/TestQuestionPool/classes/class.assQuestionGUI.php';
5require_once './Modules/TestQuestionPool/interfaces/interface.ilGuiQuestionScoringAdjustable.php';
6require_once './Modules/TestQuestionPool/interfaces/interface.ilGuiAnswerScoringAdjustable.php';
7
24{
25 const OLD_CLOZE_TEST_UI = false;
26
30 private $gapIndex;
31
37 public function __construct($id = -1)
38 {
40 include_once "./Modules/TestQuestionPool/classes/class.assClozeTest.php";
41 $this->object = new assClozeTest();
42 if ($id >= 0) {
43 $this->object->loadFromDb($id);
44 }
45 }
46
47 public function getCommand($cmd)
48 {
49 if (preg_match("/^(removegap|addgap)_(\d+)$/", $cmd, $matches)) {
50 $cmd = $matches[1];
51 $this->gapIndex = $matches[2];
52 }
53 return $cmd;
54 }
55
59 protected function writePostData($always = false)
60 {
61 $hasErrors = (!$always) ? $this->editQuestion(true) : false;
62 if (!$hasErrors) {
63 require_once 'Services/Form/classes/class.ilPropertyFormGUI.php';
64 $_POST['cloze_text'] = $this->removeIndizesFromGapText($_POST['cloze_text']);
65 $this->object->setQuestion($_POST['question']);
66
68 $this->object->setClozeText($_POST["cloze_text"]);
70 //$this->object->flushGaps();
73 return 0;
74 }
75
76 $_POST['cloze_text'] = $this->applyIndizesToGapText($_POST['cloze_text']);
77 return 1;
78 }
79
81 {
82 if (is_array($_POST['gap'])) {
83 if ($this->ctrl->getCmd() != 'createGaps') {
84 $this->object->clearGapAnswers();
85 }
86
87 foreach ($_POST['gap'] as $idx => $hidden) {
88 $clozetype = $_POST['clozetype_' . $idx];
89
90 $this->object->setGapType($idx, $clozetype);
91
92 switch ($clozetype) {
93 case CLOZE_TEXT:
94
95 $this->object->setGapShuffle($idx, 0);
96
97 if ($this->ctrl->getCmd() != 'createGaps') {
98 if (is_array($_POST['gap_' . $idx]['answer'])) {
99 foreach ($_POST['gap_' . $idx]['answer'] as $order => $value) {
100 $this->object->addGapAnswer($idx, $order, $value);
101 }
102 } else {
103 $this->object->addGapAnswer($idx, 0, '');
104 }
105 }
106
107 if (is_array($_POST['gap_' . $idx]['points'])) {
108 foreach ($_POST['gap_' . $idx]['points'] as $order => $value) {
109 $this->object->setGapAnswerPoints($idx, $order, $value);
110 }
111 }
112
113 if (array_key_exists('gap_' . $idx . '_gapsize', $_POST)) {
114 $this->object->setGapSize($idx, $order, $_POST['gap_' . $idx . '_gapsize']);
115 }
116
117 break;
118
119 case CLOZE_SELECT:
120
121 $this->object->setGapShuffle($idx, (int) (isset($_POST["shuffle_$idx"]) && $_POST["shuffle_$idx"]));
122
123 if ($this->ctrl->getCmd() != 'createGaps') {
124 if (is_array($_POST['gap_' . $idx]['answer'])) {
125 foreach ($_POST['gap_' . $idx]['answer'] as $order => $value) {
126 $this->object->addGapAnswer($idx, $order, $value);
127 }
128 } else {
129 $this->object->addGapAnswer($idx, 0, '');
130 }
131 }
132
133 if (is_array($_POST['gap_' . $idx]['points'])) {
134 foreach ($_POST['gap_' . $idx]['points'] as $order => $value) {
135 $this->object->setGapAnswerPoints($idx, $order, $value);
136 }
137 }
138 break;
139
140 case CLOZE_NUMERIC:
141
142 $this->object->setGapShuffle($idx, 0);
143
144 $gap = $this->object->getGap($idx);
145 if (!$gap) {
146 break;
147 }
148
149 $this->object->getGap($idx)->clearItems();
150
151 if (array_key_exists('gap_' . $idx . '_numeric', $_POST)) {
152 if ($this->ctrl->getCmd() != 'createGaps') {
153 $this->object->addGapAnswer(
154 $idx,
155 0,
156 str_replace(",", ".", $_POST['gap_' . $idx . '_numeric'])
157 );
158 }
159
160 $this->object->setGapAnswerLowerBound(
161 $idx,
162 0,
163 str_replace(",", ".", $_POST['gap_' . $idx . '_numeric_lower'])
164 );
165
166 $this->object->setGapAnswerUpperBound(
167 $idx,
168 0,
169 str_replace(",", ".", $_POST['gap_' . $idx . '_numeric_upper'])
170 );
171
172 $this->object->setGapAnswerPoints($idx, 0, $_POST['gap_' . $idx . '_numeric_points']);
173 } else {
174 if ($this->ctrl->getCmd() != 'createGaps') {
175 $this->object->addGapAnswer($idx, 0, '');
176 }
177
178 $this->object->setGapAnswerLowerBound($idx, 0, '');
179
180 $this->object->setGapAnswerUpperBound($idx, 0, '');
181 }
182
183 if (array_key_exists('gap_' . $idx . '_gapsize', $_POST)) {
184 $this->object->setGapSize($idx, $order, $_POST['gap_' . $idx . '_gapsize']);
185 }
186 break;
187 }
188 $assClozeGapCombinationObject = new assClozeGapCombination();
189 $assClozeGapCombinationObject->clearGapCombinationsFromDb($this->object->getId());
190 if (
191 isset($_POST['gap_combination']) &&
192 is_array($_POST['gap_combination']) &&
193 count($_POST['gap_combination']) > 0
194 ) {
195 $assClozeGapCombinationObject->saveGapCombinationToDb(
196 $this->object->getId(),
197 $_POST['gap_combination'],
198 $_POST['gap_combination_values']
199 );
200 }
201 }
202 if ($this->ctrl->getCmd() != 'createGaps') {
203 $this->object->updateClozeTextFromGaps();
204 }
205 }
206 }
207
209 {
210 $this->object->setClozeText($_POST['cloze_text']);
211 $this->object->setTextgapRating($_POST["textgap_rating"]);
212 $this->object->setIdenticalScoring($_POST["identical_scoring"]);
213 $this->object->setFixedTextLength($_POST["fixedTextLength"]);
214 }
215
221 public function editQuestion($checkonly = false)
222 {
223 $save = $this->isSaveCommand();
224 $this->getQuestionTemplate();
225
226 include_once("./Services/Form/classes/class.ilPropertyFormGUI.php");
227 $form = new ilPropertyFormGUI();
228 $this->editForm = $form;
229
230 $form->setFormAction($this->ctrl->getFormAction($this));
231 $form->setTitle($this->outQuestionType());
232 $form->setMultipart(false);
233 $form->setTableWidth("100%");
234 $form->setId("assclozetest");
235
236 // title, author, description, question, working time (assessment mode)
237 $this->addBasicQuestionFormProperties($form);
239 $this->populateAnswerSpecificFormPart($form);
240 $this->populateTaxonomyFormSection($form);
241
242 $this->addQuestionFormCommandButtons($form);
243
244 $errors = false;
245
246 if ($save) {
247 $form->setValuesByPost();
248 $errors = !$form->checkInput();
249 $form->setValuesByPost(); // again, because checkInput now performs the whole stripSlashes handling and we
250 // need this if we don't want to have duplication of backslashes
251 if ($errors) {
252 $checkonly = false;
253 }
254 }
255
256 if (!$checkonly) {
257 $this->tpl->setVariable("QUESTION_DATA", $form->getHTML());
258 }
259 return $errors;
260 }
261
262 public function addBasicQuestionFormProperties($form)
263 {
264 // title
265 $title = new ilTextInputGUI($this->lng->txt("title"), "title");
266 $title->setMaxLength(100);
267 $title->setValue($this->object->getTitle());
268 $title->setRequired(true);
269 $form->addItem($title);
270
271 if (!$this->object->getSelfAssessmentEditingMode()) {
272 // author
273 $author = new ilTextInputGUI($this->lng->txt("author"), "author");
274 $author->setValue($this->object->getAuthor());
275 $author->setRequired(true);
276 $form->addItem($author);
277
278 // description
279 $description = new ilTextInputGUI($this->lng->txt("description"), "comment");
280 $description->setValue($this->object->getComment());
281 $description->setRequired(false);
282 $form->addItem($description);
283 } else {
284 // author as hidden field
285 $hi = new ilHiddenInputGUI("author");
286 $author = ilUtil::prepareFormOutput($this->object->getAuthor());
287 if (trim($author) == "") {
288 $author = "-";
289 }
290 $hi->setValue($author);
291 $form->addItem($hi);
292 }
293
294 // lifecycle
295 $lifecycle = new ilSelectInputGUI($this->lng->txt('qst_lifecycle'), 'lifecycle');
296 $lifecycle->setOptions($this->object->getLifecycle()->getSelectOptions($this->lng));
297 $lifecycle->setValue($this->object->getLifecycle()->getIdentifier());
298 $form->addItem($lifecycle);
299
300 // questiontext
301 $question = new ilTextAreaInputGUI($this->lng->txt("question"), "question");
302 $question->setValue($this->object->getQuestion());
303 $question->setRequired(true);
304 $question->setRows(10);
305 $question->setCols(80);
306 if (!$this->object->getSelfAssessmentEditingMode()) {
307 if ($this->object->getAdditionalContentEditingMode() == assQuestion::ADDITIONAL_CONTENT_EDITING_MODE_RTE) {
308 $question->setUseRte(true);
309 include_once "./Services/AdvancedEditing/classes/class.ilObjAdvancedEditing.php";
310 $question->setRteTags(ilObjAdvancedEditing::_getUsedHTMLTags("assessment"));
311 $question->addPlugin("latex");
312 $question->addButton("latex");
313 $question->addButton("pastelatex");
314 $question->setRTESupport($this->object->getId(), "qpl", "assessment");
315 }
316 } else {
317 require_once 'Modules/TestQuestionPool/classes/questions/class.ilAssSelfAssessmentQuestionFormatter.php';
319 $question->setUseTagsForRteOnly(false);
320 }
321 $form->addItem($question);
322
323 if (!$this->object->getSelfAssessmentEditingMode()) {
324 // duration
325 $duration = new ilDurationInputGUI($this->lng->txt("working_time"), "Estimated");
326 $duration->setShowHours(true);
327 $duration->setShowMinutes(true);
328 $duration->setShowSeconds(true);
329 $ewt = $this->object->getEstimatedWorkingTime();
330 $duration->setHours($ewt["h"]);
331 $duration->setMinutes($ewt["m"]);
332 $duration->setSeconds($ewt["s"]);
333 $duration->setRequired(false);
334 $form->addItem($duration);
335 } else {
336 // number of tries
337 if (strlen($this->object->getNrOfTries())) {
338 $nr_tries = $this->object->getNrOfTries();
339 } else {
340 $nr_tries = $this->object->getDefaultNrOfTries();
341 }
342 /*if ($nr_tries <= 0)
343 {
344 $nr_tries = 1;
345 }*/
346
347 if ($nr_tries < 0) {
348 $nr_tries = 0;
349 }
350
351 $ni = new ilNumberInputGUI($this->lng->txt("qst_nr_of_tries"), "nr_of_tries");
352 $ni->setValue($nr_tries);
353 //$ni->setMinValue(1);
354 $ni->setMinValue(0);
355 $ni->setSize(5);
356 $ni->setMaxLength(5);
357 $ni->setRequired(true);
358 $form->addItem($ni);
359 }
360 }
361
363 {
364 // cloze text
365 $cloze_text = new ilTextAreaInputGUI($this->lng->txt("cloze_text"), 'cloze_text');
366 $cloze_text->setRequired(true);
367 $cloze_text->setValue($this->applyIndizesToGapText($this->object->getClozeText()));
368 $cloze_text->setInfo($this->lng->txt("close_text_hint"));
369 $cloze_text->setRows(10);
370 $cloze_text->setCols(80);
371 if (!$this->object->getSelfAssessmentEditingMode()) {
372 if ($this->object->getAdditionalContentEditingMode() == assQuestion::ADDITIONAL_CONTENT_EDITING_MODE_RTE) {
373 $cloze_text->setUseRte(true);
374 include_once "./Services/AdvancedEditing/classes/class.ilObjAdvancedEditing.php";
375 $cloze_text->setRteTags(ilObjAdvancedEditing::_getUsedHTMLTags("assessment"));
376 $cloze_text->addPlugin("latex");
377 $cloze_text->addButton("latex");
378 $cloze_text->addButton("pastelatex");
379 }
380 } else {
381 require_once 'Modules/TestQuestionPool/classes/questions/class.ilAssSelfAssessmentQuestionFormatter.php';
383 $cloze_text->setUseTagsForRteOnly(false);
384 }
385 $cloze_text->setRTESupport($this->object->getId(), "qpl", "assessment");
386 $form->addItem($cloze_text);
387
388 $tpl = new ilTemplate("tpl.il_as_qpl_cloze_gap_button_code.html", true, true, "Modules/TestQuestionPool");
389
390 $button = new ilCustomInputGUI('&nbsp;', '');
391 require_once 'Services/UIComponent/SplitButton/classes/class.ilSplitButtonGUI.php';
392 require_once 'Services/UIComponent/Button/classes/class.ilJsLinkButton.php';
393 $action_button = ilSplitButtonGUI::getInstance();
394
395 $sb_text_gap = ilJsLinkButton::getInstance();
396 $sb_text_gap->setCaption('text_gap');
397 $sb_text_gap->setName('gapbutton');
398 $sb_text_gap->setId('gaptrigger_text');
399 $action_button->setDefaultButton($sb_text_gap);
400
401 $sb_sel_gap = ilJsLinkButton::getInstance();
402 $sb_sel_gap->setCaption('select_gap');
403 $sb_sel_gap->setName('gapbutton_select');
404 $sb_sel_gap->setId('gaptrigger_select');
405 $action_button->addMenuItem(new ilButtonToSplitButtonMenuItemAdapter($sb_sel_gap));
406
407 $sb_num_gap = ilJsLinkButton::getInstance();
408 $sb_num_gap->setCaption('numeric_gap');
409 $sb_num_gap->setName('gapbutton_numeric');
410 $sb_num_gap->setId('gaptrigger_numeric');
411 $action_button->addMenuItem(new ilButtonToSplitButtonMenuItemAdapter($sb_num_gap));
412
413 $tpl->setVariable('BUTTON', $action_button->render());
414 $tpl->parseCurrentBlock();
415
416 $button->setHtml($tpl->get());
417 $form->addItem($button);
418
419 // text rating
420 if (!$this->object->getSelfAssessmentEditingMode()) {
421 $textrating = new ilSelectInputGUI($this->lng->txt("text_rating"), "textgap_rating");
422 $text_options = array(
423 "ci" => $this->lng->txt("cloze_textgap_case_insensitive"),
424 "cs" => $this->lng->txt("cloze_textgap_case_sensitive"),
425 "l1" => sprintf($this->lng->txt("cloze_textgap_levenshtein_of"), "1"),
426 "l2" => sprintf($this->lng->txt("cloze_textgap_levenshtein_of"), "2"),
427 "l3" => sprintf($this->lng->txt("cloze_textgap_levenshtein_of"), "3"),
428 "l4" => sprintf($this->lng->txt("cloze_textgap_levenshtein_of"), "4"),
429 "l5" => sprintf($this->lng->txt("cloze_textgap_levenshtein_of"), "5")
430 );
431 $textrating->setOptions($text_options);
432 $textrating->setValue($this->object->getTextgapRating());
433 $form->addItem($textrating);
434
435 // text field length
436 $fixedTextLength = new ilNumberInputGUI($this->lng->txt("cloze_fixed_textlength"), "fixedTextLength");
437 $ftl = $this->object->getFixedTextLength();
438
439 $fixedTextLength->setValue($ftl > 0 ? $ftl : '');
440 $fixedTextLength->setMinValue(0);
441 $fixedTextLength->setSize(3);
442 $fixedTextLength->setMaxLength(6);
443 $fixedTextLength->setInfo($this->lng->txt('cloze_fixed_textlength_description'));
444 $fixedTextLength->setRequired(false);
445 $form->addItem($fixedTextLength);
446
447 // identical scoring
448 $identical_scoring = new ilCheckboxInputGUI($this->lng->txt("identical_scoring"), "identical_scoring");
449 $identical_scoring->setValue(1);
450 $identical_scoring->setChecked($this->object->getIdenticalScoring());
451 $identical_scoring->setInfo($this->lng->txt('identical_scoring_desc'));
452 $identical_scoring->setRequired(false);
453 $form->addItem($identical_scoring);
454 }
455 return $form;
456 }
457
459 {
460 if (self::OLD_CLOZE_TEST_UI) {
461 for ($gapCounter = 0; $gapCounter < $this->object->getGapCount(); $gapCounter++) {
462 $this->populateGapFormPart($form, $gapCounter);
463 }
464 return $form;
465 } else {
466 require_once 'Modules/TestQuestionPool/classes/Form/class.ilClozeGapInputBuilderGUI.php';
467 $json = $this->populateJSON();
468 $assClozeGapCombinationObject = new assClozeGapCombination();
469 $combination_exists = $assClozeGapCombinationObject->combinationExistsForQid($this->object->id);
470 if ($combination_exists) {
471 $combinations = $assClozeGapCombinationObject->loadFromDb($this->object->id);
472 }
473 $new_builder = new ilClozeGapInputBuilderGUI();
474 $header = new ilFormSectionHeaderGUI();
475 $form->addItem($header);
476 $new_builder->setValueByArray($json);
477 $new_builder->setValueCombinationFromDb($combinations);
478 $form->addItem($new_builder);
479 return $form;
480 }
481 }
482
483 protected function populateJSON()
484 {
485 $gap = $this->object->getGaps();
486 $array = array();
487 if ($gap == null) {
488 return $array;
489 }
490 $translate_type = array('text','select','numeric');
491 $i = 0;
492 foreach ($gap as $content) {
493 $shuffle = false;
494 $value = $content->getItemsRaw();
495 $items = array();
496 for ($j = 0;$j < count($value);$j++) {
497 if ($content->isNumericGap()) {
498 $items[$j] = array(
499 'answer' => $value[$j]->getAnswerText(),
500 'lower' => $value[$j]->getLowerBound(),
501 'upper' => $value[$j]->getUpperBound(),
502 'points' => $value[$j]->getPoints(),
503 'error' => false
504 );
505 } else {
506 $items[$j] = array(
507 'answer' => $this->escapeTemplatePlaceholders($value[$j]->getAnswerText()),
508 'points' => $value[$j]->getPoints(),
509 'error' => false
510 );
511
512 if ($content->isSelectGap()) {
513 $shuffle = $content->getShuffle();
514 }
515 }
516 }
517 $answers[$i] = array(
518 'type' => $translate_type[$content->getType()] ,
519 'values' => $items ,
520 'shuffle' => $shuffle,
521 'text_field_length' => $content->getGapSize() > 0 ? $content->getGapSize() : '',
522 'used_in_gap_combination' => true);
523 $i++;
524 }
525 return $answers;
526 }
538 protected function populateGapFormPart($form, $gapCounter)
539 {
540 $gap = $this->object->getGap($gapCounter);
541
542 if ($gap == null) {
543 return $form;
544 }
545
546 $header = new ilFormSectionHeaderGUI();
547 $header->setTitle($this->lng->txt("gap") . " " . ($gapCounter + 1));
548 $form->addItem($header);
549
550 $gapcounter = new ilHiddenInputGUI("gap[$gapCounter]");
551 $gapcounter->setValue($gapCounter);
552 $form->addItem($gapcounter);
553
554 $gaptype = new ilSelectInputGUI($this->lng->txt('type'), "clozetype_$gapCounter");
555 $options = array(
556 0 => $this->lng->txt("text_gap"),
557 1 => $this->lng->txt("select_gap"),
558 2 => $this->lng->txt("numeric_gap")
559 );
560 $gaptype->setOptions($options);
561 $gaptype->setValue($gap->getType());
562 $form->addItem($gaptype);
563
564 if ($gap->getType() == CLOZE_TEXT) {
565 $this->populateGapSizeFormPart($form, $gap, $gapCounter);
566
567 if (count($gap->getItemsRaw()) == 0) {
568 $gap->addItem(new assAnswerCloze("", 0, 0));
569 }
570 $this->populateTextGapFormPart($form, $gap, $gapCounter);
571 } elseif ($gap->getType() == CLOZE_SELECT) {
572 if (count($gap->getItemsRaw()) == 0) {
573 $gap->addItem(new assAnswerCloze("", 0, 0));
574 }
575 $this->populateSelectGapFormPart($form, $gap, $gapCounter);
576 } elseif ($gap->getType() == CLOZE_NUMERIC) {
577 $this->populateGapSizeFormPart($form, $gap, $gapCounter);
578
579 if (count($gap->getItemsRaw()) == 0) {
580 $gap->addItem(new assAnswerCloze("", 0, 0));
581 }
582 foreach ($gap->getItemsRaw() as $item) {
583 $this->populateNumericGapFormPart($form, $item, $gapCounter);
584 }
585 }
586 return $form;
587 }
588
594 protected function populateGapSizeFormPart($form, $gap, $gapCounter)
595 {
596 $gapSizeFormItem = new ilNumberInputGUI($this->lng->txt('cloze_fixed_textlength'), "gap_" . $gapCounter . '_gapsize');
597
598 $gapSizeFormItem->allowDecimals(false);
599 $gapSizeFormItem->setMinValue(0);
600 $gapSizeFormItem->setSize(3);
601 $gapSizeFormItem->setMaxLength(6);
602 $gapSizeFormItem->setInfo($this->lng->txt('cloze_gap_size_info'));
603 $gapSizeFormItem->setValue($gap->getGapSize());
604 $form->addItem($gapSizeFormItem);
605
606 return $form;
607 }
608
621 protected function populateSelectGapFormPart($form, $gap, $gapCounter)
622 {
623 include_once "./Modules/TestQuestionPool/classes/class.ilAnswerWizardInputGUI.php";
624 include_once "./Modules/TestQuestionPool/classes/class.assAnswerCloze.php";
625 $values = new ilAnswerWizardInputGUI($this->lng->txt("values"), "gap_" . $gapCounter . "");
626 $values->setRequired(true);
627 $values->setQuestionObject($this->object);
628 $values->setSingleline(true);
629 $values->setAllowMove(false);
630
631 $values->setValues($gap->getItemsRaw());
632 $form->addItem($values);
633
634 // shuffle
635 $shuffle = new ilCheckboxInputGUI($this->lng->txt("shuffle_answers"), "shuffle_" . $gapCounter . "");
636 $shuffle->setValue(1);
637 $shuffle->setChecked($gap->getShuffle());
638 $shuffle->setRequired(false);
639 $form->addItem($shuffle);
640 return $form;
641 }
642
654 protected function populateTextGapFormPart($form, $gap, $gapCounter)
655 {
656 // Choices
657 include_once "./Modules/TestQuestionPool/classes/class.ilAnswerWizardInputGUI.php";
658 include_once "./Modules/TestQuestionPool/classes/class.assAnswerCloze.php";
659 $values = new ilAnswerWizardInputGUI($this->lng->txt("values"), "gap_" . $gapCounter . "");
660 $values->setRequired(true);
661 $values->setQuestionObject($this->object);
662 $values->setSingleline(true);
663 $values->setAllowMove(false);
664 $values->setValues($gap->getItemsRaw());
665 $form->addItem($values);
666
667 if ($this->object->getFixedTextLength() > 0) {
668 $values->setSize($this->object->getFixedTextLength());
669 $values->setMaxLength($this->object->getFixedTextLength());
670 }
671
672 return $form;
673 }
674
686 protected function populateNumericGapFormPart($form, $gap, $gapCounter)
687 {
688 // #8944: the js-based ouput in self-assessment cannot support formulas
689 if (!$this->object->getSelfAssessmentEditingMode()) {
690 $value = new ilFormulaInputGUI($this->lng->txt('value'), "gap_" . $gapCounter . "_numeric");
691 $value->setInlineStyle('text-align: right;');
692
693 $lowerbound = new ilFormulaInputGUI($this->lng->txt('range_lower_limit'), "gap_" . $gapCounter . "_numeric_lower");
694 $lowerbound->setInlineStyle('text-align: right;');
695
696 $upperbound = new ilFormulaInputGUI($this->lng->txt('range_upper_limit'), "gap_" . $gapCounter . "_numeric_upper");
697 $upperbound->setInlineStyle('text-align: right;');
698 } else {
699 $value = new ilNumberInputGUI($this->lng->txt('value'), "gap_" . $gapCounter . "_numeric");
700 $value->allowDecimals(true);
701
702 $lowerbound = new ilNumberInputGUI($this->lng->txt('range_lower_limit'), "gap_" . $gapCounter . "_numeric_lower");
703 $lowerbound->allowDecimals(true);
704
705 $upperbound = new ilNumberInputGUI($this->lng->txt('range_upper_limit'), "gap_" . $gapCounter . "_numeric_upper");
706 $upperbound->allowDecimals(true);
707 }
708
709 $value->setSize(10);
710 $value->setValue(ilUtil::prepareFormOutput($gap->getAnswertext()));
711 $value->setRequired(true);
712 $form->addItem($value);
713
714 $lowerbound->setSize(10);
715 $lowerbound->setRequired(true);
716 $lowerbound->setValue(ilUtil::prepareFormOutput($gap->getLowerBound()));
717 $form->addItem($lowerbound);
718
719 $upperbound->setSize(10);
720 $upperbound->setRequired(true);
721 $upperbound->setValue(ilUtil::prepareFormOutput($gap->getUpperBound()));
722 $form->addItem($upperbound);
723
724 if ($this->object->getFixedTextLength() > 0) {
725 $value->setSize($this->object->getFixedTextLength());
726 $value->setMaxLength($this->object->getFixedTextLength());
727 $lowerbound->setSize($this->object->getFixedTextLength());
728 $lowerbound->setMaxLength($this->object->getFixedTextLength());
729 $upperbound->setSize($this->object->getFixedTextLength());
730 $upperbound->setMaxLength($this->object->getFixedTextLength());
731 }
732
733 $points = new ilNumberInputGUI($this->lng->txt('points'), "gap_" . $gapCounter . "_numeric_points");
734 $points->allowDecimals(true);
735 $points->setSize(3);
736 $points->setRequired(true);
737 $points->setValue(ilUtil::prepareFormOutput($gap->getPoints()));
738 $form->addItem($points);
739 return $form;
740 }
741
745 public function createGaps()
746 {
747 $this->writePostData(true);
748 $this->object->saveToDb();
749 $this->editQuestion();
750 }
751
755 public function removegap()
756 {
757 $this->writePostData(true);
758 $this->object->deleteAnswerText($this->gapIndex, key($_POST['cmd']['removegap_' . $this->gapIndex]));
759 $this->editQuestion();
760 }
761
765 public function addgap()
766 {
767 $this->writePostData(true);
768 $this->object->addGapAnswer($this->gapIndex, key($_POST['cmd']['addgap_' . $this->gapIndex]) + 1, "");
769 $this->editQuestion();
770 }
771
780 public function getPreview($show_question_only = false, $showInlineFeedback = false)
781 {
782 $user_solution = is_object($this->getPreviewSession()) ? (array) $this->getPreviewSession()->getParticipantsSolution() : array();
783
784 // generate the question output
785 include_once "./Services/UICore/classes/class.ilTemplate.php";
786 $template = new ilTemplate("tpl.il_as_qpl_cloze_question_output.html", true, true, "Modules/TestQuestionPool");
787 $output = $this->object->getClozeTextForHTMLOutput();
788 foreach ($this->object->getGaps() as $gap_index => $gap) {
789 switch ($gap->getType()) {
790 case CLOZE_TEXT:
791 $gaptemplate = new ilTemplate("tpl.il_as_qpl_cloze_question_gap_text.html", true, true, "Modules/TestQuestionPool");
792
793 $gap_size = $gap->getGapSize() > 0 ? $gap->getGapSize() : $this->object->getFixedTextLength();
794 if ($gap_size > 0) {
795 $gaptemplate->setCurrentBlock('size_and_maxlength');
796 $gaptemplate->setVariable("TEXT_GAP_SIZE", $gap_size);
797 $gaptemplate->parseCurrentBlock();
798 }
799 $gaptemplate->setVariable("GAP_COUNTER", $gap_index);
800 foreach ($user_solution as $val1 => $val2) {
801 if (strcmp($val1, $gap_index) == 0) {
802 $gaptemplate->setVariable("VALUE_GAP", " value=\"" . ilUtil::prepareFormOutput($val2) . "\"");
803 }
804 }
805 // fau: fixGapReplace - use replace function
806 $output = $this->object->replaceFirstGap($output, $gaptemplate->get());
807// fau.
808 break;
809 case CLOZE_SELECT:
810 $gaptemplate = new ilTemplate("tpl.il_as_qpl_cloze_question_gap_select.html", true, true, "Modules/TestQuestionPool");
811 foreach ($gap->getItems($this->object->getShuffler(), $gap_index) as $item) {
812 $gaptemplate->setCurrentBlock("select_gap_option");
813 $gaptemplate->setVariable("SELECT_GAP_VALUE", $item->getOrder());
814 $gaptemplate->setVariable("SELECT_GAP_TEXT", ilUtil::prepareFormOutput($item->getAnswerText()));
815 foreach ($user_solution as $val1 => $val2) {
816 if (strcmp($val1, $gap_index) == 0) {
817 if (strcmp($val2, $item->getOrder()) == 0) {
818 $gaptemplate->setVariable("SELECT_GAP_SELECTED", " selected=\"selected\"");
819 }
820 }
821 }
822 $gaptemplate->parseCurrentBlock();
823 }
824 $gaptemplate->setVariable("PLEASE_SELECT", $this->lng->txt("please_select"));
825 $gaptemplate->setVariable("GAP_COUNTER", $gap_index);// fau: fixGapReplace - use replace function
826 $output = $this->object->replaceFirstGap($output, $gaptemplate->get());
827// fau.
828 break;
829 case CLOZE_NUMERIC:
830 $gaptemplate = new ilTemplate("tpl.il_as_qpl_cloze_question_gap_numeric.html", true, true, "Modules/TestQuestionPool");
831 $gap_size = $gap->getGapSize() > 0 ? $gap->getGapSize() : $this->object->getFixedTextLength();
832 if ($gap_size > 0) {
833 $gaptemplate->setCurrentBlock('size_and_maxlength');
834 $gaptemplate->setVariable("TEXT_GAP_SIZE", $gap_size);
835 $gaptemplate->parseCurrentBlock();
836 }
837 $gaptemplate->setVariable("GAP_COUNTER", $gap_index);
838 foreach ($user_solution as $val1 => $val2) {
839 if (strcmp($val1, $gap_index) == 0) {
840 $gaptemplate->setVariable("VALUE_GAP", " value=\"" . ilUtil::prepareFormOutput($val2) . "\"");
841 }
842 }
843 // fau: fixGapReplace - use replace function
844 $output = $this->object->replaceFirstGap($output, $gaptemplate->get());
845// fau.
846 break;
847 }
848 }
849 $template->setVariable("QUESTIONTEXT", $this->object->getQuestionForHTMLOutput());
850 $template->setVariable("CLOZETEXT", $this->object->prepareTextareaOutput($output, true));
851 $questionoutput = $template->get();
852 if (!$show_question_only) {
853 // get page object output
854 $questionoutput = $this->getILIASPage($questionoutput);
855 }
856 return $questionoutput;
857 }
858
865 {
866 return true;
867 }
868
884 public function getSolutionOutput(
885 $active_id,
886 $pass = null,
887 $graphicalOutput = false,
888 $result_output = false,
889 $show_question_only = true,
890 $show_feedback = false,
891 $show_correct_solution = false,
892 $show_manual_scoring = false,
893 $show_question_text = true
894 ) {
895 // get the solution of the user for the active pass or from the last pass if allowed
896 $user_solution = array();
897 if (($active_id > 0) && (!$show_correct_solution)) {
898 // get the solutions of a user
899 $user_solution = $this->object->getSolutionValues($active_id, $pass, !$this->getUseIntermediateSolution());
900 if (!is_array($user_solution)) {
901 $user_solution = array();
902 }
903 }
904
905 include_once "./Services/UICore/classes/class.ilTemplate.php";
906 $template = new ilTemplate("tpl.il_as_qpl_cloze_question_output_solution.html", true, true, "Modules/TestQuestionPool");
907 $output = $this->object->getClozeTextForHTMLOutput();
908 $assClozeGapCombinationObject = new assClozeGapCombination();
909 $check_for_gap_combinations = $assClozeGapCombinationObject->loadFromDb($this->object->getId());
910
911 foreach ($this->object->getGaps() as $gap_index => $gap) {
912 $gaptemplate = new ilTemplate("tpl.il_as_qpl_cloze_question_output_solution_gap.html", true, true, "Modules/TestQuestionPool");
913 $found = array();
914 foreach ($user_solution as $solutionarray) {
915 if ($solutionarray["value1"] == $gap_index) {
916 $found = $solutionarray;
917 }
918 }
919
920 if ($active_id) {
921 if ($graphicalOutput) {
922 // output of ok/not ok icons for user entered solutions
923 $details = $this->object->calculateReachedPoints($active_id, $pass, true, true);
924 $check = $details[$gap_index];
925
926 if (count($check_for_gap_combinations) != 0) {
927 $gaps_used_in_combination = $assClozeGapCombinationObject->getGapsWhichAreUsedInCombination($this->object->getId());
928 $custom_user_solution = array();
929 if (array_key_exists($gap_index, $gaps_used_in_combination)) {
930 $combination_id = $gaps_used_in_combination[$gap_index];
931 foreach ($gaps_used_in_combination as $key => $value) {
932 $a = 0;
933 if ($value == $combination_id) {
934 foreach ($user_solution as $solution_key => $solution_value) {
935 if ($solution_value['value1'] == $key) {
936 $result_row = array();
937 $result_row['gap_id'] = $solution_value['value1'];
938 $result_row['value'] = $solution_value['value2'];
939 array_push($custom_user_solution, $result_row);
940 }
941 }
942 }
943 }
944 $points_array = $this->object->calculateCombinationResult($custom_user_solution);
945 $max_combination_points = $assClozeGapCombinationObject->getMaxPointsForCombination($this->object->getId(), $combination_id);
946 if ($points_array[0] == $max_combination_points) {
947 $gaptemplate->setVariable("ICON_OK", ilUtil::getImagePath("icon_ok.svg"));
948 $gaptemplate->setVariable("TEXT_OK", $this->lng->txt("answer_is_right"));
949 } elseif ($points_array[0] > 0) {
950 $gaptemplate->setVariable("ICON_NOT_OK", ilUtil::getImagePath("icon_mostly_ok.svg"));
951 $gaptemplate->setVariable("TEXT_NOT_OK", $this->lng->txt("answer_is_not_correct_but_positive"));
952 } else {
953 $gaptemplate->setVariable("ICON_NOT_OK", ilUtil::getImagePath("icon_not_ok.svg"));
954 $gaptemplate->setVariable("TEXT_NOT_OK", $this->lng->txt("answer_is_wrong"));
955 }
956 } else {
957 if ($check["best"]) {
958 $gaptemplate->setCurrentBlock("icon_ok");
959 $gaptemplate->setVariable("ICON_OK", ilUtil::getImagePath("icon_ok.svg"));
960 $gaptemplate->setVariable("TEXT_OK", $this->lng->txt("answer_is_right"));
961 $gaptemplate->parseCurrentBlock();
962 } else {
963 $gaptemplate->setCurrentBlock("icon_not_ok");
964 if ($check["positive"]) {
965 $gaptemplate->setVariable("ICON_NOT_OK", ilUtil::getImagePath("icon_mostly_ok.svg"));
966 $gaptemplate->setVariable("TEXT_NOT_OK", $this->lng->txt("answer_is_not_correct_but_positive"));
967 } else {
968 $gaptemplate->setVariable("ICON_NOT_OK", ilUtil::getImagePath("icon_not_ok.svg"));
969 $gaptemplate->setVariable("TEXT_NOT_OK", $this->lng->txt("answer_is_wrong"));
970 }
971 $gaptemplate->parseCurrentBlock();
972 }
973 }
974 } else {
975 if ($check["best"]) {
976 $gaptemplate->setCurrentBlock("icon_ok");
977 $gaptemplate->setVariable("ICON_OK", ilUtil::getImagePath("icon_ok.svg"));
978 $gaptemplate->setVariable("TEXT_OK", $this->lng->txt("answer_is_right"));
979 $gaptemplate->parseCurrentBlock();
980 } else {
981 $gaptemplate->setCurrentBlock("icon_not_ok");
982 if ($check["positive"]) {
983 $gaptemplate->setVariable("ICON_NOT_OK", ilUtil::getImagePath("icon_mostly_ok.svg"));
984 $gaptemplate->setVariable("TEXT_NOT_OK", $this->lng->txt("answer_is_not_correct_but_positive"));
985 } else {
986 $gaptemplate->setVariable("ICON_NOT_OK", ilUtil::getImagePath("icon_not_ok.svg"));
987 $gaptemplate->setVariable("TEXT_NOT_OK", $this->lng->txt("answer_is_wrong"));
988 }
989 $gaptemplate->parseCurrentBlock();
990 }
991 }
992 }
993 }
994 $combination = null;
995 switch ($gap->getType()) {
996 case CLOZE_TEXT:
997 $solutiontext = "";
998 if (($active_id > 0) && (!$show_correct_solution)) {
999 if ((count($found) == 0) || (strlen(trim($found["value2"])) == 0)) {
1000 for ($chars = 0; $chars < $gap->getMaxWidth(); $chars++) {
1001 $solutiontext .= "&nbsp;";
1002 }
1003 } else {
1004 $solutiontext = ilUtil::prepareFormOutput($found["value2"]);
1005 }
1006 } else {
1007 $solutiontext = $this-> getBestSolutionText($gap, $gap_index, $check_for_gap_combinations);
1008 }
1009 $this->populateSolutiontextToGapTpl($gaptemplate, $gap, $solutiontext);
1010 // fau: fixGapReplace - use replace function
1011 $output = $this->object->replaceFirstGap($output, $gaptemplate->get());
1012// fau.
1013 break;
1014 case CLOZE_SELECT:
1015 $solutiontext = "";
1016 if (($active_id > 0) && (!$show_correct_solution)) {
1017 if ((count($found) == 0) || (strlen(trim($found["value2"])) == 0)) {
1018 for ($chars = 0; $chars < $gap->getMaxWidth(); $chars++) {
1019 $solutiontext .= "&nbsp;";
1020 }
1021 } else {
1022 $item = $gap->getItem($found["value2"]);
1023 if (is_object($item)) {
1024 $solutiontext = ilUtil::prepareFormOutput($item->getAnswertext());
1025 } else {
1026 for ($chars = 0; $chars < $gap->getMaxWidth(); $chars++) {
1027 $solutiontext .= "&nbsp;";
1028 }
1029 }
1030 }
1031 } else {
1032 $solutiontext = $this-> getBestSolutionText($gap, $gap_index, $check_for_gap_combinations);
1033 }
1034 $this->populateSolutiontextToGapTpl($gaptemplate, $gap, $solutiontext);
1035 // fau: fixGapReplace - use replace function
1036 $output = $this->object->replaceFirstGap($output, $gaptemplate->get());
1037// fau.
1038 break;
1039 case CLOZE_NUMERIC:
1040 $solutiontext = "";
1041 if (($active_id > 0) && (!$show_correct_solution)) {
1042 if ((count($found) == 0) || (strlen(trim($found["value2"])) == 0)) {
1043 for ($chars = 0; $chars < $gap->getMaxWidth(); $chars++) {
1044 $solutiontext .= "&nbsp;";
1045 }
1046 } else {
1047 $solutiontext = ilUtil::prepareFormOutput($found["value2"]);
1048 }
1049 } else {
1050 $solutiontext = $this-> getBestSolutionText($gap, $gap_index, $check_for_gap_combinations);
1051 }
1052 $this->populateSolutiontextToGapTpl($gaptemplate, $gap, $solutiontext);
1053 // fau: fixGapReplace - use replace function
1054 $output = $this->object->replaceFirstGap($output, $gaptemplate->get());
1055// fau.
1056 break;
1057 }
1058 }
1059
1060 if ($show_question_text) {
1061 $template->setVariable(
1062 "QUESTIONTEXT",
1063 $this->object->getQuestionForHTMLOutput()
1064 );
1065 }
1066
1067 $template->setVariable("CLOZETEXT", $this->object->prepareTextareaOutput($output, true));
1068 // generate the question output
1069 $solutiontemplate = new ilTemplate("tpl.il_as_tst_solution_output.html", true, true, "Modules/TestQuestionPool");
1070 $questionoutput = $template->get();
1071
1072 $feedback = '';
1073 if ($show_feedback) {
1074 if (!$this->isTestPresentationContext()) {
1075 $fb = $this->getGenericFeedbackOutput($active_id, $pass);
1076 $feedback .= strlen($fb) ? $fb : '';
1077 }
1078
1079 $fb = $this->getSpecificFeedbackOutput(
1080 $this->object->fetchIndexedValuesFromValuePairs($user_solution)
1081 );
1082 $feedback .= strlen($fb) ? $fb : '';
1083 }
1084 if (strlen($feedback)) {
1085 $cssClass = (
1086 $this->hasCorrectSolution($active_id, $pass) ?
1088 );
1089
1090 $solutiontemplate->setVariable("ILC_FB_CSS_CLASS", $cssClass);
1091 $solutiontemplate->setVariable("FEEDBACK", $this->object->prepareTextareaOutput($feedback, true));
1092 }
1093
1094 $solutiontemplate->setVariable("SOLUTION_OUTPUT", $questionoutput);
1095
1096 $solutionoutput = $solutiontemplate->get();
1097
1098 if (!$show_question_only) {
1099 // get page object output
1100 $solutionoutput = $this->getILIASPage($solutionoutput);
1101 }
1102
1103 return $solutionoutput;
1104 }
1105
1112 protected function getBestSolutionText($gap, $gap_index, $gap_combinations)
1113 {
1114 $combination = null;
1115 foreach ((array) $gap_combinations as $combiGapSolRow) {
1116 if ($combiGapSolRow['gap_fi'] == $gap_index && $combiGapSolRow['best_solution']) {
1117 $combination = $combiGapSolRow;
1118 break;
1119 }
1120 }
1121 $best_solution_text = ilUtil::prepareFormOutput($gap->getBestSolutionOutput(
1122 $this->object->getShuffler(),
1123 $combination
1124 ));
1125 return $best_solution_text;
1126 }
1127
1128 public function getAnswerFeedbackOutput($active_id, $pass)
1129 {
1130 include_once "./Modules/Test/classes/class.ilObjTest.php";
1131 $manual_feedback = ilObjTest::getManualFeedback($active_id, $this->object->getId(), $pass);
1132 if (strlen($manual_feedback)) {
1133 return $manual_feedback;
1134 }
1135 $correct_feedback = $this->object->feedbackOBJ->getGenericFeedbackTestPresentation($this->object->getId(), true);
1136 $incorrect_feedback = $this->object->feedbackOBJ->getGenericFeedbackTestPresentation($this->object->getId(), false);
1137 if (strlen($correct_feedback . $incorrect_feedback)) {
1138 $reached_points = $this->object->calculateReachedPoints($active_id, $pass);
1139 $max_points = $this->object->getMaximumPoints();
1140 if ($reached_points == $max_points) {
1141 $output .= $correct_feedback;
1142 } else {
1143 $output .= $incorrect_feedback;
1144 }
1145 }
1146 $test = new ilObjTest($this->object->active_id);
1147 return $this->object->prepareTextareaOutput($output, true);
1148 }
1149
1150 public function getTestOutput(
1151 $active_id,
1152 // hey: prevPassSolutions - will be always available from now on
1153 $pass,
1154 // hey.
1155 $is_postponed = false,
1156 $use_post_solutions = false,
1157 $show_feedback = false
1158 ) {
1159 // get the solution of the user for the active pass or from the last pass if allowed
1160 $user_solution = array();
1161 if ($use_post_solutions !== false) {
1162 $indexedSolution = $this->object->fetchSolutionSubmit($use_post_solutions);
1163 $user_solution = $this->object->fetchValuePairsFromIndexedValues($indexedSolution);
1164 } elseif ($active_id) {
1165 // hey: prevPassSolutions - obsolete due to central check
1166 #include_once "./Modules/Test/classes/class.ilObjTest.php";
1167 #if (!ilObjTest::_getUsePreviousAnswers($active_id, true))
1168 #{
1169 # if (is_null($pass)) $pass = ilObjTest::_getPass($active_id);
1170 #}
1171 $user_solution = $this->object->getTestOutputSolutions($active_id, $pass);
1172 // hey.
1173 if (!is_array($user_solution)) {
1174 $user_solution = array();
1175 }
1176 }
1177
1178 // generate the question output
1179 include_once "./Services/UICore/classes/class.ilTemplate.php";
1180 $template = new ilTemplate("tpl.il_as_qpl_cloze_question_output.html", true, true, "Modules/TestQuestionPool");
1181 $output = $this->object->getClozeTextForHTMLOutput();
1182 foreach ($this->object->getGaps() as $gap_index => $gap) {
1183 switch ($gap->getType()) {
1184 case CLOZE_TEXT:
1185 $gaptemplate = new ilTemplate("tpl.il_as_qpl_cloze_question_gap_text.html", true, true, "Modules/TestQuestionPool");
1186 $gap_size = $gap->getGapSize() > 0 ? $gap->getGapSize() : $this->object->getFixedTextLength();
1187
1188 if ($gap_size > 0) {
1189 $gaptemplate->setCurrentBlock('size_and_maxlength');
1190 $gaptemplate->setVariable("TEXT_GAP_SIZE", $gap_size);
1191 $gaptemplate->parseCurrentBlock();
1192 }
1193
1194 $gaptemplate->setVariable("GAP_COUNTER", $gap_index);
1195 foreach ($user_solution as $solution) {
1196 if (strcmp($solution["value1"], $gap_index) == 0) {
1197 $gaptemplate->setVariable("VALUE_GAP", " value=\"" . ilUtil::prepareFormOutput($solution["value2"]) . "\"");
1198 }
1199 }
1200 // fau: fixGapReplace - use replace function
1201 $output = $this->object->replaceFirstGap($output, $gaptemplate->get());
1202// fau.
1203 break;
1204 case CLOZE_SELECT:
1205 $gaptemplate = new ilTemplate("tpl.il_as_qpl_cloze_question_gap_select.html", true, true, "Modules/TestQuestionPool");
1206 foreach ($gap->getItems($this->object->getShuffler(), $gap_index) as $item) {
1207 $gaptemplate->setCurrentBlock("select_gap_option");
1208 $gaptemplate->setVariable("SELECT_GAP_VALUE", $item->getOrder());
1209 $gaptemplate->setVariable("SELECT_GAP_TEXT", ilUtil::prepareFormOutput($item->getAnswerText()));
1210 foreach ($user_solution as $solution) {
1211 if (strcmp($solution["value1"], $gap_index) == 0) {
1212 if (strcmp($solution["value2"], $item->getOrder()) == 0) {
1213 $gaptemplate->setVariable("SELECT_GAP_SELECTED", " selected=\"selected\"");
1214 }
1215 }
1216 }
1217 $gaptemplate->parseCurrentBlock();
1218 }
1219 $gaptemplate->setVariable("PLEASE_SELECT", $this->lng->txt("please_select"));
1220 $gaptemplate->setVariable("GAP_COUNTER", $gap_index);// fau: fixGapReplace - use replace function
1221 $output = $this->object->replaceFirstGap($output, $gaptemplate->get());
1222// fau.
1223 break;
1224 case CLOZE_NUMERIC:
1225 $gaptemplate = new ilTemplate("tpl.il_as_qpl_cloze_question_gap_numeric.html", true, true, "Modules/TestQuestionPool");
1226 $gap_size = $gap->getGapSize() > 0 ? $gap->getGapSize() : $this->object->getFixedTextLength();
1227 if ($gap_size > 0) {
1228 $gaptemplate->setCurrentBlock('size_and_maxlength');
1229 $gaptemplate->setVariable("TEXT_GAP_SIZE", $gap_size);
1230 $gaptemplate->parseCurrentBlock();
1231 }
1232
1233 $gaptemplate->setVariable("GAP_COUNTER", $gap_index);
1234 foreach ($user_solution as $solution) {
1235 if (strcmp($solution["value1"], $gap_index) == 0) {
1236 $gaptemplate->setVariable("VALUE_GAP", " value=\"" . ilUtil::prepareFormOutput($solution["value2"]) . "\"");
1237 }
1238 }
1239 // fau: fixGapReplace - use replace function
1240 $output = $this->object->replaceFirstGap($output, $gaptemplate->get());
1241// fau.
1242 break;
1243 }
1244 }
1245
1246 $template->setVariable("QUESTIONTEXT", $this->object->getQuestionForHTMLOutput());
1247 $template->setVariable("CLOZETEXT", $this->object->prepareTextareaOutput($output, true));
1248 $questionoutput = $template->get();
1249 $pageoutput = $this->outQuestionPage("", $is_postponed, $active_id, $questionoutput);
1250 return $pageoutput;
1251 }
1252
1253 public function getSpecificFeedbackOutput($userSolution)
1254 {
1255 if (!$this->object->feedbackOBJ->specificAnswerFeedbackExists()) {
1256 return '';
1257 }
1258
1259 global $DIC;
1260 $lng = $DIC['lng'];
1261
1262 $feedback = '<table class="test_specific_feedback"><tbody>';
1263
1264 foreach ($this->object->gaps as $gapIndex => $gap) {
1265 $answerValue = $this->object->fetchAnswerValueForGap($userSolution, $gapIndex);
1266 $answerIndex = $this->object->feedbackOBJ->determineAnswerIndexForAnswerValue($gap, $answerValue);
1267 $fb = $this->object->feedbackOBJ->determineTestOutputGapFeedback($gapIndex, $answerIndex);
1268
1269 $caption = $lng->txt('gap') . ' ' . ($gapIndex + 1) . ': ';
1270 $feedback .= '<tr><td>';
1271 $feedback .= $caption . '</td><td>';
1272 $feedback .= $fb . '</td> </tr>';
1273 }
1274 $feedback .= '</tbody></table>';
1275
1276 return $this->object->prepareTextareaOutput($feedback, true);
1277 }
1278
1289 {
1290 return array();
1291 }
1292
1303 {
1304 return array();
1305 }
1306
1315 public function getAggregatedAnswersView($relevant_answers)
1316 {
1317 $overview = array();
1318 $aggregation = array();
1319 foreach ($relevant_answers as $answer) {
1320 $overview[$answer['active_fi']][$answer['pass']][$answer['value1']] = $answer['value2'];
1321 }
1322
1323 foreach ($overview as $active) {
1324 foreach ($active as $answer) {
1325 foreach ($answer as $option => $value) {
1326 $aggregation[$option][$value] = $aggregation[$option][$value] + 1;
1327 }
1328 }
1329 }
1330
1331 $html = '<div>';
1332 $i = 0;
1333 foreach ($this->object->getGaps() as $gap_index => $gap) {
1334 if ($gap->type == CLOZE_SELECT) {
1335 $html .= '<p>Gap ' . ($i + 1) . ' - SELECT</p>';
1336 $html .= '<ul>';
1337 $j = 0;
1338 foreach ($gap->getItems($this->object->getShuffler(), $gap_index) as $gap_item) {
1339 $aggregate = $aggregation[$i];
1340 $html .= '<li>' . $gap_item->getAnswerText() . ' - ' . ($aggregate[$j] ? $aggregate[$j] : 0) . '</li>';
1341 $j++;
1342 }
1343 $html .= '</ul>';
1344 }
1345
1346 if ($gap->type == CLOZE_TEXT) {
1347 $present_elements = array();
1348 foreach ($gap->getItems(new ilArrayElementShuffler()) as $item) {
1350 $present_elements[] = $item->getAnswertext();
1351 }
1352
1353 $html .= '<p>Gap ' . ($i + 1) . ' - TEXT</p>';
1354 $html .= '<ul>';
1355 $aggregate = (array) $aggregation[$i];
1356 foreach ($aggregate as $answer => $count) {
1357 $show_mover = '';
1358 if (in_array($answer, $present_elements)) {
1359 $show_mover = ' style="display: none;" ';
1360 }
1361
1362 $html .= '<li>' . $answer . ' - ' . $count
1363 . '&nbsp;<button class="clone_fields_add btn btn-link" ' . $show_mover . ' data-answer="' . $answer . '" name="add_gap_' . $i . '_0">
1364 <span class="sr-only"></span><span class="glyphicon glyphicon-plus"></span></button>
1365 </li>';
1366 }
1367 $html .= '</ul>';
1368 }
1369
1370 if ($gap->type == CLOZE_NUMERIC) {
1371 $html .= '<p>Gap ' . ($i + 1) . ' - NUMERIC</p>';
1372 $html .= '<ul>';
1373 $j = 0;
1374 foreach ($gap->getItems($this->object->getShuffler(), $gap_index) as $gap_item) {
1375 $aggregate = (array) $aggregation[$i];
1376 foreach ($aggregate as $answer => $count) {
1377 $html .= '<li>' . $answer . ' - ' . $count . '</li>';
1378 }
1379 $j++;
1380 }
1381 $html .= '</ul>';
1382 }
1383 $i++;
1384 $html .= '<hr />';
1385 }
1386
1387 $html .= '</div>';
1388 return $html;
1389 }
1390
1391 public function applyIndizesToGapText($question_text)
1392 {
1393 $parts = explode('[gap', $question_text);
1394 $i = 0;
1395 $question_text = '';
1396 foreach ($parts as $part) {
1397 if ($i == 0) {
1398 $question_text .= $part;
1399 } else {
1400 $question_text .= '[gap ' . $i . $part;
1401 }
1402 $i++;
1403 }
1404 return $question_text;
1405 }
1406
1407 public function removeIndizesFromGapText($question_text)
1408 {
1409 $parts = preg_split('/\[gap \d*\]/', $question_text);
1410 $question_text = implode('[gap]', $parts);
1411 return $question_text;
1412 }
1413
1418 private function populateSolutiontextToGapTpl($gaptemplate, $gap, $solutiontext)
1419 {
1420 if ($this->renderPurposeSupportsFormHtml() || $this->isRenderPurposePrintPdf()) {
1421 $gaptemplate->setCurrentBlock('gap_span');
1422 $gaptemplate->setVariable('SPAN_SOLUTION', $solutiontext);
1423 } elseif ($gap->getType() == CLOZE_SELECT) {
1424 $gaptemplate->setCurrentBlock('gap_select');
1425 $gaptemplate->setVariable('SELECT_SOLUTION', $solutiontext);
1426 } else {
1427 $gap_size = $gap->getGapSize() > 0 ? $gap->getGapSize() : $this->object->getFixedTextLength();
1428
1429 if ($gap_size > 0) {
1430 $gaptemplate->setCurrentBlock('gap_size');
1431 $gaptemplate->setVariable("GAP_SIZE", $gap_size);
1432 $gaptemplate->parseCurrentBlock();
1433 }
1434
1435 $gaptemplate->setCurrentBlock('gap_input');
1436 $gaptemplate->setVariable('INPUT_SOLUTION', $solutiontext);
1437 }
1438
1439
1440 $gaptemplate->parseCurrentBlock();
1441 }
1442
1443 protected function hasAddAnswerAction($relevantAnswers, $questionIndex)
1444 {
1445 foreach ($this->getAnswersFrequency($relevantAnswers, $questionIndex) as $answer) {
1446 if (isset($answer['actions'])) {
1447 return true;
1448 }
1449 }
1450
1451 return false;
1452 }
1453
1454 public function getAnswerFrequencyTableGUI($parentGui, $parentCmd, $relevantAnswers, $questionIndex)
1455 {
1456 global $DIC; /* @var ILIAS\DI\Container $DIC */
1457
1458 $table = parent::getAnswerFrequencyTableGUI(
1459 $parentGui,
1460 $parentCmd,
1461 $relevantAnswers,
1462 $questionIndex
1463 );
1464
1465 $table->setTitle(sprintf(
1466 $DIC->language()->txt('tst_corrections_answers_tbl_subindex'),
1467 $DIC->language()->txt('gap') . ' ' . ($questionIndex + 1)
1468 ));
1469
1470 if ($this->hasAddAnswerAction($relevantAnswers, $questionIndex)) {
1471 $table->addColumn('', '', '200');
1472 }
1473
1474 return $table;
1475 }
1476
1477 public function getSubQuestionsIndex()
1478 {
1479 return array_keys($this->object->getGaps());
1480 }
1481
1482 protected function getAnswerTextLabel($gapIndex, $answer)
1483 {
1484 $gap = $this->object->getGap($gapIndex);
1485
1486 switch ($gap->type) {
1487 case CLOZE_NUMERIC:
1488 case CLOZE_TEXT:
1489 return $answer;
1490
1491 case CLOZE_SELECT:
1492
1493 $items = $gap->getItems(new ilArrayElementOrderKeeper());
1494 return $items[$answer]->getAnswertext();
1495 }
1496 }
1497
1498 protected function completeAddAnswerAction($answers, $questionIndex)
1499 {
1500 $gap = $this->object->getGap($questionIndex);
1501
1502 if ($gap->type != CLOZE_TEXT) {
1503 return $answers;
1504 }
1505
1506 foreach ($answers as $key => $ans) {
1507 $found = false;
1508
1509 foreach ($gap->getItems(new ilArrayElementOrderKeeper()) as $item) {
1510 if ($ans['answer'] !== $item->getAnswerText()) {
1511 continue;
1512 }
1513
1514 $found = true;
1515 break;
1516 }
1517
1518 if (!$found) {
1519 $answers[$key]['addable'] = true;
1520 }
1521 }
1522
1523 return $answers;
1524 }
1525
1526 public function getAnswersFrequency($relevant_answers, $questionIndex)
1527 {
1528 $answers = array();
1529
1530 foreach ($relevant_answers as $row) {
1531 if ($row['value1'] != $questionIndex) {
1532 continue;
1533 }
1534
1535 if (!isset($answers[$row['value2']])) {
1536 $label = $this->getAnswerTextLabel($row['value1'], $row['value2']);
1537
1538 $answers[$row['value2']] = array(
1539 'answer' => $label, 'frequency' => 0
1540 );
1541 }
1542
1543 $answers[$row['value2']]['frequency']++;
1544 }
1545
1546 $answers = $this->completeAddAnswerAction($answers, $questionIndex);
1547
1548 return $answers;
1549 }
1550
1552 {
1553 foreach ($this->object->getGapCombinations() as $combination) {
1554 if ($combination['gap_fi'] != $gapIndex) {
1555 continue;
1556 }
1557
1558 return true;
1559 }
1560
1561 return false;
1562 }
1563
1564 protected function getGapCombinations()
1565 {
1566 $combinations = array();
1567
1568 foreach ($this->object->getGapCombinations() as $c) {
1569 if (!isset($combinations[$c['cid']])) {
1570 $combinations[$c['cid']] = array();
1571 }
1572
1573 if (!isset($combinations[$c['cid']][$c['row_id']])) {
1574 $combinations[$c['cid']][$c['row_id']] = array(
1575 'gaps' => array(), 'points' => $c['points'],
1576 );
1577 }
1578
1579 if (!isset($combinations[$c['cid']][$c['row_id']]['gaps'][$c['gap_fi']])) {
1580 $combinations[$c['cid']][$c['row_id']]['gaps'][$c['gap_fi']] = array();
1581 }
1582
1583 $combinations[$c['cid']][$c['row_id']]['gaps'][$c['gap_fi']] = $c['answer'];
1584 }
1585
1586 return $combinations;
1587 }
1588
1590 {
1591 foreach ($this->object->getGaps() as $gapIndex => $gap) {
1593 $form,
1594 $gap,
1595 $gapIndex,
1597 );
1598 }
1599
1600 if ($this->object->getGapCombinationsExists()) {
1601 foreach ($this->getGapCombinations() as $combiIndex => $gapCombination) {
1602 $this->populateGapCombinationCorrectionFormProperty($form, $gapCombination, $combiIndex);
1603 }
1604 }
1605 }
1606
1607 protected function populateGapCombinationCorrectionFormProperty(ilPropertyFormGUI $form, $gapCombi, $combiIndex)
1608 {
1609 $header = new ilFormSectionHeaderGUI();
1610 $header->setTitle("Gap Combination " . ($combiIndex + 1));
1611 $form->addItem($header);
1612
1613 require_once 'Modules/TestQuestionPool/classes/forms/class.ilAssClozeTestCombinationVariantsInputGUI.php';
1614 $inp = new ilAssClozeTestCombinationVariantsInputGUI('Answers', 'combination_' . $combiIndex);
1615 $inp->setValues($gapCombi);
1616 $form->addItem($inp);
1617 }
1618
1624 protected function populateGapCorrectionFormProperties($form, $gap, $gapIndex, $hidePoints)
1625 {
1626 $header = new ilFormSectionHeaderGUI();
1627 $header->setTitle($this->lng->txt("gap") . " " . ($gapIndex + 1));
1628 $form->addItem($header);
1629
1630 if ($gap->getType() == CLOZE_TEXT || $gap->getType() == CLOZE_SELECT) {
1631 $this->populateTextOrSelectGapCorrectionFormProperty($form, $gap, $gapIndex, $hidePoints);
1632 } elseif ($gap->getType() == CLOZE_NUMERIC) {
1633 foreach ($gap->getItemsRaw() as $item) {
1634 $this->populateNumericGapCorrectionFormProperty($form, $item, $gapIndex, $hidePoints);
1635 }
1636 }
1637 }
1638
1639 protected function populateTextOrSelectGapCorrectionFormProperty($form, $gap, $gapIndex, $hidePoints)
1640 {
1641 require_once "Modules/TestQuestionPool/classes/forms/class.ilAssAnswerCorrectionsInputGUI.php";
1642 $values = new ilAssAnswerCorrectionsInputGUI($this->lng->txt("values"), "gap_" . $gapIndex);
1643 $values->setHidePointsEnabled($hidePoints);
1644 $values->setRequired(true);
1645 $values->setQuestionObject($this->object);
1646 $values->setValues($gap->getItemsRaw());
1647 $form->addItem($values);
1648 }
1649
1650 protected function populateNumericGapCorrectionFormProperty($form, $item, $gapIndex, $hidePoints)
1651 {
1652 $value = new ilNumberInputGUI($this->lng->txt('value'), "gap_" . $gapIndex . "_numeric");
1653 $value->allowDecimals(true);
1654 $value->setSize(10);
1655 $value->setValue(ilUtil::prepareFormOutput($item->getAnswertext()));
1656 $value->setRequired(true);
1657 $form->addItem($value);
1658
1659 $lowerbound = new ilNumberInputGUI($this->lng->txt('range_lower_limit'), "gap_" . $gapIndex . "_numeric_lower");
1660 $lowerbound->allowDecimals(true);
1661 $lowerbound->setSize(10);
1662 $lowerbound->setRequired(true);
1663 $lowerbound->setValue(ilUtil::prepareFormOutput($item->getLowerBound()));
1664 $form->addItem($lowerbound);
1665
1666 $upperbound = new ilNumberInputGUI($this->lng->txt('range_upper_limit'), "gap_" . $gapIndex . "_numeric_upper");
1667 $upperbound->allowDecimals(true);
1668 $upperbound->setSize(10);
1669 $upperbound->setRequired(true);
1670 $upperbound->setValue(ilUtil::prepareFormOutput($item->getUpperBound()));
1671 $form->addItem($upperbound);
1672
1673 if (!$hidePoints) {
1674 $points = new ilNumberInputGUI($this->lng->txt('points'), "gap_" . $gapIndex . "_numeric_points");
1675 $points->allowDecimals(true);
1676 $points->setSize(3);
1677 $points->setRequired(true);
1678 $points->setValue(ilUtil::prepareFormOutput($item->getPoints()));
1679 $form->addItem($points);
1680 }
1681 }
1682
1687 {
1688 foreach ($this->object->getGaps() as $gapIndex => $gap) {
1689 if ($this->isUsedInCombinations($gapIndex)) {
1690 continue;
1691 }
1692
1693 $this->saveGapCorrectionFormProperty($form, $gap, $gapIndex);
1694 }
1695
1696 if ($this->object->getGapCombinationsExists()) {
1698 }
1699 }
1700
1702 {
1703 if ($gap->getType() == CLOZE_TEXT || $gap->getType() == CLOZE_SELECT) {
1705 } elseif ($gap->getType() == CLOZE_NUMERIC) {
1706 foreach ($gap->getItemsRaw() as $item) {
1707 $this->saveNumericGapCorrectionFormProperty($form, $item, $gapIndex);
1708 }
1709 }
1710 }
1711
1713 {
1714 $answers = $form->getItemByPostVar('gap_' . $gapIndex)->getValues();
1715
1716 foreach ($gap->getItemsRaw() as $index => $item) {
1717 $item->setPoints((float) $answers[$index]->getPoints());
1718 }
1719 }
1720
1722 {
1723 $item->setAnswertext($form->getInput('gap_' . $gapIndex . '_numeric'));
1724 $item->setLowerBound($form->getInput('gap_' . $gapIndex . '_numeric_lower'));
1725 $item->setUpperBound($form->getInput('gap_' . $gapIndex . '_numeric_upper'));
1726 $item->setPoints($form->getInput('gap_' . $gapIndex . '_numeric_points'));
1727 }
1728
1730 {
1731 // please dont ask (!) -.-
1732
1733 $combinationPoints = array('points' => array(), 'select' => array());
1734 $combinationValues = array();
1735
1736 foreach ($this->getGapCombinations() as $combiId => $combi) {
1737 $values = $form->getItemByPostVar('combination_' . $combiId)->getValues();
1738
1739 if (!isset($combinationPoints['points'][$combiId])) {
1740 $combinationPoints['points'][$combiId] = array();
1741 $combinationPoints['select'][$combiId] = array();
1742 $combinationValues[$combiId] = array();
1743 }
1744
1745 foreach ($combi as $varId => $variant) {
1746 $combinationPoints['points'][$combiId][$varId] = (float) $values[$varId]['points'];
1747 $combinationPoints['select'][$combiId] = array_keys($values[$varId]['gaps']);
1748 $combinationValues[$combiId][$varId] = array_values($values[$varId]['gaps']);
1749 }
1750 }
1751
1752 $combinationPoints = $combinationPoints;
1753 $combinationValues = $combinationValues;
1754
1755 $assClozeGapCombinationObject = new assClozeGapCombination();
1756 $assClozeGapCombinationObject->clearGapCombinationsFromDb($this->object->getId());
1757
1758 $assClozeGapCombinationObject->saveGapCombinationToDb(
1759 $this->object->getId(),
1760 $combinationPoints,
1761 $combinationValues
1762 );
1763 }
1764}
$test
Definition: Utf8Test.php:84
$_POST["username"]
setAnswertext($answertext="")
Sets the answer text.
setPoints($points=0.0)
Sets the points.
An exception for terminatinating execution or to throw for unit testing.
Class for cloze question numeric answers.
setUpperBound($bound)
Sets the upper bound.
setLowerBound($bound)
Sets the lower boind.
Class for cloze question gaps.
getType()
Gets the cloze gap type.
getItemsRaw()
Gets the items of a cloze gap.
Cloze test question GUI representation.
getAnswerFeedbackOutput($active_id, $pass)
Returns the answer generic feedback depending on the results of the question.
hasAddAnswerAction($relevantAnswers, $questionIndex)
applyIndizesToGapText($question_text)
populateGapCombinationCorrectionFormProperty(ilPropertyFormGUI $form, $gapCombi, $combiIndex)
populateTextOrSelectGapCorrectionFormProperty($form, $gap, $gapIndex, $hidePoints)
editQuestion($checkonly=false)
Creates an output of the edit form for the question.
populateNumericGapCorrectionFormProperty($form, $item, $gapIndex, $hidePoints)
getAnswerTextLabel($gapIndex, $answer)
getAnswerFrequencyTableGUI($parentGui, $parentCmd, $relevantAnswers, $questionIndex)
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.
__construct($id=-1)
assClozeTestGUI constructor
populateSelectGapFormPart($form, $gap, $gapCounter)
Populates the form-part for a select gap.
populateNumericGapFormPart($form, $gap, $gapCounter)
Populates the form-part for a numeric gap.
createGaps()
Create gaps from cloze text.
getSpecificFeedbackOutput($userSolution)
Returns the answer specific feedback for the question.
getAfterParticipationSuppressionQuestionPostVars()
Returns a list of postvars which will be suppressed in the form output when used in scoring adjustmen...
$gapIndex
A temporary variable to store gap indexes of ilCtrl commands in the getCommand method.
removeIndizesFromGapText($question_text)
populateGapCorrectionFormProperties($form, $gap, $gapIndex, $hidePoints)
writeQuestionSpecificPostData(ilPropertyFormGUI $form)
Extracts the question specific values from $_POST and applies them to the data object.
populateCorrectionsFormProperties(ilPropertyFormGUI $form)
populateQuestionSpecificFormPart(ilPropertyFormGUI $form)
Adds the question specific forms parts to a question property form gui.
populateGapSizeFormPart($form, $gap, $gapCounter)
getBestSolutionText($gap, $gap_index, $gap_combinations)
populateSolutiontextToGapTpl($gaptemplate, $gap, $solutiontext)
populateTextGapFormPart($form, $gap, $gapCounter)
Populates the form-part for a text gap.
getPreview($show_question_only=false, $showInlineFeedback=false)
Creates a preview output of the question.
saveCorrectionsFormProperties(ilPropertyFormGUI $form)
populateGapFormPart($form, $gapCounter)
Populates a gap form-part.
addgap()
Add a gap answer.
getAfterParticipationSuppressionAnswerPostVars()
Returns a list of postvars which will be suppressed in the form output when used in scoring adjustmen...
saveGapCombinationCorrectionFormProperties(ilPropertyFormGUI $form)
supportsIntermediateSolutionOutput()
Question type specific support of intermediate solution output The function getSolutionOutput respect...
getAnswersFrequency($relevant_answers, $questionIndex)
writeAnswerSpecificPostData(ilPropertyFormGUI $form)
Extracts the answer specific values from $_POST and applies them to the data object.
getTestOutput( $active_id, $pass, $is_postponed=false, $use_post_solutions=false, $show_feedback=false)
saveNumericGapCorrectionFormProperty(ilPropertyFormGUI $form, assAnswerCloze $item, $gapIndex)
populateAnswerSpecificFormPart(ilPropertyFormGUI $form)
Adds the answer specific form parts to a question property form gui.
writePostData($always=false)
{Evaluates a posted edit form and writes the form data in the question object.integer A positive valu...
completeAddAnswerAction($answers, $questionIndex)
addBasicQuestionFormProperties($form)
Add basic question form properties: assessment: title, author, description, question,...
removegap()
Remove a gap answer.
saveGapCorrectionFormProperty(ilPropertyFormGUI $form, assClozeGap $gap, $gapIndex)
saveTextOrSelectGapCorrectionFormProperty(ilPropertyFormGUI $form, assClozeGap $gap, $gapIndex)
Class for cloze tests.
Basic GUI class for assessment questions.
populateTaxonomyFormSection(ilPropertyFormGUI $form)
addQuestionFormCommandButtons($form)
Add the command buttons of a question properties form.
escapeTemplatePlaceholders(string $text)
getILIASPage($html="")
Returns the ILIAS Page around a question.
getQuestionTemplate()
get question template
outQuestionPage($a_temp_var, $a_postponed=false, $active_id="", $html="", $inlineFeedbackEnabled=false)
output question page
getUseIntermediateSolution()
Get if intermediate solution should be used for solution output.
hasCorrectSolution($activeId, $passIndex)
getGenericFeedbackOutput($active_id, $pass)
Returns the answer specific feedback for the question.
const ADDITIONAL_CONTENT_EDITING_MODE_RTE
constant for additional content editing mode "default"
This class represents a single choice wizard property in a property form.
static getSelfAssessmentTags()
Get tags allowed in question tags in self assessment mode.
This class represents a checkbox property in a property form.
This class represents a custom property in a property form.
This class represents a duration (typical hh:mm:ss) property in a property form.
This class represents a section header in a property form.
This class represents a formula text property in a property form.
This class represents a hidden form property in a property form.
This class represents a number property in a property form.
static _getUsedHTMLTags($a_module="")
Returns an array of all allowed HTML tags for text editing.
static getManualFeedback($active_id, $question_id, $pass)
Retrieves the feedback comment for a question in a test if it is finalized.
This class represents a property form user interface.
addItem($a_item)
Add Item (Property, SectionHeader).
getInput($a_post_var, $ensureValidation=true)
Returns the value of a HTTP-POST variable, identified by the passed id.
getItemByPostVar($a_post_var)
Get Item by POST variable.
This class represents a selection list property in a property form.
special template class to simplify handling of ITX/PEAR
This class represents a text area property in a property form.
This class represents a text property in a property form.
static getImagePath($img, $module_path="", $mode="output", $offline=false)
get image path (for images located in a template directory)
static prepareFormOutput($a_str, $a_strip=false)
prepares string output for html forms @access public
$c
Definition: cli.php:37
global $DIC
Definition: goto.php:24
$errors
Definition: imgupload.php:49
const CLOZE_NUMERIC
const CLOZE_SELECT
const CLOZE_TEXT
Cloze question constants.
Interface ilGuiAnswerScoringAdjustable.
Interface ilGuiQuestionScoringAdjustable.
getAggregatedAnswersView($relevant_answers)
Returns an html string containing a question specific representation of the answers so far given in t...
$index
Definition: metadata.php:128
$i
Definition: metadata.php:24
__construct(Container $dic, ilPlugin $plugin)
@inheritDoc
$a
thx to https://mlocati.github.io/php-cs-fixer-configurator for the examples