ILIAS  trunk Revision v11.0_alpha-2645-g16283d3b3f8
assMatchingQuestionImport Class Reference

This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Learning e.V. More...

+ Inheritance diagram for assMatchingQuestionImport:
+ Collaboration diagram for assMatchingQuestionImport:

Public Member Functions

 saveImage ($data, $filename)
 
 fromXML (string $importdirectory, int $user_id, ilQTIItem $item, int $questionpool_id, ?int $tst_id, ?ilObject &$tst_object, int &$question_counter, array $import_mapping)
 
- Public Member Functions inherited from assQuestionImport
 getQuestionId ()
 
 getFeedbackGeneric ($item)
 
 fromXML (string $importdirectory, int $user_id, ilQTIItem $item, int $questionpool_id, ?int $tst_id, ?ilObject &$tst_object, int &$question_counter, array $import_mapping)
 
 importSuggestedSolutions (int $question_id, array $solution_from_import)
 
 QTIMaterialToString (ilQTIMaterial $a_material)
 Reads an QTI material tag and creates a text or XHTML string. More...
 

Protected Member Functions

 fetchIndexFromFeedbackIdent ($feedbackIdent, $prefix='response_')
 
- Protected Member Functions inherited from assQuestionImport
 fetchIndexFromFeedbackIdent ($feedbackIdent, $prefix='response_')
 
 getFeedbackAnswerSpecific (ilQTIItem $item, $prefix='response_')
 
 addGeneralMetadata (ilQTIItem $item)
 
 fetchLifecycle (ilQTIItem $item)
 
 processNonAbstractedImageReferences ($text, $sourceNic)
 
 fetchAdditionalContentEditingModeInformation ($qtiItem)
 fetches the "additional content editing mode" information from qti item and falls back to ADDITIONAL_CONTENT_EDITING_MODE_RTE when no or invalid information is given More...
 
 findSolutionTypeByValue (string $value)
 
 getSuggestedSolutionsRepo ()
 
 deduceThumbSizeFromImportValue (?int $size)
 
 addQuestionToParentObjectAndBuildMappingEntry (int $questionpool_id, ?int $tst_id, int &$question_counter, ?ilObjTest &$tst_object)
 

Additional Inherited Members

- Data Fields inherited from assQuestionImport
 $object
 
- Protected Attributes inherited from assQuestionImport
SuggestedSolutionsDatabaseRepository $suggestedsolution_repo = null
 

Detailed Description

This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Learning e.V.

ILIAS is licensed with the GPL-3.0, see https://www.gnu.org/licenses/gpl-3.0.en.html You should have received a copy of said license along with the source code, too.

If this is not the case or you just want to try ILIAS, you'll find us at: https://www.ilias.de https://github.com/ILIAS-eLearning Class for matching question imports

assMatchingQuestionImport is a class for matching question imports

Author
Helmut Schottmüller helmu.nosp@m.t.sc.nosp@m.hottm.nosp@m.uell.nosp@m.er@ma.nosp@m.c.co.nosp@m.m
Version
$Id$ \

Definition at line 28 of file class.assMatchingQuestionImport.php.

Member Function Documentation

◆ fetchIndexFromFeedbackIdent()

assMatchingQuestionImport::fetchIndexFromFeedbackIdent (   $feedbackIdent,
  $prefix = 'response_' 
)
protected
Parameters
$feedbackIdent
string$prefix
Returns
int

Definition at line 314 of file class.assMatchingQuestionImport.php.

References ILIAS\Repository\object().

Referenced by fromXML().

314  : int
315  {
316  list($termId, $definitionId) = explode('_', str_replace($prefix, '', $feedbackIdent));
317 
318  foreach ($this->object->getMatchingPairs() as $index => $pair) {
319  /* @var assAnswerMatchingPair $pair */
320 
321  if ($pair->getTerm()->getIdentifier() != $termId) {
322  continue;
323  }
324 
325  if ($pair->getDefinition()->getIdentifier() != $definitionId) {
326  continue;
327  }
328 
329  return (int) $index;
330  }
331 
332  return -1;
333  }
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ fromXML()

assMatchingQuestionImport::fromXML ( string  $importdirectory,
int  $user_id,
ilQTIItem  $item,
int  $questionpool_id,
?int  $tst_id,
?ilObject $tst_object,
int &  $question_counter,
array  $import_mapping 
)

