ILIAS  release_10 Revision v10.1-43-ga1241a92c2f
class.assClozeTestImport.php
Go to the documentation of this file.
1 <?php
2 
29 {
30  private ilDBInterface $db;
31 
32  public function __construct($a_object)
33  {
35  global $DIC;
36  $this->db = $DIC['ilDB'];
37 
38  parent::__construct($a_object);
39  }
40 
54  public function fromXML(
55  string $importdirectory,
56  int $user_id,
57  ilQTIItem $item,
58  int $questionpool_id,
59  ?int $tst_id,
60  ?ilObject &$tst_object,
61  int &$question_counter,
62  array $import_mapping
63  ): array {
64  // empty session variable for imported xhtml mobs
65  ilSession::clear('import_mob_xhtml');
66  $presentation = $item->getPresentation();
67 
68  $questiontext = $this->processNonAbstractedImageReferences(
69  $item->getMetadataEntry('question') ?? '&nbsp;',
70  $item->getIliasSourceNic()
71  );
72 
73  $clozetext_array = [];
74  $gaps = [];
75  foreach ($presentation->order as $entry) {
76  if ($entry['type'] === 'material') {
77  $material_string = $this->QTIMaterialToString(
78  $presentation->material[$entry['index']]
79  );
80 
81  if ($questiontext === '&nbsp;') {
87  $questiontext = $material_string;
88  continue;
89  }
90 
91  $clozetext_array[] = $material_string;
92  continue;
93  }
94 
95  if ($entry['type'] === 'response') {
96  $response = $presentation->response[$entry['index']];
97  $clozetext_array[] = "<<{$response->getIdent()}>>";
98 
99  if ($response->getRenderType() instanceof ilQTIRenderFib) {
100  $fibtype = $response->getRenderType()->getFibtype();
101  if ($fibtype === ilQTIRenderFib::FIBTYPE_DECIMAL
102  || $fibtype === ilQTIRenderFib::FIBTYPE_INTEGER) {
103  $gaps[] = [
104  'ident' => $response->getIdent(),
105  'type' => assClozeGap::TYPE_NUMERIC,
106  'answers' => [],
107  'minnumber' => $response->getRenderType()->getMinnumber(),
108  'maxnumber' => $response->getRenderType()->getMaxnumber(),
109  'gap_size' => $response->getRenderType()->getMaxchars()
110  ];
111  continue;
112  }
113 
114  $gaps[] = [
115  'ident' => $response->getIdent(),
116  'type' => assClozeGap::TYPE_TEXT,
117  'answers' => [],
118  'gap_size' => $response->getRenderType()->getMaxchars()
119  ];
120  continue;
121  }
122 
123  if ($response->getRenderType() instanceof ilQTIRenderChoice) {
124  $answers = [];
125  $answerorder = 0;
126  foreach ($response->getRenderType()->response_labels as $response_label) {
127  $ident = $response_label->getIdent();
128  $answertext = '';
129  foreach ($response_label->material as $mat) {
130  $answertext .= $this->QTIMaterialToString($mat);
131  }
132  $answers[$ident] = [
133  'answertext' => $answertext,
134  'points' => 0,
135  'answerorder' => $answerorder++,
136  'action' => '',
137  'shuffle' => $response->getRenderType()->getShuffle()
138  ];
139  }
140  $gaps[] = [
141  'ident' => $response->getIdent(),
142  'type' => assClozeGap::TYPE_SELECT,
143  'shuffle' => $response->getRenderType()->getShuffle(),
144  'answers' => $answers
145  ];
146  }
147  }
148  }
149  $feedbacks = [];
150  $feedbacksgeneric = [];
151  foreach ($item->resprocessing as $resprocessing) {
152  foreach ($resprocessing->respcondition as $respcondition) {
153  $ident = '';
154  $correctness = 1;
155  $conditionvar = $respcondition->getConditionvar();
156  $equals = '';
157  $gapident = '';
158  foreach ($conditionvar->order as $order) {
159  if ($order['field'] === 'varequal') {
160  $equals = $conditionvar->varequal[$order['index']]->getContent();
161  $gapident = $conditionvar->varequal[$order['index']]->getRespident();
162  }
163  }
164  if ($gapident === '') {
165  continue;
166  }
167  foreach ($respcondition->setvar as $setvar) {
168  foreach ($gaps as $gi => $g) {
169  if ($g['ident'] !== $gapident) {
170  continue;
171  }
172  switch ($g['type']) {
174  foreach ($gaps[$gi]['answers'] as $ai => $answer) {
175  if ($answer['answertext'] === $equals) {
176  $gaps[$gi]['answers'][$ai]['action'] = $setvar->getAction();
177  $gaps[$gi]['answers'][$ai]['points'] = $setvar->getContent();
178  }
179  }
180  break;
183  $gaps[$gi]['answers'][] = [
184  'answertext' => $equals,
185  'points' => $setvar->getContent(),
186  'answerorder' => count($gaps[$gi]['answers']),
187  'action' => $setvar->getAction()
188 
189  ];
190  break;
191  }
192  }
193  }
194 
195  if ($respcondition->displayfeedback === []) {
196  continue;
197  }
198 
199  foreach ($respcondition->displayfeedback as $feedbackpointer) {
200  if ($feedbackpointer->getLinkrefid() === '') {
201  continue;
202  }
203  foreach ($item->itemfeedback as $ifb) {
204  switch ($ifb->getIdent()) {
205  case 'response_allcorrect':
206  foreach ($ifb->material as $material) {
207  $feedbacksgeneric[1] = $material;
208  }
209  foreach ($ifb->flow_mat as $fmat) {
210  foreach ($fmat->material as $material) {
211  $feedbacksgeneric[1] = $material;
212  }
213  }
214  break;
215  case 'response_onenotcorrect':
216  foreach ($ifb->material as $material) {
217  $feedbacksgeneric[0] = $material;
218  }
219  foreach ($ifb->flow_mat as $fmat) {
220  foreach ($fmat->material as $material) {
221  $feedbacksgeneric[0] = $material;
222  }
223  }
224  break;
225  default:
226  foreach ($ifb->material as $material) {
227  $feedbacks[$ifb->getIdent()] = $material;
228  }
229  foreach ($ifb->flow_mat as $fmat) {
230  foreach ($fmat->material as $material) {
231  $feedbacks[$ifb->getIdent()] = $material;
232  }
233  }
234  }
235  }
236  }
237  }
238  }
239 
240  $this->addGeneralMetadata($item);
241  $this->object->setTitle($item->getTitle());
242  $this->object->setNrOfTries((int) $item->getMaxattempts());
243  $this->object->setComment($item->getComment());
244  $this->object->setAuthor($item->getAuthor());
245  $this->object->setOwner($user_id);
246  $this->object->setObjId($questionpool_id);
247  $textgap_rating = $item->getMetadataEntry('textgaprating') ?? '';
248  $this->object->setFixedTextLength((int) $item->getMetadataEntry('fixedTextLength'));
249  $this->object->setIdenticalScoring((bool) $item->getMetadataEntry('identicalScoring'));
250  $this->object->setFeedbackMode(
251  ($item->getMetadataEntry('feedback_mode') ?? '') !== '' ?
253  );
254  $combinations = json_decode(base64_decode($item->getMetadataEntry('combinations') ?? ''));
255  if ($textgap_rating === '') {
256  $textgap_rating = 'ci';
257  }
258  $this->object->setTextgapRating($textgap_rating);
259  $gaptext = [];
260  foreach ($gaps as $gapidx => $gap) {
261  $gapcontent = [];
262  $clozegap = new assClozeGap($gap['type']);
263  foreach ($gap['answers'] as $answer) {
264  $gapanswer = new assAnswerCloze($answer['answertext'], $answer['points'], $answer['answerorder']);
265  $gapanswer->setGapSize((int) ($gap['gap_size'] ?? 0));
266  switch ($clozegap->getType()) {
268  $clozegap->setShuffle($answer['shuffle']);
269  break;
271  $gapanswer->setLowerBound($gap['minnumber']);
272  $gapanswer->setUpperBound($gap['maxnumber']);
273  break;
274  }
275  $clozegap->setGapSize((int) ($gap['gap_size'] ?? 0));
276  $clozegap->addItem($gapanswer);
277  array_push($gapcontent, $answer['answertext']);
278  }
279  $this->object->addGapAtIndex($clozegap, $gapidx);
280  $gaptext[$gap['ident']] = '[gap]' . join(',', $gapcontent) . '[/gap]';
281  }
282 
283  $this->object->setQuestion($questiontext);
284  $clozetext = join('', $clozetext_array);
285 
286  foreach ($gaptext as $idx => $val) {
287  $clozetext = str_replace('<<' . $idx . '>>', $val, $clozetext);
288  }
289  $this->object->setClozeTextValue($clozetext);
290 
291  // additional content editing mode information
292  $this->object->setAdditionalContentEditingMode(
294  );
295  $this->object->saveToDb();
296 
297  if (is_array($combinations) && count($combinations) > 0) {
298  $gap_combinations = new assClozeGapCombination($this->db);
299  $gap_combinations->clearGapCombinationsFromDb($this->object->getId());
300  $gap_combinations->importGapCombinationToDb($this->object->getId(), $combinations);
301  $gap_combinations->loadFromDb($this->object->getId());
302  $this->object->setGapCombinations($gap_combinations);
303  $this->object->setGapCombinationsExists(true);
304  }
305 
306  // handle the import of media objects in XHTML code
307  foreach ($feedbacks as $ident => $material) {
308  $m = $this->QTIMaterialToString($material);
309  $feedbacks[$ident] = $m;
310  }
311  foreach ($feedbacksgeneric as $correctness => $material) {
312  $m = $this->QTIMaterialToString($material);
313  $feedbacksgeneric[$correctness] = $m;
314  }
315  if (is_array(ilSession::get('import_mob_xhtml'))) {
316  foreach (ilSession::get('import_mob_xhtml') as $mob) {
317  $importfile = $importdirectory . DIRECTORY_SEPARATOR . $mob['uri'];
318  global $DIC;
319  $DIC['ilLog']->write(__METHOD__ . ': import mob from dir: ' . $importfile);
320 
321  $media_object = ilObjMediaObject::_saveTempFileAsMediaObject(basename($importfile), $importfile, false);
322  $questiontext = str_replace('src="' . $mob['mob'] . '"', 'src="' . 'il_' . IL_INST_ID . '_mob_' . $media_object->getId() . '"', $questiontext);
323  $clozetext = str_replace('src="' . $mob['mob'] . '"', 'src="' . 'il_' . IL_INST_ID . '_mob_' . $media_object->getId() . '"', $clozetext);
324  foreach ($feedbacks as $ident => $material) {
325  $feedbacks[$ident] = str_replace('src="' . $mob['mob'] . '"', 'src="' . 'il_' . IL_INST_ID . '_mob_' . $media_object->getId() . '"', $material);
326  }
327  foreach ($feedbacksgeneric as $correctness => $material) {
328  $feedbacksgeneric[$correctness] = str_replace('src="' . $mob['mob'] . '"', 'src="' . 'il_' . IL_INST_ID . '_mob_' . $media_object->getId() . '"', $material);
329  }
330  }
331  }
332  $this->object->setQuestion(ilRTE::_replaceMediaObjectImageSrc($questiontext, 1));
333  $this->object->setClozeTextValue(ilRTE::_replaceMediaObjectImageSrc($clozetext, 1));
334  foreach ($feedbacks as $ident => $material) {
335  $fbIdentifier = $this->buildFeedbackIdentifier($ident);
336  $this->object->feedbackOBJ->importSpecificAnswerFeedback(
337  $this->object->getId(),
338  $fbIdentifier->getQuestionIndex(),
339  $fbIdentifier->getAnswerIndex(),
341  );
342  }
343  foreach ($feedbacksgeneric as $correctness => $material) {
344  $this->object->feedbackOBJ->importGenericFeedback(
345  $this->object->getId(),
346  $correctness,
348  );
349  }
350  $this->object->saveToDb();
351 
352  $this->importSuggestedSolutions($this->object->getId(), $item->suggested_solutions);
353  $import_mapping[$item->getIdent()] = $this->addQuestionToParentObjectAndBuildMappingEntry(
354  $questionpool_id,
355  $tst_id,
356  $question_counter,
357  $tst_object
358  );
359  return $import_mapping;
360  }
361 
367  {
368  $fbIdentifier = new ilAssSpecificFeedbackIdentifier();
369 
370  $ident = explode('_', $ident);
371 
372  if (count($ident) > 1) {
373  $fbIdentifier->setQuestionIndex($ident[0]);
374  $fbIdentifier->setAnswerIndex($ident[1]);
375  } else {
376  $fbIdentifier->setQuestionIndex($ident[0]);
377  $fbIdentifier->setAnswerIndex(0);
378  }
379 
380  return $fbIdentifier;
381  }
382 }
static _replaceMediaObjectImageSrc(string $a_text, int $a_direction=0, string $nic='')
Replaces image source from mob image urls with the mob id or replaces mob id with the correct image s...
static get(string $a_var)
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
addGeneralMetadata(ilQTIItem $item)
const IL_INST_ID
Definition: constants.php:40
QTIMaterialToString(ilQTIMaterial $a_material)
Reads an QTI material tag and creates a text or XHTML string.
addQuestionToParentObjectAndBuildMappingEntry(int $questionpool_id, ?int $tst_id, int &$question_counter, ?ilObjTest &$tst_object)
getMetadataEntry(string $a_label)
processNonAbstractedImageReferences($text, $sourceNic)
fetchAdditionalContentEditingModeInformation($qtiItem)
fetches the "additional content editing mode" information from qti item and falls back to ADDITIONAL_...
$response
Definition: xapitoken.php:90
Class for cloze question gaps.
global $DIC
Definition: shib_login.php:25
importSuggestedSolutions(int $question_id, array $solution_from_import)
static _saveTempFileAsMediaObject(string $name, string $tmp_name, bool $upload=true)
__construct(Container $dic, ilPlugin $plugin)
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
Class for question imports.
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
static clear(string $a_var)
const FB_MODE_GAP_QUESTION
constants for different feedback modes (per gap or per gap-answers/options)
fromXML(string $importdirectory, int $user_id, ilQTIItem $item, int $questionpool_id, ?int $tst_id, ?ilObject &$tst_object, int &$question_counter, array $import_mapping)
Creates a question from a QTI file.