ILIAS  trunk Revision v11.0_alpha-2638-g80c1d007f79
class.assOrderingQuestionImport.php
Go to the documentation of this file.
1 <?php
2 
29 {
33  public $object;
34 
35  public function fromXML(
36  string $importdirectory,
37  int $user_id,
38  ilQTIItem $item,
39  int $questionpool_id,
40  ?int $tst_id,
41  ?ilObject &$tst_object,
42  int &$question_counter,
43  array $import_mapping
44  ): array {
45  // empty session variable for imported xhtml mobs
46  ilSession::clear('import_mob_xhtml');
47 
48  $presentation = $item->getPresentation();
49  $shuffle = 0;
50  $foundimage = false;
51  $answers = [];
53 
54  foreach ($presentation->order as $entry) {
55  switch ($entry['type']) {
56  case 'response':
57  $response = $presentation->response[$entry["index"]];
58  $type = $response->getIdent();
59  if ($response->getIdent() === 'OQP') {
61  } elseif ($response->getIdent() === 'OQNP') {
63  } elseif ($response->getIdent() === 'OQNT') {
65  } elseif ($response->getIdent() === 'OQT') {
67  }
68 
69  $rendertype = $response->getRenderType();
70  switch (get_class($rendertype)) {
71  case ilQTIRenderChoice::class:
72  $shuffle = $rendertype->getShuffle();
73  $answerorder = 0;
74  foreach ($rendertype->response_labels as $response_label) {
75  $ident = $response_label->getIdent();
76  $answertext = '';
77  $answerimage = [];
78  $answerdepth = 0;
79  foreach ($response_label->material as $mat) {
80  for ($m = 0; $m < $mat->getMaterialCount(); $m++) {
81  $foundmat = $mat->getMaterial($m);
82 
83  if ($foundmat['material']->getLabel() === 'answerdepth') {
84  $answerdepth = $foundmat['material']->getContent();
85  }
86  if ($foundmat['type'] === 'mattext'
87  && $foundmat['material']->getLabel() !== 'answerdepth') {
88  $answertext .= $foundmat['material']->getContent();
89  }
90  if ($foundmat['type'] === 'matimage'
91  && $foundmat['material']->getLabel() !== 'answerdepth') {
92  $foundimage = true;
93  $answerimage = [
94  'imagetype' => $foundmat['material']->getImageType(),
95  'label' => $foundmat['material']->getLabel(),
96  'content' => $foundmat['material']->getContent()
97  ];
98  }
99  }
100  }
101  $answers[$answerorder] = [
102  'ident' => $ident,
103  'answertext' => $answertext,
104  'answerimage' => $answerimage,
105  'points' => 0,
106  'answerorder' => $answerorder,
107  'answerdepth' => $answerdepth,
108  'correctness' => '',
109  'action' => ''
110  ];
111  $answerorder++;
112  }
113  break;
114  }
115  break;
116  }
117  }
118 
119  $feedbacksgeneric = [];
120  foreach ($item->resprocessing as $resprocessing) {
121  foreach ($resprocessing->respcondition as $respcondition) {
122  $ident = '';
123  $correctness = 1;
124  $conditionvar = $respcondition->getConditionvar();
125  foreach ($conditionvar->order as $order) {
126  switch ($order['field']) {
127  case "arr_not":
128  $correctness = 0;
129  break;
130  case "varequal":
131  $ident = $conditionvar->varequal[$order['index']]->getContent();
132  $orderindex = $conditionvar->varequal[$order['index']]->getIndex();
133  break;
134  }
135  }
136  foreach ($respcondition->setvar as $setvar) {
137  if ($ident !== '') {
138  $answers[$ident]['solutionorder'] = $orderindex;
139  $answers[$ident]['action'] = $setvar->getAction();
140  $answers[$ident]['points'] = $setvar->getContent();
141  }
142  }
143  if (!is_array($respcondition->displayfeedback)) {
144  continue;
145  }
146 
147  foreach ($respcondition->displayfeedback as $feedbackpointer) {
148  if ($feedbackpointer->getLinkrefid() === '') {
149  continue;
150  }
151 
152  foreach ($item->itemfeedback as $ifb) {
153  if ($ifb->getIdent() === 'response_allcorrect') {
154  // found a feedback for the identifier
155  foreach ($ifb->material as $material) {
156  $feedbacksgeneric[1] = $material;
157  }
158  foreach ($ifb->flow_mat as $fmat) {
159  foreach ($fmat->material as $material) {
160  $feedbacksgeneric[1] = $material;
161  }
162  }
163  continue;
164  }
165 
166  if ($ifb->getIdent() === 'response_onenotcorrect') {
167  // found a feedback for the identifier
168  foreach ($ifb->material as $material) {
169  $feedbacksgeneric[0] = $material;
170  }
171  foreach ($ifb->flow_mat as $fmat) {
172  foreach ($fmat->material as $material) {
173  $feedbacksgeneric[0] = $material;
174  }
175  }
176  }
177  }
178  }
179  }
180  }
181 
182  $itemfeedbacks = $this->getFeedbackAnswerSpecific($item, 'link_');
183 
184  $this->addGeneralMetadata($item);
185  $this->object->setTitle($item->getTitle());
186  $this->object->setNrOfTries((int) $item->getMaxattempts());
187  $this->object->setComment($item->getComment());
188  $this->object->setAuthor($item->getAuthor());
189  $this->object->setOwner($user_id);
190  $this->object->setQuestion($this->QTIMaterialToString($item->getQuestiontext()));
191  $this->object->setOrderingType($type);
192  $this->object->setObjId($questionpool_id);
193  $this->object->setThumbSize(
194  $this->deduceThumbSizeFromImportValue((int) $item->getMetadataEntry('thumb_geometry'))
195  );
196  $this->object->setElementHeight($item->getMetadataEntry('element_height')
197  ? (int) $item->getMetadataEntry('element_height')
198  : null);
199  $this->object->setShuffle($shuffle);
200  $this->object->setPoints(0);
201  $this->object->saveQuestionDataToDb();
202  $points = 0;
203  $solanswers = [];
204 
205  foreach ($answers as $answer) {
206  if (isset($answer['solutionorder'])) {
207  $solanswers[$answer['solutionorder']] = $answer;
208  }
209  }
210  ksort($solanswers);
211  $position = 0;
212  $element_list = $this->object->getOrderingElementList();
213  foreach ($solanswers as $answer) {
214  $points += $answer['points'];
215 
216  $element = new ilAssOrderingElement();
217 
218  if ($element->isExportIdent($answer['ident'])) {
219  $element->setExportIdent($answer['ident']);
220  } else {
221  $element = $element->withPosition($position++);
222  if (isset($answer['answerdepth'])) {
223  $element = $element->withIndentation((int) $answer['answerdepth']);
224  }
225  }
226 
227  if ($this->object->isImageOrderingType()) {
228  $filename = $this->handleUploadedfile($answer);
229  if ($filename !== null) {
230  $element = $element->withContent($filename);
231  }
232  } else {
233  $element = $element->withContent($answer['answertext']);
234  }
235 
236  $element_list->addElement($element);
237  }
238  $this->object->setOrderingElementList($element_list);
239  $points = ($item->getMetadataEntry('points') > 0) ? $item->getMetadataEntry('points') : $points;
240  $this->object->setPoints($points);
241  // additional content editing mode information
242  $this->object->setAdditionalContentEditingMode(
244  );
245  $this->object->saveToDb();
246  $this->importSuggestedSolutions($this->object->getId(), $item->suggested_solutions);
247  foreach ($feedbacksgeneric as $correctness => $material) {
248  $m = $this->QTIMaterialToString($material);
249  $feedbacksgeneric[$correctness] = $m;
250  }
251  $questiontext = $this->object->getQuestion();
252 
253  // handle the import of media objects in XHTML code
254  if (is_array(ilSession::get('import_mob_xhtml'))) {
255  foreach (ilSession::get('import_mob_xhtml') as $mob) {
256  $importfile = $importdirectory . DIRECTORY_SEPARATOR . $mob['uri'];
257 
258  global $DIC; /* @var ILIAS\DI\Container $DIC */
259  $DIC['ilLog']->write(__METHOD__ . ': import mob from dir: ' . $importfile);
260 
261  $media_object = ilObjMediaObject::_saveTempFileAsMediaObject(basename($importfile), $importfile, false);
262  ilObjMediaObject::_saveUsage($media_object->getId(), "qpl:html", $this->object->getId());
263  $questiontext = str_replace("src=\"" . $mob["mob"] . "\"", "src=\"" . "il_" . IL_INST_ID . "_mob_" . $media_object->getId() . "\"", $questiontext);
264  foreach ($this->object->getOrderingElementList() as $element) {
265  $element->setContent(str_replace("src=\"" . $mob["mob"] . "\"", "src=\"" . "il_" . IL_INST_ID . "_mob_" . $media_object->getId() . "\"", $element->getContent()));
266  }
267  foreach ($feedbacksgeneric as $correctness => $material) {
268  $feedbacksgeneric[$correctness] = str_replace("src=\"" . $mob["mob"] . "\"", "src=\"" . "il_" . IL_INST_ID . "_mob_" . $media_object->getId() . "\"", $material);
269  }
270  foreach ($itemfeedbacks as $ident => $material) {
271  $itemfeedbacks[$ident] = str_replace("src=\"" . $mob["mob"] . "\"", "src=\"" . "il_" . IL_INST_ID . "_mob_" . $media_object->getId() . "\"", $material);
272  }
273  }
274  }
275  $this->object->setQuestion(ilRTE::_replaceMediaObjectImageSrc($questiontext, 1));
276  foreach ($this->object->getOrderingElementList() as $element) {
277  $element->setContent(ilRTE::_replaceMediaObjectImageSrc($element->getContent(), 1));
278  }
279  foreach ($feedbacksgeneric as $correctness => $material) {
280  $this->object->feedbackOBJ->importGenericFeedback(
281  $this->object->getId(),
282  $correctness,
284  );
285  }
286  foreach ($itemfeedbacks as $ident => $material) {
287  $index = $this->fetchIndexFromFeedbackIdent($ident, 'link_');
288 
289  $this->object->feedbackOBJ->importSpecificAnswerFeedback(
290  $this->object->getId(),
291  0,
292  $index,
294  );
295  }
296  $this->object->saveToDb();
297  $import_mapping[$item->getIdent()] = $this->addQuestionToParentObjectAndBuildMappingEntry(
298  $questionpool_id,
299  $tst_id,
300  $question_counter,
301  $tst_object
302  );
303  return $import_mapping;
304  }
305 
306  protected function handleUploadedFile(array $answer): ?string
307  {
308  $image = base64_decode($answer["answerimage"]["content"] ?? '');
309  $image_file_name = $answer['answerimage']['label'] ?? '';
310  $tmp_path = ilFileUtils::ilTempnam();
311 
312  $file_handle = fopen($tmp_path, "wb");
313  if ($file_handle === false) {
314  return null;
315  }
316  fwrite($file_handle, $image);
317  fclose($file_handle);
318 
319  $filename_path_parts = explode(".", $image_file_name);
320  $suffix = strtolower(array_pop($filename_path_parts));
321  if (!in_array($suffix, assOrderingQuestion::VALID_UPLOAD_SUFFIXES)) {
322  return null;
323  }
324 
325  $this->ensureImagePathExists();
326  $target_filename = $this->object->buildHashedImageFilename($image_file_name, true);
327  $target_filepath = $this->object->getImagePath() . $target_filename;
328  if (rename($tmp_path, $target_filepath)) {
329  $thumb_path = $this->object->getImagePath() . $this->object->getThumbPrefix() . $target_filename;
330  ilShellUtil::convertImage($target_filepath, $thumb_path, "JPEG", $this->object->getThumbSize());
331  return $target_filename;
332  }
333 
334  return null;
335  }
336 
337  protected function ensureImagePathExists()
338  {
339  if (!file_exists($this->object->getImagePath())) {
340  ilFileUtils::makeDirParents($this->object->getImagePath());
341  }
342  }
343 }
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)
getFeedbackAnswerSpecific(ilQTIItem $item, $prefix='response_')
deduceThumbSizeFromImportValue(?int $size)
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.
fromXML(string $importdirectory, int $user_id, ilQTIItem $item, int $questionpool_id, ?int $tst_id, ?ilObject &$tst_object, int &$question_counter, array $import_mapping)
addQuestionToParentObjectAndBuildMappingEntry(int $questionpool_id, ?int $tst_id, int &$question_counter, ?ilObjTest &$tst_object)
getMetadataEntry(string $a_label)
fetchAdditionalContentEditingModeInformation($qtiItem)
fetches the "additional content editing mode" information from qti item and falls back to ADDITIONAL_...
static _saveUsage(int $a_mob_id, string $a_type, int $a_id, int $a_usage_hist_nr=0, string $a_lang="-")
Save usage of mob within another container (e.g.
$response
Definition: xapitoken.php:93
static makeDirParents(string $a_dir)
Create a new directory and all parent directories.
while($session_entry=$r->fetchRow(ilDBConstants::FETCHMODE_ASSOC)) return null
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
global $DIC
Definition: shib_login.php:26
static convertImage(string $a_from, string $a_to, string $a_target_format="", string $a_geometry="", string $a_background_color="")
$filename
Definition: buildRTE.php:78
importSuggestedSolutions(int $question_id, array $solution_from_import)
static _saveTempFileAsMediaObject(string $name, string $tmp_name, bool $upload=true)
static ilTempnam(?string $a_temp_path=null)
Returns a unique and non existing Path for e temporary file or directory.
Class for question imports.
static clear(string $a_var)
fetchIndexFromFeedbackIdent($feedbackIdent, $prefix='response_')