Definition at line 46 of file class.assMatchingQuestionImport.php.

References $DIC, $response, ilRTE\_replaceMediaObjectImageSrc(), ilObjMediaObject\_saveTempFileAsMediaObject(), ilObjMediaObject\_saveUsage(), assQuestionImport\addGeneralMetadata(), assQuestionImport\addQuestionToParentObjectAndBuildMappingEntry(), ilSession\clear(), assQuestionImport\deduceThumbSizeFromImportValue(), assQuestionImport\fetchAdditionalContentEditingModeInformation(), fetchIndexFromFeedbackIdent(), ilSession\get(), ilQTIItem\getAuthor(), ilQTIItem\getComment(), assQuestionImport\getFeedbackAnswerSpecific(), ilQTIItem\getIdent(), ilQTIItem\getMaxattempts(), ilQTIItem\getMetadataEntry(), ilQTIItem\getPresentation(), ilQTIItem\getQuestiontext(), ilQTIItem\getTitle(), IL_INST_ID, assQuestionImport\importSuggestedSolutions(), assMatchingQuestion\MATCHING_MODE_1_ON_1, ILIAS\Repository\object(), assQuestionImport\QTIMaterialToString(), and saveImage().

55  : array {
56  // empty session variable for imported xhtml mobs
57  ilSession::clear('import_mob_xhtml');
58  $presentation = $item->getPresentation();
59  $shuffle = 0;
60  $definitions = [];
61  $terms = [];
62  $foundimage = false;
63  foreach ($presentation->order as $entry) {
64  switch ($entry["type"]) {
65  case "response":
66  $response = $presentation->response[$entry["index"]];
67  $rendertype = $response->getRenderType();
68  switch (strtolower(get_class($rendertype))) {
69  case "ilqtirenderchoice":
70  $shuffle = $rendertype->getShuffle();
71  $answerorder = 0;
72  foreach ($rendertype->response_labels as $response_label) {
73  $ident = $response_label->getIdent();
74  $answertext = "";
75  $answerimage = [];
76  foreach ($response_label->material as $mat) {
77  for ($m = 0; $m < $mat->getMaterialCount(); $m++) {
78  $foundmat = $mat->getMaterial($m);
79  if (strcmp($foundmat["type"], "mattext") == 0) {
80  $answertext .= $foundmat["material"]->getContent();
81  }
82  if (strcmp($foundmat["type"], "matimage") == 0) {
83  $foundimage = true;
84  $answerimage = [
85  "imagetype" => $foundmat["material"]->getImageType(),
86  "label" => $foundmat["material"]->getLabel(),
87  "content" => $foundmat["material"]->getContent()
88  ];
89  }
90  }
91  }
92  if (($response_label->getMatchMax() == 1) && (strlen($response_label->getMatchGroup()))) {
93  $definitions[$ident] = [
94  "answertext" => $answertext,
95  "answerimage" => $answerimage,
96  "points" => 0,
97  "answerorder" => $ident,
98  "action" => ""
99  ];
100  } else {
101  $terms[$ident] = [
102  "term" => $answertext,
103  "answerimage" => $answerimage,
104  "points" => 0,
105  "ident" => $ident,
106  "action" => ""
107  ];
108  }
109  }
110  break;
111  }
112  break;
113  }
114  }
115  $responses = [];
116  $feedbacksgeneric = [];
117  foreach ($item->resprocessing as $resprocessing) {
118  foreach ($resprocessing->respcondition as $respcondition) {
119  $subset = [];
120  $correctness = 1;
121  $conditionvar = $respcondition->getConditionvar();
122  foreach ($conditionvar->order as $order) {
123  switch ($order["field"]) {
124  case "varsubset":
125  $subset = explode(",", $conditionvar->varsubset[$order["index"]]->getContent());
126  break;
127  }
128  }
129  foreach ($respcondition->setvar as $setvar) {
130  array_push($responses, ["subset" => $subset, "action" => $setvar->getAction(), "points" => $setvar->getContent()]);
131  }
132 
133  if (count($respcondition->displayfeedback)) {
134  foreach ($respcondition->displayfeedback as $feedbackpointer) {
135  if (strlen($feedbackpointer->getLinkrefid())) {
136  foreach ($item->itemfeedback as $ifb) {
137  if (strcmp($ifb->getIdent(), "response_allcorrect") == 0) {
138  // found a feedback for the identifier
139  if (count($ifb->material)) {
140  foreach ($ifb->material as $material) {
141  $feedbacksgeneric[1] = $material;
142  }
143  }
144  if ((count($ifb->flow_mat) > 0)) {
145  foreach ($ifb->flow_mat as $fmat) {
146  if (count($fmat->material)) {
147  foreach ($fmat->material as $material) {
148  $feedbacksgeneric[1] = $material;
149  }
150  }
151  }
152  }
153  } elseif (strcmp($ifb->getIdent(), "response_onenotcorrect") == 0) {
154  // found a feedback for the identifier
155  if (count($ifb->material)) {
156  foreach ($ifb->material as $material) {
157  $feedbacksgeneric[0] = $material;
158  }
159  }
160  if ((count($ifb->flow_mat) > 0)) {
161  foreach ($ifb->flow_mat as $fmat) {
162  if (count($fmat->material)) {
163  foreach ($fmat->material as $material) {
164  $feedbacksgeneric[0] = $material;
165  }
166  }
167  }
168  }
169  }
170  }
171  }
172  }
173  }
174  }
175  }
176 
177  $this->object->createNewQuestion();
178  $this->addGeneralMetadata($item);
179  $this->object->setTitle($item->getTitle());
180  $this->object->setNrOfTries((int) $item->getMaxattempts());
181  $this->object->setComment($item->getComment());
182  $this->object->setAuthor($item->getAuthor());
183  $this->object->setOwner($user_id);
184  $this->object->setQuestion($this->QTIMaterialToString($item->getQuestiontext()));
185  $this->object->setObjId($questionpool_id);
186  $extended_shuffle = $item->getMetadataEntry('shuffle');
187  $this->object->setThumbGeometry(
188  $this->deduceThumbSizeFromImportValue((int) $item->getMetadataEntry('thumb_geometry'))
189  );
190 
191  if (strlen($item->getMetadataEntry('matching_mode'))) {
192  $this->object->setMatchingMode($item->getMetadataEntry('matching_mode'));
193  } else {
194  $this->object->setMatchingMode(assMatchingQuestion::MATCHING_MODE_1_ON_1);
195  }
196 
197  // save images
198  foreach ($terms as $term) {
199  if (count($term['answerimage'])) {
200  $this->saveImage($term['answerimage']['content'], $term['answerimage']['label']);
201  }
202  }
203  foreach ($definitions as $definition) {
204  if (count($definition['answerimage'])) {
205  $this->saveImage($definition['answerimage']['content'], $definition['answerimage']['label']);
206  }
207  }
208 
209  foreach ($terms as $termindex => $term) {
210  // @PHP8-CR: If you look above, how $this->object->addDefinition does in fact take an object, I take this
211  // issue as an indicator for a bigger issue and won't suppress / "quickfix" this but postpone further
212  // analysis, eventually involving T&A TechSquad (see also remark in assMatchingQuestionGUI
213  $this->object->addTerm(new assAnswerMatchingTerm($term["term"], $term['answerimage']['label'] ?? '', $term["ident"]));
214  }
215  foreach ($definitions as $definitionindex => $definition) {
216  $this->object->addDefinition(new assAnswerMatchingDefinition($definition["answertext"], $definition['answerimage']['label'] ?? '', $definition["answerorder"]));
217  }
218 
219  if (strlen($extended_shuffle) > 0) {
220  $shuffle = $extended_shuffle;
221  }
222  $this->object->setShuffle($shuffle);
223 
224  foreach ($responses as $response) {
225  $subset = $response["subset"];
226  foreach ($subset as $ident) {
227  if (array_key_exists($ident, $definitions)) {
228  $definition = $definitions[$ident];
229  }
230  if (array_key_exists($ident, $terms)) {
231  $term = $terms[$ident];
232  }
233  }
234  $this->object->addMatchingPair(new assAnswerMatchingTerm('', '', (float) $term["ident"]), new assAnswerMatchingDefinition('', '', (int) $definition["answerorder"]), (float) $response['points']);
235  }
236  // additional content editing mode information
237  $this->object->setAdditionalContentEditingMode(
239  );
240  $this->object->saveToDb();
241  $this->importSuggestedSolutions($this->object->getId(), $item->suggested_solutions);
242  foreach ($responses as $response) {
243  $subset = $response["subset"];
244  foreach ($subset as $ident) {
245  if (array_key_exists($ident, $definitions)) {
246  $definition = $definitions[$ident];
247  }
248  if (array_key_exists($ident, $terms)) {
249  $term = $terms[$ident];
250  }
251  }
252  }
253 
254  foreach ($feedbacksgeneric as $correctness => $material) {
255  $m = $this->QTIMaterialToString($material);
256  $feedbacksgeneric[$correctness] = $m;
257  }
258 
259  $feedbacks = $this->getFeedbackAnswerSpecific($item, 'correct_');
260 
261  // handle the import of media objects in XHTML code
262  $questiontext = $this->object->getQuestion();
263  if (is_array(ilSession::get("import_mob_xhtml"))) {
264  foreach (ilSession::get("import_mob_xhtml") as $mob) {
265  $importfile = $importdirectory . DIRECTORY_SEPARATOR . $mob["uri"];
266 
267  global $DIC; /* @var ILIAS\DI\Container $DIC */
268  $DIC['ilLog']->write(__METHOD__ . ': import mob from dir: ' . $importfile);
269 
270  $media_object = ilObjMediaObject::_saveTempFileAsMediaObject(basename($importfile), $importfile, false);
271  ilObjMediaObject::_saveUsage($media_object->getId(), "qpl:html", $this->object->getId());
272  $questiontext = str_replace("src=\"" . $mob["mob"] . "\"", "src=\"" . "il_" . IL_INST_ID . "_mob_" . $media_object->getId() . "\"", $questiontext);
273  foreach ($feedbacks as $ident => $material) {
274  $feedbacks[$ident] = str_replace("src=\"" . $mob["mob"] . "\"", "src=\"" . "il_" . IL_INST_ID . "_mob_" . $media_object->getId() . "\"", $material);
275  }
276  foreach ($feedbacksgeneric as $correctness => $material) {
277  $feedbacksgeneric[$correctness] = str_replace("src=\"" . $mob["mob"] . "\"", "src=\"" . "il_" . IL_INST_ID . "_mob_" . $media_object->getId() . "\"", $material);
278  }
279  }
280  }
281  $this->object->setQuestion(ilRTE::_replaceMediaObjectImageSrc($questiontext, 1));
282  foreach ($feedbacks as $ident => $material) {
283  $index = $this->fetchIndexFromFeedbackIdent($ident, 'correct_');
284 
285  $this->object->feedbackOBJ->importSpecificAnswerFeedback(
286  $this->object->getId(),
287  0,
288  $index,
290  );
291  }
292  foreach ($feedbacksgeneric as $correctness => $material) {
293  $this->object->feedbackOBJ->importGenericFeedback(
294  $this->object->getId(),
295  $correctness,
297  );
298  }
299  $this->object->saveToDb();
300  $import_mapping[$item->getIdent()] = $this->addQuestionToParentObjectAndBuildMappingEntry(
301  $questionpool_id,
302  $tst_id,
303  $question_counter,
304  $tst_object
305  );
306  return $import_mapping;
307  }
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...
Class for matching question terms.
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.
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
global $DIC
Definition: shib_login.php:26
fetchIndexFromFeedbackIdent($feedbackIdent, $prefix='response_')
importSuggestedSolutions(int $question_id, array $solution_from_import)
static _saveTempFileAsMediaObject(string $name, string $tmp_name, bool $upload=true)
Class for matching question definitions.
static clear(string $a_var)
+ Here is the call graph for this function:

◆ saveImage()

assMatchingQuestionImport::saveImage (   $data,
  $filename 
)

Definition at line 30 of file class.assMatchingQuestionImport.php.

References $data, $filename, and ilFileUtils\makeDirParents().

Referenced by fromXML().

30  : void
31  {
32  $image = base64_decode($data);
33  $imagepath = $this->object->getImagePath();
34  if (!file_exists($imagepath)) {
35  ilFileUtils::makeDirParents($imagepath);
36  }
37  $imagepath .= $filename;
38  $fh = fopen($imagepath, "wb");
39  if ($fh == false) {
40  } else {
41  $imagefile = fwrite($fh, $image);
42  fclose($fh);
43  }
44  }
static makeDirParents(string $a_dir)
Create a new directory and all parent directories.
$filename
Definition: buildRTE.php:78
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

The documentation for this class was generated from the following file: