ILIAS  release_9 Revision v9.13-25-g2c18ec4c24f
class.assQuestionImport.php
Go to the documentation of this file.
1 <?php
2 
23 
34 {
38  public $object;
39 
41 
48  public function __construct($a_object)
49  {
50  $this->object = $a_object;
51 
53  global $DIC;
54  $this->filesystem = $DIC['filesystem']->web();
55  }
56 
57  public function getQuestionId(): int
58  {
59  return (int) $this->object->getId();
60  }
61 
62  public function getFeedbackGeneric($item): array
63  {
64  $feedbacksgeneric = [];
65  foreach ($item->resprocessing as $resprocessing) {
66  foreach ($resprocessing->respcondition as $respcondition) {
67  foreach ($respcondition->displayfeedback as $feedbackpointer) {
68  if (strlen($feedbackpointer->getLinkrefid())) {
69  foreach ($item->itemfeedback as $ifb) {
70  if (strcmp($ifb->getIdent(), "response_allcorrect") == 0) {
71  // found a feedback for the identifier
72  if (count($ifb->material)) {
73  foreach ($ifb->material as $material) {
74  $feedbacksgeneric[1] = $material;
75  }
76  }
77  if ((count($ifb->flow_mat) > 0)) {
78  foreach ($ifb->flow_mat as $fmat) {
79  if (count($fmat->material)) {
80  foreach ($fmat->material as $material) {
81  $feedbacksgeneric[1] = $material;
82  }
83  }
84  }
85  }
86  } elseif (strcmp($ifb->getIdent(), "response_onenotcorrect") == 0) {
87  // found a feedback for the identifier
88  if (count($ifb->material)) {
89  foreach ($ifb->material as $material) {
90  $feedbacksgeneric[0] = $material;
91  }
92  }
93  if ((count($ifb->flow_mat) > 0)) {
94  foreach ($ifb->flow_mat as $fmat) {
95  if (count($fmat->material)) {
96  foreach ($fmat->material as $material) {
97  $feedbacksgeneric[0] = $material;
98  }
99  }
100  }
101  }
102  }
103  }
104  }
105  }
106  }
107  }
108  // handle the import of media objects in XHTML code
109  foreach ($feedbacksgeneric as $correctness => $material) {
110  $m = $this->QTIMaterialToString($material);
111  $feedbacksgeneric[$correctness] = $m;
112  }
113  return $feedbacksgeneric;
114  }
115 
121  protected function fetchIndexFromFeedbackIdent($feedbackIdent, $prefix = 'response_'): int
122  {
123  return (int) str_replace($prefix, '', $feedbackIdent);
124  }
125 
131  protected function getFeedbackAnswerSpecific(ilQTIItem $item, $prefix = 'response_'): array
132  {
133  $feedbacks = [];
134 
135  foreach ($item->itemfeedback as $ifb) {
136  if ($ifb->getIdent() == 'response_allcorrect' || $ifb->getIdent() == 'response_onenotcorrect') {
137  continue;
138  }
139 
140  if ($ifb->getIdent() == $prefix . 'allcorrect' || $ifb->getIdent() == $prefix . 'onenotcorrect') {
141  continue;
142  }
143 
144  if (substr($ifb->getIdent(), 0, strlen($prefix)) != $prefix) {
145  continue;
146  }
147 
148  $ident = $ifb->getIdent();
149 
150  // found a feedback for the identifier
151 
152  if (count($ifb->material)) {
153  foreach ($ifb->material as $material) {
154  $feedbacks[$ident] = $material;
155  }
156  }
157 
158  if ((count($ifb->flow_mat) > 0)) {
159  foreach ($ifb->flow_mat as $fmat) {
160  if (count($fmat->material)) {
161  foreach ($fmat->material as $material) {
162  $feedbacks[$ident] = $material;
163  }
164  }
165  }
166  }
167  }
168 
169  foreach ($feedbacks as $ident => $material) {
170  $m = $this->QTIMaterialToString($material);
171  $feedbacks[$ident] = $m;
172  }
173 
174  return $feedbacks;
175  }
176 
190  public function fromXML(&$item, $questionpool_id, &$tst_id, &$tst_object, &$question_counter, $import_mapping): array
191  {
192  }
193 
197  protected function addGeneralMetadata(ilQTIItem $item): void
198  {
199  if ($item->getMetadataEntry('externalID')) {
200  $this->object->setExternalId($item->getMetadataEntry('externalID'));
201  } else {
202  $this->object->setExternalId($item->getMetadataEntry('externalId'));
203  }
204 
205  $this->object->setLifecycle($this->fetchLifecycle($item));
206  }
207 
213  {
214  try {
216  $item->getMetadataEntry('ilias_lifecycle')
217  );
219  try {
220  $lomLifecycle = new ilAssQuestionLomLifecycle(
221  $item->getMetadataEntry('lifecycle')
222  );
223 
225  $lomLifecycle->getMappedIliasLifecycleIdentifer()
226  );
229  }
230  }
231 
232  return $lifecycle;
233  }
234 
238  protected function getQplImportArchivDirectory(): string
239  {
240  return ilObjQuestionPool::_getImportDirectory() . '/' . ilSession::get("qpl_import_subdir");
241  }
242 
246  protected function getTstImportArchivDirectory(): string
247  {
248  return ilObjTest::_getImportDirectory() . '/' . ilSession::get("tst_import_subdir");
249  }
250 
251  protected function processNonAbstractedImageReferences($text, $sourceNic): string
252  {
253  $reg = '/<img.*src=".*\\/mm_(\\d+)\\/(.*?)".*>/m';
254  $matches = null;
255 
256  if (preg_match_all($reg, $text, $matches)) {
257  $mobs = [];
258  for ($i = 0, $max = count($matches[1]); $i < $max; $i++) {
259  $mobSrcId = $matches[1][$i];
260  $mobSrcName = $matches[2][$i];
261  $mobSrcLabel = 'il_' . $sourceNic . '_mob_' . $mobSrcId;
262 
263  //if (!is_array(ilSession::get("import_mob_xhtml"))) {
264  // ilSession::set("import_mob_xhtml", array());
265  //}
266 
267  //$_SESSION["import_mob_xhtml"][] = array(
268  $mobs[] = [
269  "mob" => $mobSrcLabel, "uri" => 'objects/' . $mobSrcLabel . '/' . $mobSrcName
270  ];
271  }
272  ilSession::set('import_mob_xhtml', $mobs);
273  }
274 
275  return ilRTE::_replaceMediaObjectImageSrc($text, 0, $sourceNic);
276  }
277 
286  final protected function fetchAdditionalContentEditingModeInformation($qtiItem): string
287  {
288  $additionalContentEditingMode = $qtiItem->getMetadataEntry('additional_cont_edit_mode');
289 
290  if (!$this->object->isValidAdditionalContentEditingMode($additionalContentEditingMode ?? '')) {
291  $additionalContentEditingMode = assQuestion::ADDITIONAL_CONTENT_EDITING_MODE_RTE;
292  }
293 
294  return $additionalContentEditingMode;
295  }
296 
297  public function importSuggestedSolutions(
298  int $question_id,
299  array $solution_from_import
300  ): void {
301  if (!$solution_from_import === []
302  || !isset($solution_from_import[0]['solution'])) {
303  return;
304  }
305 
306  $solution_item = $solution_from_import[0]['solution'];
307  $content = $solution_item->getContent();
308  if ($solution_item->getTexttype() === 'application/json') {
309  $content = json_decode($content, true);
310  if (!isset($content['type']) || !isset($content['value'])) {
311  return;
312  }
313  $type = $content['type'];
314  } else {
315  $type = $this->findSolutionTypeByValue($solution_item->getContent());
316  if ($type === null) {
317  return;
318  }
319  }
320 
321  $repo = $this->getSuggestedSolutionsRepo();
322  $solution_object = $repo->create($question_id, $type);
323 
324  if ($type !== assQuestionSuggestedSolution::TYPE_FILE) {
325  $link = is_string($content) ? $content : $content['value'];
326  $adapted_link = $this->object->resolveInternalLink($link);
327  if ($adapted_link === '') {
328  return;
329  }
330  $solution_object = $solution_object
331  ->withInternalLink($adapted_link)
332  ->withImportId($link);
333  } else {
334  if (!isset($content['title']) || !isset($content['filename'])) {
335  return;
336  }
337  $path = str_replace(CLIENT_WEB_DIR . DIRECTORY_SEPARATOR, '', $this->object->getSuggestedSolutionPath() . $content['filename']);
338  $this->filesystem->put($path, base64_decode($content['value']));
339  $solution_object = $solution_object->withTitle($content['title'])
340  ->withFilename($content['filename'])
341  ->withSize((int) $this->filesystem->getSize($path, DataSize::Byte)->inBytes())
342  ->withMime($this->filesystem->getMimeType($path));
343  }
344  $repo->update([$solution_object]);
345  }
346 
347  protected function findSolutionTypeByValue(string $value): ?string
348  {
349  foreach (array_keys(assQuestionSuggestedSolution::TYPES) as $type) {
350  $search_type = '_' . $type . '_';
351  if (strpos($value, $search_type) !== false) {
352  return $type;
353  }
354  }
355  return null;
356  }
357 
358 
361  {
362  if (is_null($this->suggestedsolution_repo)) {
364  $this->suggestedsolution_repo = $dic['question.repo.suggestedsolutions'];
365  }
367  }
368 
373  public function QTIMaterialToString(ilQTIMaterial $a_material): string
374  {
375  $result = "";
376  $mobs = ilSession::get('import_mob_xhtml') ?? [];
377  for ($i = 0; $i < $a_material->getMaterialCount(); $i++) {
378  $material = $a_material->getMaterial($i);
379  if (strcmp($material["type"], "mattext") === 0) {
380  $result .= $material["material"]->getContent();
381  }
382  if (strcmp($material["type"], "matimage") === 0) {
383  $matimage = $material["material"];
384  if (preg_match("/(il_([0-9]+)_mob_([0-9]+))/", $matimage->getLabel(), $matches)) {
385  // import an mediaobject which was inserted using tiny mce
386  //if (!is_array(ilSession::get("import_mob_xhtml"))) {
387  // ilSession::set("import_mob_xhtml", array());
388  //}
389  $mobs[] = ["mob" => $matimage->getLabel(),
390  "uri" => $matimage->getUri()
391  ];
392  }
393  }
394  }
395  ilSession::set('import_mob_xhtml', $mobs);
396  return $result;
397  }
398 
399  protected function deduceThumbSizeFromImportValue(?int $size): int
400  {
401  if ($size === null) {
402  return $this->object->getThumbSize();
403  }
404 
405  if ($size < $this->object->getMinimumThumbSize()) {
406  return $this->object->getMinimumThumbSize();
407  }
408 
409  if ($size > $this->object->getMaximumThumbSize()) {
410  return $this->object->getMaximumThumbSize();
411  }
412 
413  return $size;
414  }
415 }
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)
QTIMaterialToString(ilQTIMaterial $a_material)
Reads an QTI material tag and creates a text or XHTML string.
getMetadataEntry(string $a_label)
processNonAbstractedImageReferences($text, $sourceNic)
fetchAdditionalContentEditingModeInformation($qtiItem)
fetches the "additional content editing mode" information from qti item and falls back to ADDITIONAL_...
getQplImportArchivDirectory()
returns the full path to extracted qpl import archiv (qpl import dir + qpl archiv subdir) ...
getMaterial(int $a_index)
$path
Definition: ltiservices.php:32
global $DIC
Definition: feed.php:28
fetchLifecycle(ilQTIItem $item)
__construct(VocabulariesInterface $vocabularies)
fromXML(&$item, $questionpool_id, &$tst_id, &$tst_object, &$question_counter, $import_mapping)
Creates a question from a QTI file.
const CLIENT_WEB_DIR
Definition: constants.php:47
$lifecycle
importSuggestedSolutions(int $question_id, array $solution_from_import)
assQuestionSuggestedSolutionsDatabaseRepository $suggestedsolution_repo
findSolutionTypeByValue(string $value)
const ADDITIONAL_CONTENT_EDITING_MODE_RTE
$dic
Definition: result.php:32
getTstImportArchivDirectory()
returns the full path to extracted tst import archiv (tst import dir + tst archiv subdir) ...
static _getImportDirectory()
get import directory of lm
Class for question imports.
fetchIndexFromFeedbackIdent($feedbackIdent, $prefix='response_')
static set(string $a_var, $a_val)
Set a value.
static _getImportDirectory()
Get the import directory location of the test.