ILIAS  release_9 Revision v9.13-25-g2c18ec4c24f
class.assOrderingQuestion.php
Go to the documentation of this file.
1 <?php
2 
19 require_once './Modules/Test/classes/inc.AssessmentConstants.php';
20 
22 
38 {
39  public const ORDERING_ELEMENT_FORM_FIELD_POSTVAR = 'order_elems';
40 
41  public const ORDERING_ELEMENT_FORM_CMD_UPLOAD_IMG = 'uploadElementImage';
42  public const ORDERING_ELEMENT_FORM_CMD_REMOVE_IMG = 'removeElementImage'; //might actually go away - use ORDERING_ELEMENT_FORM_CMD_UPLOAD_IMG
43 
44  public const OQ_PICTURES = 0;
45  public const OQ_TERMS = 1;
46  public const OQ_NESTED_PICTURES = 2;
47  public const OQ_NESTED_TERMS = 3;
48 
49  public const OQ_CT_PICTURES = 'pics';
50  public const OQ_CT_TERMS = 'terms';
51 
52  public const VALID_UPLOAD_SUFFIXES = ["jpg", "jpeg", "png", "gif"];
53 
54  protected const HAS_SPECIFIC_FEEDBACK = false;
55 
56 
61 
66  protected $ordering_type;
67 
68  public ?int $element_height = null;
69 
70  public $old_ordering_depth = array();
71  public $leveled_ordering = array();
72 
76  protected $oq_repository = null;
77 
90  public function __construct(
91  $title = "",
92  $comment = "",
93  $author = "",
94  $owner = -1,
95  $question = "",
97  ) {
99  $this->orderingElementList = new ilAssOrderingElementList();
100  $this->ordering_type = $ordering_type;
101  }
102 
108  public function isComplete(): bool
109  {
110  $elements = array_filter(
111  $this->getOrderingElementList()->getElements(),
112  fn($element) => trim($element->getContent()) != ''
113  );
114  $has_at_least_two_elements = count($elements) > 1;
115 
116  $complete = $this->getAuthor()
117  && $this->getTitle()
118  && $this->getQuestion()
119  && $this->getMaximumPoints()
120  && $has_at_least_two_elements;
121 
122  return $complete;
123  }
124 
125 
126 
127  protected function getRepository(): ILIAS\TA\Questions\Ordering\assOrderingQuestionDatabaseRepository
128  {
129  if (is_null($this->oq_repository)) {
130  global $DIC;
131  $ilDB = $DIC['ilDB'];
132  $this->oq_repository = new OQRepository($ilDB);
133  }
134  return $this->oq_repository;
135  }
136 
137 
145  public function saveToDb($original_id = ""): void
146  {
147  if ($original_id == '') {
148  $this->saveQuestionDataToDb();
149  } else {
150  $this->saveQuestionDataToDb((int) $original_id);
151  }
153  parent::saveToDb();
154  }
155 
163  public function loadFromDb($question_id): void
164  {
165  global $DIC;
166  $ilDB = $DIC['ilDB'];
167 
168  $result = $ilDB->queryF(
169  "SELECT qpl_questions.*, " . $this->getAdditionalTableName() . ".* FROM qpl_questions LEFT JOIN " . $this->getAdditionalTableName() . " ON " . $this->getAdditionalTableName() . ".question_fi = qpl_questions.question_id WHERE qpl_questions.question_id = %s",
170  array("integer"),
171  array($question_id)
172  );
173  if ($result->numRows() == 1) {
174  $data = $ilDB->fetchAssoc($result);
175  $this->setId($question_id);
176  $this->setObjId($data["obj_fi"]);
177  $this->setTitle((string) $data["title"]);
178  $this->setComment((string) $data["description"]);
179  $this->setOriginalId($data["original_id"]);
180  $this->setAuthor($data["author"]);
181  $this->setNrOfTries($data['nr_of_tries']);
182  $this->setPoints($data["points"]);
183  $this->setOwner($data["owner"]);
184  $this->setQuestion(ilRTE::_replaceMediaObjectImageSrc((string) $data["question_text"], 1));
185  $this->ordering_type = $data["ordering_type"] !== null ? (int) $data["ordering_type"] : OQ_TERMS;
186  if ($data['thumb_geometry'] !== null && $data['thumb_geometry'] >= $this->getMinimumThumbSize()) {
187  $this->setThumbSize($data['thumb_geometry']);
188  }
189  $this->element_height = $data["element_height"] ? (int) $data['element_height'] : null;
190 
191  try {
192  $this->setLifecycle(ilAssQuestionLifecycle::getInstance($data['lifecycle']));
195  }
196 
197  try {
198  $this->setAdditionalContentEditingMode($data['add_cont_edit_mode']);
199  } catch (ilTestQuestionPoolException $e) {
200  }
201  }
202 
203  parent::loadFromDb($question_id);
204  }
205 
206  public function duplicate(
207  bool $for_test = true,
208  ?string $title = "",
209  ?string $author = "",
210  ?int $owner = -1,
211  $testObjId = null
212  ): int {
213  if ($this->id <= 0) {
214  // The question has not been saved. It cannot be duplicated
215  return -1;
216  }
217  // duplicate the question in database
218  $this_id = $this->getId();
219  $thisObjId = $this->getObjId();
220 
221  $clone = clone $this;
222  $original_id = $this->questioninfo->getOriginalId($this->id);
223  $clone->id = -1;
224 
225  if ((int) $testObjId > 0) {
226  $clone->setObjId($testObjId);
227  }
228 
229  if ($title) {
230  $clone->setTitle($title);
231  }
232  if ($author) {
233  $clone->setAuthor($author);
234  }
235  if ($owner) {
236  $clone->setOwner($owner);
237  }
238  if ($for_test) {
239  $clone->saveToDb($original_id);
240  } else {
241  $clone->saveToDb();
242  }
243 
244  //$list = $this->getRepository()->getOrderingList($original_id)
245  $list = $this->getRepository()->getOrderingList($this_id)
246  ->withQuestionId($clone->getId());
247  $list->distributeNewRandomIdentifiers();
248  $clone->setOrderingElementList($list);
249  $clone->saveToDb();
250 
251  $clone->copyPageOfQuestion($this_id);
252  $clone->copyXHTMLMediaObjectsOfQuestion($this_id);
253  $clone->duplicateImages($this_id, $thisObjId, $clone->getId(), $testObjId);
254 
255  $clone->onDuplicate($thisObjId, $this_id, $clone->getObjId(), $clone->getId());
256  return $clone->getId();
257  }
258 
264  public function copyObject($target_questionpool_id, $title = ""): int
265  {
266  if ($this->getId() <= 0) {
267  throw new RuntimeException('The question has not been saved. It cannot be duplicated');
268  }
269  // duplicate the question in database
270  $clone = clone $this;
271  $this_id = $this->getId();
272  $original_id = $this->questioninfo->getOriginalId($this_id);
273  $clone->id = -1;
274  $source_questionpool_id = $this->getObjId();
275  $clone->setObjId($target_questionpool_id);
276  if ($title) {
277  $clone->setTitle($title);
278  }
279  $clone->saveToDb();
280 
281  $list = $this->getRepository()->getOrderingList($this_id)
282  ->withQuestionId($clone->getId());
283  $list->distributeNewRandomIdentifiers();
284  $clone->setOrderingElementList($list);
285  $clone->saveToDb();
286 
287  $clone->copyPageOfQuestion($original_id);
288  $clone->copyXHTMLMediaObjectsOfQuestion($original_id);
289  $clone->duplicateImages($original_id, $source_questionpool_id, $clone->getId(), $target_questionpool_id);
290 
291  $clone->onCopy($source_questionpool_id, $original_id, $clone->getObjId(), $clone->getId());
292 
293  return $clone->getId();
294  }
295 
296  public function createNewOriginalFromThisDuplicate($targetParentId, $targetQuestionTitle = ""): int
297  {
298  if ($this->getId() <= 0) {
299  throw new RuntimeException('The question has not been saved. It cannot be duplicated');
300  }
301 
302  $sourceQuestionId = $this->id;
303  $sourceParentId = $this->getObjId();
304 
305  // duplicate the question in database
306  $clone = clone $this;
307  $clone->id = -1;
308 
309  $clone->setObjId($targetParentId);
310 
311  if ($targetQuestionTitle) {
312  $clone->setTitle($targetQuestionTitle);
313  }
314 
315  $clone->saveToDb();
316 
317  $list = $this->getRepository()->getOrderingList($this->getId())
318  ->withQuestionId($clone->getId());
319  $list->distributeNewRandomIdentifiers();
320  $clone->setOrderingElementList($list);
321  $clone->saveToDb();
322 
323  // copy question page content
324  $clone->copyPageOfQuestion($sourceQuestionId);
325  // copy XHTML media objects
326  $clone->copyXHTMLMediaObjectsOfQuestion($sourceQuestionId);
327  // duplicate the image
328  $clone->duplicateImages($sourceQuestionId, $sourceParentId, $clone->getId(), $clone->getObjId());
329 
330  $clone->onCopy($sourceParentId, $sourceQuestionId, $clone->getObjId(), $clone->getId());
331 
332  return $clone->id;
333  }
334 
335  public function duplicateImages($src_question_id, $src_object_id, $dest_question_id, $dest_object_id): void
336  {
337  global $DIC;
338  $ilLog = $DIC['ilLog'];
339  if ($this->isImageOrderingType()) {
340  $imagepath_original = $this->getImagePath($src_question_id, $src_object_id);
341  $imagepath = $this->getImagePath($dest_question_id, $dest_object_id);
342 
343  if (!file_exists($imagepath)) {
344  ilFileUtils::makeDirParents($imagepath);
345  }
346  foreach ($this->getOrderingElementList() as $element) {
347  $filename = $element->getContent();
348 
349  if ($filename === '') {
350  continue;
351  }
352 
353  if (!file_exists($imagepath_original . $filename)
354  || !copy($imagepath_original . $filename, $imagepath . $filename)) {
355  $ilLog->write("image could not be duplicated!!!!");
356  $ilLog->write($imagepath_original . $filename);
357  $ilLog->write($imagepath . $filename);
358  }
359  if (file_exists($imagepath_original . $this->getThumbPrefix() . $filename)
360  && !copy($imagepath_original . $this->getThumbPrefix() . $filename, $imagepath . $this->getThumbPrefix() . $filename)) {
361  $ilLog->write("image thumbnail could not be duplicated!!!!");
362  }
363  }
364  }
365  }
366 
372  public function copyImages($question_id, $source_questionpool): void
373  {
374  global $DIC;
375  $ilLog = $DIC['ilLog'];
376  if ($this->getOrderingType() == OQ_PICTURES) {
377  $imagepath = $this->getImagePath();
378  $imagepath_original = str_replace("/$this->id/images", "/$question_id/images", $imagepath);
379  $imagepath_original = str_replace("/$this->obj_id/", "/$source_questionpool/", $imagepath_original);
380  if (!file_exists($imagepath)) {
381  ilFileUtils::makeDirParents($imagepath);
382  }
383  foreach ($this->getOrderingElementList() as $element) {
384  $filename = $element->getContent();
385  if (!@copy($imagepath_original . $filename, $imagepath . $filename)) {
386  $ilLog->write('Ordering Question image could not be copied: ' . $imagepath_original . ${filename});
387  }
388  if (@file_exists($imagepath_original . $this->getThumbPrefix() . $filename)) {
389  if (!@copy($imagepath_original . $this->getThumbPrefix() . $filename, $imagepath . $this->getThumbPrefix() . $filename)) {
390  $ilLog->write('Ordering Question image thumbnail could not be copied: ' . $imagepath_original . $this->getThumbPrefix() . $filename);
391  }
392  }
393  }
394  }
395  }
396 
397  protected function getValidOrderingTypes(): array
398  {
399  return [
404  ];
405  }
406 
408  {
409  if (!in_array($ordering_type, $this->getValidOrderingTypes())) {
410  throw new \InvalidArgumentException('Must be valid ordering type.');
411  }
412  $this->ordering_type = $ordering_type;
413  }
414 
415  public function getOrderingType(): int
416  {
417  return $this->ordering_type;
418  }
419 
420  public function isOrderingTypeNested(): bool
421  {
422  $nested = [
425  ];
426  return in_array($this->getOrderingType(), $nested);
427  }
428 
429  public function isImageOrderingType(): bool
430  {
431  $with_images = [
434  ];
435  return in_array($this->getOrderingType(), $with_images);
436  }
437 
438  public function setContentType($ct)
439  {
440  if (!in_array($ct, [
441  self::OQ_CT_PICTURES,
442  self::OQ_CT_TERMS
443  ])) {
444  throw new \InvalidArgumentException("use OQ content-type", 1);
445  }
446  if ($ct == self::OQ_CT_PICTURES) {
447  if ($this->isOrderingTypeNested()) {
449  } else {
451  }
452  $this->setThumbSize($this->getThumbSize());
453  }
454  if ($ct == self::OQ_CT_TERMS) {
455  if ($this->isOrderingTypeNested()) {
457  } else {
459  }
460  }
461  }
462 
463  public function setNestingType(bool $nesting)
464  {
465  if ($nesting) {
466  if ($this->isImageOrderingType()) {
468  } else {
470  }
471  } else {
472  if ($this->isImageOrderingType()) {
474  } else {
476  }
477  }
478  }
479 
480  public function hasOrderingTypeUploadSupport(): bool
481  {
482  return $this->isImageOrderingType();
483  }
484 
491  public function getOrderingElementListForSolutionOutput($forceCorrectSolution, $activeId, $passIndex): ilAssOrderingElementList
492  {
493  if ($forceCorrectSolution || !$activeId || $passIndex === null) {
494  return $this->getOrderingElementList();
495  }
496 
497  $solutionValues = $this->getSolutionValues($activeId, $passIndex);
498 
499  if (!count($solutionValues)) {
500  return $this->getShuffledOrderingElementList();
501  }
502 
503  return $this->getSolutionOrderingElementList($this->fetchIndexedValuesFromValuePairs($solutionValues));
504  }
505 
516  {
517  if ($inputGUI->isPostSubmit($lastPost)) {
518  return $this->fetchSolutionListFromFormSubmissionData($lastPost);
519  }
520  $indexedSolutionValues = $this->fetchIndexedValuesFromValuePairs(
521  // hey: prevPassSolutions - obsolete due to central check
522  $this->getTestOutputSolutions($activeId, $pass)
523  // hey.
524  );
525 
526  if (count($indexedSolutionValues)) {
527  return $this->getSolutionOrderingElementList($indexedSolutionValues);
528  }
529 
530  return $this->getShuffledOrderingElementList();
531  }
532 
539  {
540  $value2 = explode(':', $value2);
541 
542  $randomIdentifier = $value2[0];
543  $selectedPosition = $value1;
544  $selectedIndentation = $value2[1];
545 
546  $element = $this->getOrderingElementList()->getElementByRandomIdentifier($randomIdentifier)->getClone();
547 
548  $element->setPosition($selectedPosition);
549  $element->setIndentation($selectedIndentation);
550 
551  return $element;
552  }
553 
560  {
561  $solutionIdentifier = $value1;
562  $selectedPosition = ($value2 - 1);
563  $selectedIndentation = 0;
564 
565  $element = $this->getOrderingElementList()->getElementBySolutionIdentifier($solutionIdentifier)->getClone();
566 
567  $element->setPosition($selectedPosition);
568  $element->setIndentation($selectedIndentation);
569 
570  return $element;
571  }
572 
578  public function getSolutionOrderingElementList($indexedSolutionValues): ilAssOrderingElementList
579  {
580  $solutionOrderingList = new ilAssOrderingElementList();
581  $solutionOrderingList->setQuestionId($this->getId());
582 
583  foreach ($indexedSolutionValues as $value1 => $value2) {
584  if ($this->isOrderingTypeNested()) {
585  $element = $this->getSolutionValuePairBrandedOrderingElementByRandomIdentifier($value1, $value2);
586  } else {
587  $element = $this->getSolutionValuePairBrandedOrderingElementBySolutionIdentifier($value1, $value2);
588  }
589 
590  $solutionOrderingList->addElement($element);
591  }
592 
593  if (!$this->getOrderingElementList()->hasSameElementSetByRandomIdentifiers($solutionOrderingList)) {
594  throw new ilTestQuestionPoolException('inconsistent solution values given');
595  }
596 
597  return $solutionOrderingList;
598  }
599 
606  {
607  $shuffledRandomIdentifierIndex = $this->getShuffler()->transform(
608  $this->getOrderingElementList()->getRandomIdentifierIndex()
609  );
610 
611  $shuffledElementList = $this->getOrderingElementList()->getClone();
612  $shuffledElementList->reorderByRandomIdentifiers($shuffledRandomIdentifierIndex);
613  $shuffledElementList->resetElementsIndentations();
614 
615  return $shuffledElementList;
616  }
617 
622  {
623  return $this->getRepository()->getOrderingList($this->getId());
624  }
625 
630  {
631  $list = $list->withQuestionId($this->getId());
632  $elements = $list->getElements();
633  $nu = [];
634  foreach ($elements as $e) {
635  $nu[] = $list->ensureValidIdentifiers($e);
636  }
637  $list = $list->withElements($nu);
638  $this->getRepository()->updateOrderingList($list);
639  }
640 
647  public function getAnswer($index = 0): ?ilAssOrderingElement
648  {
649  if (!$this->getOrderingElementList()->elementExistByPosition($index)) {
650  return null;
651  }
652 
653  return $this->getOrderingElementList()->getElementByPosition($index);
654  }
655 
664  public function deleteAnswer($randomIdentifier): void
665  {
666  $this->getOrderingElementList()->removeElement(
667  $this->getOrderingElementList()->getElementByRandomIdentifier($randomIdentifier)
668  );
669  $this->getOrderingElementList()->saveToDb();
670  }
671 
679  public function getAnswerCount(): int
680  {
681  return $this->getOrderingElementList()->countElements();
682  }
683 
694  public function calculateReachedPoints($active_id, $pass = null, $authorizedSolution = true, $returndetails = false): float
695  {
696  if ($returndetails) {
697  throw new ilTestException('return details not implemented for ' . __METHOD__);
698  }
699 
700  if (is_null($pass)) {
701  $pass = $this->getSolutionMaxPass($active_id);
702  }
703 
704  $solutionValuePairs = $this->getSolutionValues($active_id, $pass, $authorizedSolution);
705 
706  if (!count($solutionValuePairs)) {
707  return (float) 0;
708  }
709 
710  $indexedSolutionValues = $this->fetchIndexedValuesFromValuePairs($solutionValuePairs);
711  $solutionOrderingElementList = $this->getSolutionOrderingElementList($indexedSolutionValues);
712 
713  return $this->calculateReachedPointsForSolution($solutionOrderingElementList);
714  }
715 
717  {
718  if (!$previewSession->hasParticipantSolution()) {
719  return 0;
720  }
721 
722  $solutionOrderingElementList = unserialize(
723  $previewSession->getParticipantsSolution(),
724  ["allowed_classes" => true]
725  );
726 
727  $reachedPoints = $this->calculateReachedPointsForSolution($solutionOrderingElementList);
728  $reachedPoints = $this->deductHintPointsFromReachedPoints($previewSession, $reachedPoints);
729 
730  return $this->ensureNonNegativePoints($reachedPoints);
731  }
732 
739  public function getMaximumPoints(): float
740  {
741  return $this->getPoints();
742  }
743 
744  /*
745  * Returns the encrypted save filename of a matching picture
746  * Images are saved with an encrypted filename to prevent users from
747  * cheating by guessing the solution from the image filename
748  *
749  * @param string $filename Original filename
750  * @return string Encrypted filename
751  */
752  public function getEncryptedFilename($filename): string
753  {
754  $extension = "";
755  if (preg_match("/.*\\.(\\w+)$/", $filename, $matches)) {
756  $extension = $matches[1];
757  }
758  return md5($filename) . "." . $extension;
759  }
760 
761  protected function cleanImagefiles(): void
762  {
763  if ($this->getOrderingType() == self::OQ_PICTURES) {
764  if (@file_exists($this->getImagePath())) {
765  $contents = ilFileUtils::getDir($this->getImagePath());
766  foreach ($contents as $f) {
767  if (strcmp($f['type'], 'file') == 0) {
768  $found = false;
769  foreach ($this->getOrderingElementList() as $orderElement) {
770  if (strcmp($f['entry'], $orderElement->getContent()) == 0) {
771  $found = true;
772  }
773  if (strcmp($f['entry'], $this->getThumbPrefix() . $orderElement->getContent()) == 0) {
774  $found = true;
775  }
776  }
777  if (!$found) {
778  if (@file_exists($this->getImagePath() . $f['entry'])) {
779  @unlink($this->getImagePath() . $f['entry']);
780  }
781  }
782  }
783  }
784  }
785  } else {
786  if (@file_exists($this->getImagePath())) {
788  }
789  }
790  }
791 
792  /*
793  * Deletes an imagefile from the system if the file is deleted manually
794  *
795  * @param string $filename Image file filename
796  * @return boolean Success
797  */
798  public function dropImageFile($imageFilename)
799  {
800  if (!strlen($imageFilename)) {
801  return false;
802  }
803 
804  $result = @unlink($this->getImagePath() . $imageFilename);
805  $result = $result && @unlink($this->getImagePath() . $this->getThumbPrefix() . $imageFilename);
806 
807  return $result;
808  }
809 
810  public function isImageFileStored($imageFilename): bool
811  {
812  if (!strlen($imageFilename)) {
813  return false;
814  }
815 
816  if (!file_exists($this->getImagePath() . $imageFilename)) {
817  return false;
818  }
819 
820  return is_file($this->getImagePath() . $imageFilename);
821  }
822 
823  public function isImageReplaced(ilAssOrderingElement $newElement, ilAssOrderingElement $oldElement): bool
824  {
825  if (!$this->hasOrderingTypeUploadSupport()) {
826  return false;
827  }
828 
829  if (!$newElement->getContent()) {
830  return false;
831  }
832 
833  return $newElement->getContent() != $oldElement->getContent();
834  }
835 
836 
837  public function storeImageFile(string $upload_file, string $upload_name): ?string
838  {
839  $name_parts = explode(".", $upload_name);
840  $suffix = strtolower(array_pop($name_parts));
841  if (!in_array($suffix, self::VALID_UPLOAD_SUFFIXES)) {
842  return null;
843  }
844 
845  $this->ensureImagePathExists();
846  $target_filename = $this->buildHashedImageFilename($upload_name, true);
847  $target_filepath = $this->getImagePath() . $target_filename;
848  if (ilFileUtils::moveUploadedFile($upload_file, $target_filename, $target_filepath)) {
849  $thumb_path = $this->getImagePath() . $this->getThumbPrefix() . $target_filename;
850  ilShellUtil::convertImage($target_filepath, $thumb_path, "JPEG", (string) $this->getThumbSize());
851 
852  return $target_filename;
853  }
854 
855  return null;
856  }
857 
858  public function updateImageFile(string $existing_image_name): ?string
859  {
860  $existing_image_path = $this->getImagePath() . $existing_image_name;
861  $target_filename = $this->buildHashedImageFilename($existing_image_name, true);
862  $target_filepath = $this->getImagePath() . $target_filename;
863  if (ilFileUtils::rename($existing_image_path, $target_filepath)) {
864  unlink($this->getImagePath() . $this->getThumbPrefix() . $existing_image_name);
865  $thumb_path = $this->getImagePath() . $this->getThumbPrefix() . $target_filename;
866  ilShellUtil::convertImage($target_filepath, $thumb_path, "JPEG", (string) $this->getThumbSize());
867 
868  return $target_filename;
869  }
870 
871  return $existing_image_name;
872  }
873 
874  public function validateSolutionSubmit(): bool
875  {
876  $submittedSolutionList = $this->getSolutionListFromPostSubmit();
877 
878  if (!$submittedSolutionList->hasElements()) {
879  return true;
880  }
881 
882  return $this->getOrderingElementList()->hasSameElementSetByRandomIdentifiers($submittedSolutionList);
883  }
884 
893  public function saveWorkingData($active_id, $pass = null, $authorized = true): bool
894  {
895  if ($this->dic->testQuestionPool()->internal()->request()->raw('test_answer_changed') === null) {
896  return true;
897  }
898 
899  $entered_values = 0;
900 
901  if (is_null($pass)) {
902  $pass = ilObjTest::_getPass($active_id);
903  }
904 
905  $this->getProcessLocker()->executeUserSolutionUpdateLockOperation(
906  function () use (&$entered_values, $active_id, $pass, $authorized) {
907  $this->removeCurrentSolution($active_id, $pass, $authorized);
908 
909  foreach ($this->getSolutionListFromPostSubmit() as $orderingElement) {
910  $value1 = $orderingElement->getStorageValue1($this->getOrderingType());
911  $value2 = $orderingElement->getStorageValue2($this->getOrderingType());
912 
913  $this->saveCurrentSolution($active_id, $pass, $value1, trim($value2), $authorized);
914 
915  $entered_values++;
916  }
917  }
918  );
919 
920  if ($entered_values) {
921  $this->log($active_id, 'log_user_entered_values');
922  } else {
923  $this->log($active_id, 'log_user_not_entered_values');
924  }
925 
926  return true;
927  }
928 
929  protected function savePreviewData(ilAssQuestionPreviewSession $previewSession): void
930  {
931  if ($this->validateSolutionSubmit()) {
932  $previewSession->setParticipantsSolution(serialize($this->getSolutionListFromPostSubmit()));
933  }
934  }
935 
936  public function saveAdditionalQuestionDataToDb()
937  {
939  global $DIC;
940  $ilDB = $DIC['ilDB'];
941 
942  // save additional data
943  $ilDB->manipulateF(
944  "DELETE FROM " . $this->getAdditionalTableName() . " WHERE question_fi = %s",
945  ["integer"],
946  [$this->getId()]
947  );
948 
949  $ilDB->manipulateF(
950  "INSERT INTO " . $this->getAdditionalTableName() . " (question_fi, ordering_type, thumb_geometry, element_height)
951  VALUES (%s, %s, %s, %s)",
952  ["integer", "text", "integer", "integer"],
953  [
954  $this->getId(),
955  $this->ordering_type,
956  $this->getThumbSize(),
957  ($this->getElementHeight() > 20) ? $this->getElementHeight() : null
958  ]
959  );
960  }
961 
962 
963  protected function getQuestionRepository(): ILIAS\TA\Questions\Ordering\assOrderingQuestionDatabaseRepository
964  {
965  global $DIC;
966  $ilDB = $DIC['ilDB'];
967  return new \ILIAS\TA\Questions\Ordering\assOrderingQuestionDatabaseRepository($ilDB);
968  }
969 
970  public function saveAnswerSpecificDataToDb()
971  {
972  }
973 
980  public function getQuestionType(): string
981  {
982  return "assOrderingQuestion";
983  }
984 
991  public function getAdditionalTableName(): string
992  {
993  return "qpl_qst_ordering";
994  }
995 
1002  public function getAnswerTableName(): string
1003  {
1004  return "qpl_a_ordering";
1005  }
1006 
1011  public function getRTETextWithMediaObjects(): string
1012  {
1013  $text = parent::getRTETextWithMediaObjects();
1014 
1015  foreach ($this->getOrderingElementList() as $orderingElement) {
1016  $text .= $orderingElement->getContent();
1017  }
1018 
1019  return $text;
1020  }
1021 
1026  public function getOrderElements(): array
1027  {
1028  return $this->getOrderingElementList()->getRandomIdentifierIndexedElements();
1029  }
1030 
1034  public function setExportDetailsXLSX(ilAssExcelFormatHelper $worksheet, int $startrow, int $col, int $active_id, int $pass): int
1035  {
1036  parent::setExportDetailsXLSX($worksheet, $startrow, $col, $active_id, $pass);
1037 
1038  $solutions = $this->getSolutionValues($active_id, $pass);
1039  $sol = array();
1040  foreach ($solutions as $solution) {
1041  $sol[$solution["value1"]] = $solution["value2"];
1042  }
1043  asort($sol);
1044  $sol = array_keys($sol);
1045 
1046  $i = 1;
1047  foreach ($sol as $idx) {
1048  foreach ($solutions as $solution) {
1049  if ($solution["value1"] == $idx) {
1050  $worksheet->setCell($startrow + $i, $col, $solution["value2"]);
1051  $worksheet->setBold($worksheet->getColumnCoord($col) . ($startrow + $i));
1052  }
1053  }
1054  $element = $this->getOrderingElementList()->getElementBySolutionIdentifier($idx);
1055  $worksheet->setCell($startrow + $i, $col + 2, $element->getContent());
1056  $i++;
1057  }
1058 
1059  return $startrow + $i + 1;
1060  }
1061 
1062  public function getElementHeight(): ?int
1063  {
1064  return $this->element_height;
1065  }
1066 
1067  public function setElementHeight(?int $a_height): void
1068  {
1069  $this->element_height = ($a_height < 20) ? null : $a_height;
1070  }
1071 
1072  /*
1073  * Rebuild the thumbnail images with a new thumbnail size
1074  */
1075  public function rebuildThumbnails(): void
1076  {
1077  if ($this->isImageOrderingType()) {
1078  foreach ($this->getOrderElements() as $orderingElement) {
1079  if ($orderingElement->getContent() !== '') {
1080  $this->generateThumbForFile($this->getImagePath(), $orderingElement->getContent());
1081  }
1082  }
1083  }
1084  }
1085 
1086  public function getThumbPrefix(): string
1087  {
1088  return "thumb.";
1089  }
1090 
1091  protected function generateThumbForFile($path, $file): void
1092  {
1093  $filename = $path . $file;
1094  if (@file_exists($filename)) {
1095  $thumbpath = $path . $this->getThumbPrefix() . $file;
1096  $path_info = @pathinfo($filename);
1097  $ext = "";
1098  switch (strtoupper($path_info['extension'])) {
1099  case 'PNG':
1100  $ext = 'PNG';
1101  break;
1102  case 'GIF':
1103  $ext = 'GIF';
1104  break;
1105  default:
1106  $ext = 'JPEG';
1107  break;
1108  }
1109  ilShellUtil::convertImage($filename, $thumbpath, $ext, (string) $this->getThumbSize());
1110  }
1111  }
1112 
1116  public function toJSON(): string
1117  {
1118  $result = array();
1119  $result['id'] = $this->getId();
1120  $result['type'] = (string) $this->getQuestionType();
1121  $result['title'] = $this->getTitleForHTMLOutput();
1122  $result['question'] = $this->formatSAQuestion($this->getQuestion());
1123  $result['nr_of_tries'] = $this->getNrOfTries();
1124  $result['shuffle'] = true;
1125  $result['points'] = $this->getPoints();
1126  $result['feedback'] = array(
1127  'onenotcorrect' => $this->formatSAQuestion($this->feedbackOBJ->getGenericFeedbackTestPresentation($this->getId(), false)),
1128  'allcorrect' => $this->formatSAQuestion($this->feedbackOBJ->getGenericFeedbackTestPresentation($this->getId(), true))
1129  );
1130  if ($this->getOrderingType() == self::OQ_PICTURES) {
1131  $result['path'] = $this->getImagePathWeb();
1132  }
1133 
1134  $counter = 1;
1135  $answers = array();
1136  foreach ($this->getOrderingElementList() as $orderingElement) {
1137  $answers[$counter] = $orderingElement->getContent();
1138  $counter++;
1139  }
1140  $answers = $this->getShuffler()->transform($answers);
1141  $arr = array();
1142  foreach ($answers as $order => $answer) {
1143  array_push($arr, array(
1144  "answertext" => (string) $answer,
1145  "order" => (int) $order
1146  ));
1147  }
1148  $result['answers'] = $arr;
1149 
1150  $mobs = ilObjMediaObject::_getMobsOfObject("qpl:html", $this->getId());
1151  $result['mobs'] = $mobs;
1152 
1153  return json_encode($result);
1154  }
1155 
1161  {
1162  if ($this->isImageOrderingType()) {
1163  return $this->buildOrderingImagesInputGui();
1164  }
1165  return $this->buildOrderingTextsInputGui();
1166  }
1167 
1168 
1173  {
1174  switch (true) {
1175  case $formField instanceof ilAssNestedOrderingElementsInputGUI:
1176  $formField->setInteractionEnabled(true);
1177  $formField->setNestingEnabled($this->isOrderingTypeNested());
1178  break;
1179 
1180  case $formField instanceof ilAssOrderingTextsInputGUI:
1181  case $formField instanceof ilAssOrderingImagesInputGUI:
1182  default:
1183 
1184  $formField->setEditElementOccuranceEnabled(true);
1185  $formField->setEditElementOrderEnabled(true);
1186  }
1187  }
1188 
1192  public function initOrderingElementFormFieldLabels(ilFormPropertyGUI $formField): void
1193  {
1194  $formField->setInfo($this->lng->txt('ordering_answer_sequence_info'));
1195  $formField->setTitle($this->lng->txt('answers'));
1196  }
1197 
1202  {
1203  $formDataConverter = $this->buildOrderingTextsFormDataConverter();
1204 
1205  $orderingElementInput = new ilAssOrderingTextsInputGUI(
1206  $formDataConverter,
1207  self::ORDERING_ELEMENT_FORM_FIELD_POSTVAR
1208  );
1209 
1210  $this->initOrderingElementFormFieldLabels($orderingElementInput);
1211 
1212  return $orderingElementInput;
1213  }
1214 
1219  {
1220  $formDataConverter = $this->buildOrderingImagesFormDataConverter();
1221 
1222  $orderingElementInput = new ilAssOrderingImagesInputGUI(
1223  $formDataConverter,
1224  self::ORDERING_ELEMENT_FORM_FIELD_POSTVAR
1225  );
1226 
1227  $orderingElementInput->setImageUploadCommand(self::ORDERING_ELEMENT_FORM_CMD_UPLOAD_IMG);
1228  $orderingElementInput->setImageRemovalCommand(self::ORDERING_ELEMENT_FORM_CMD_REMOVE_IMG);
1229 
1230  $this->initOrderingElementFormFieldLabels($orderingElementInput);
1231 
1232  return $orderingElementInput;
1233  }
1234 
1239  {
1240  $formDataConverter = $this->buildNestedOrderingFormDataConverter();
1241 
1242  $orderingElementInput = new ilAssNestedOrderingElementsInputGUI(
1243  $formDataConverter,
1244  self::ORDERING_ELEMENT_FORM_FIELD_POSTVAR
1245  );
1246 
1247  $orderingElementInput->setUniquePrefix($this->getId());
1248  $orderingElementInput->setOrderingType($this->getOrderingType());
1249  $orderingElementInput->setElementImagePath($this->getImagePathWeb());
1250  $orderingElementInput->setThumbPrefix($this->getThumbPrefix());
1251 
1252  $this->initOrderingElementFormFieldLabels($orderingElementInput);
1253 
1254  return $orderingElementInput;
1255  }
1256 
1257 
1264  {
1265  $orderingGUI = $this->buildNestedOrderingElementInputGui();
1267  $orderingGUI->setValueByArray($userSolutionPost);
1268 
1269  if (!$orderingGUI->checkInput()) {
1270  throw new ilTestException('error on validating user solution post');
1271  }
1272 
1273  $solutionOrderingElementList = ilAssOrderingElementList::buildInstance($this->getId());
1274 
1275  $storedElementList = $this->getOrderingElementList();
1276 
1277  foreach ($orderingGUI->getElementList($this->getId()) as $submittedElement) {
1278  $solutionElement = $storedElementList->getElementByRandomIdentifier(
1279  $submittedElement->getRandomIdentifier()
1280  )->getClone();
1281 
1282  $solutionElement->setPosition($submittedElement->getPosition());
1283 
1284  if ($this->isOrderingTypeNested()) {
1285  $solutionElement->setIndentation($submittedElement->getIndentation());
1286  }
1287 
1288  $solutionOrderingElementList->addElement($solutionElement);
1289  }
1290 
1291  return $solutionOrderingElementList;
1292  }
1293 
1298 
1303  {
1304  if ($this->postSolutionOrderingElementList === null) {
1305  $post_array = $_POST;
1306  if (! is_array($post_array)) {
1307  global $DIC;
1308  $request = $DIC->http()->request();
1309  $post_array = $request->getParsedBody();
1310  }
1312  $this->postSolutionOrderingElementList = $list;
1313  }
1314 
1316  }
1317 
1321  public function getSolutionPostSubmit(): array
1322  {
1323  return $this->fetchSolutionSubmit($_POST);
1324  }
1325 
1331  protected function calculateReachedPointsForSolution(ilAssOrderingElementList $solutionOrderingElementList): float
1332  {
1333  $reachedPoints = $this->getPoints();
1334 
1335  foreach ($this->getOrderingElementList() as $correctElement) {
1336  $userElement = $solutionOrderingElementList->getElementByPosition($correctElement->getPosition());
1337 
1338  if (!$correctElement->isSameElement($userElement)) {
1339  $reachedPoints = 0;
1340  break;
1341  }
1342  }
1343 
1344  return $reachedPoints;
1345  }
1346 
1355  public function getOperators($expression): array
1356  {
1358  }
1359 
1364  public function getExpressionTypes(): array
1365  {
1366  return array(
1371  );
1372  }
1373 
1382  public function getUserQuestionResult($active_id, $pass): ilUserQuestionResult
1383  {
1385  global $DIC;
1386  $ilDB = $DIC['ilDB'];
1387  $result = new ilUserQuestionResult($this, $active_id, $pass);
1388 
1389  $maxStep = $this->lookupMaxStep($active_id, $pass);
1390 
1391  if ($maxStep > 0) {
1392  $data = $ilDB->queryF(
1393  "SELECT value1, value2 FROM tst_solutions WHERE active_fi = %s AND pass = %s AND question_fi = %s AND step = %s ORDER BY value1 ASC ",
1394  array("integer", "integer", "integer","integer"),
1395  array($active_id, $pass, $this->getId(), $maxStep)
1396  );
1397  } else {
1398  $data = $ilDB->queryF(
1399  "SELECT value1, value2 FROM tst_solutions WHERE active_fi = %s AND pass = %s AND question_fi = %s ORDER BY value1 ASC ",
1400  array("integer", "integer", "integer"),
1401  array($active_id, $pass, $this->getId())
1402  );
1403  }
1404 
1405  $elements = array();
1406  while ($row = $ilDB->fetchAssoc($data)) {
1407  $newKey = explode(":", $row["value2"]);
1408 
1409  foreach ($this->getOrderingElementList() as $answer) {
1410  // Images not supported
1411  if (!$this->isOrderingTypeNested()) {
1412  if ($answer->getSolutionIdentifier() == $row["value1"]) {
1413  $elements[$row["value2"]] = $answer->getSolutionIdentifier() + 1;
1414  break;
1415  }
1416  } else {
1417  if ($answer->getRandomIdentifier() == $newKey[0]) {
1418  $elements[$row["value1"]] = $answer->getSolutionIdentifier() + 1;
1419  break;
1420  }
1421  }
1422  }
1423  }
1424 
1425  ksort($elements);
1426 
1427  foreach (array_values($elements) as $element) {
1428  $result->addKeyValue($element, $element);
1429  }
1430 
1431  $points = $this->calculateReachedPoints($active_id, $pass);
1432  $max_points = $this->getMaximumPoints();
1433 
1434  $result->setReachedPercentage(($points / $max_points) * 100);
1435 
1436  return $result;
1437  }
1438 
1446  public function getAvailableAnswerOptions($index = null)
1447  {
1448  if ($index !== null) {
1449  return $this->getOrderingElementList()->getElementByPosition($index);
1450  }
1451 
1452  return $this->getOrderingElementList()->getElements();
1453  }
1454 
1458  protected function afterSyncWithOriginal($origQuestionId, $dupQuestionId, $origParentObjId, $dupParentObjId): void
1459  {
1460  parent::afterSyncWithOriginal($origQuestionId, $dupQuestionId, $origParentObjId, $dupParentObjId);
1461  $this->duplicateImages($dupQuestionId, $dupParentObjId, $origQuestionId, $origParentObjId);
1462  }
1463 
1464  // fau: testNav - new function getTestQuestionConfig()
1469  // hey: refactored identifiers
1471  // hey.
1472  {
1473  // hey: refactored identifiers
1474  return parent::buildTestPresentationConfig()
1475  // hey.
1477  ->setUseUnchangedAnswerLabel($this->lng->txt('tst_unchanged_order_is_correct'));
1478  }
1479  // fau.
1480 
1481  protected function ensureImagePathExists(): void
1482  {
1483  if (!file_exists($this->getImagePath())) {
1485  }
1486  }
1487 
1491  public function fetchSolutionSubmit($formSubmissionDataStructure): array
1492  {
1493  $solutionSubmit = array();
1494 
1495  if (isset($formSubmissionDataStructure['orderresult'])) {
1496  $orderresult = $formSubmissionDataStructure['orderresult'];
1497 
1498  if (strlen($orderresult)) {
1499  $orderarray = explode(":", $orderresult);
1500  $ordervalue = 1;
1501  foreach ($orderarray as $index) {
1502  $idmatch = null;
1503  if (preg_match("/id_(\\d+)/", $index, $idmatch)) {
1504  $randomid = $idmatch[1];
1505  foreach ($this->getOrderingElementList() as $answeridx => $answer) {
1506  if ($answer->getRandomIdentifier() == $randomid) {
1507  $solutionSubmit[$answeridx] = $ordervalue;
1508  $ordervalue++;
1509  }
1510  }
1511  }
1512  }
1513  }
1514  } elseif ($this->getOrderingType() == OQ_NESTED_TERMS || $this->getOrderingType() == OQ_NESTED_PICTURES) {
1515  $index = 0;
1516  foreach ($formSubmissionDataStructure['content'] as $randomId => $content) {
1517  $indentation = $formSubmissionDataStructure['indentation'];
1518 
1519  $value1 = $index++;
1520  $value2 = implode(':', array($randomId, $indentation));
1521 
1522  $solutionSubmit[$value1] = $value2;
1523  }
1524  } else {
1525  foreach ($formSubmissionDataStructure as $key => $value) {
1526  $matches = null;
1527  if (preg_match("/^order_(\d+)/", $key, $matches)) {
1528  if (!(preg_match("/initial_value_\d+/", $value))) {
1529  if (strlen($value)) {
1530  foreach ($this->getOrderingElementList() as $answeridx => $answer) {
1531  if ($answer->getRandomIdentifier() == $matches[1]) {
1532  $solutionSubmit[$answeridx] = $value;
1533  }
1534  }
1535  }
1536  }
1537  }
1538  }
1539  }
1540 
1541  return $solutionSubmit;
1542  }
1543 
1548  {
1549  $converter = new ilAssOrderingFormValuesObjectsConverter();
1550  $converter->setPostVar(self::ORDERING_ELEMENT_FORM_FIELD_POSTVAR);
1551 
1552  return $converter;
1553  }
1554 
1559  {
1560  $formDataConverter = $this->buildOrderingElementFormDataConverter();
1562 
1563  $formDataConverter->setImageRemovalCommand(self::ORDERING_ELEMENT_FORM_CMD_REMOVE_IMG);
1564  $formDataConverter->setImageUrlPath($this->getImagePathWeb());
1565  $formDataConverter->setImageFsPath($this->getImagePath());
1566 
1567  if ($this->getThumbPrefix()) {
1568  $formDataConverter->setThumbnailPrefix($this->getThumbPrefix());
1569  }
1570  return $formDataConverter;
1571  }
1572 
1577  {
1578  $formDataConverter = $this->buildOrderingElementFormDataConverter();
1580  return $formDataConverter;
1581  }
1582 
1587  {
1588  $formDataConverter = $this->buildOrderingElementFormDataConverter();
1590 
1591  if ($this->getOrderingType() == OQ_NESTED_PICTURES) {
1592  $formDataConverter->setImageRemovalCommand(self::ORDERING_ELEMENT_FORM_CMD_REMOVE_IMG);
1593  $formDataConverter->setImageUrlPath($this->getImagePathWeb());
1594  $formDataConverter->setThumbnailPrefix($this->getThumbPrefix());
1595  }
1596 
1597  return $formDataConverter;
1598  }
1599 }
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...
duplicate(bool $for_test=true, ?string $title="", ?string $author="", ?int $owner=-1, $testObjId=null)
getSolutionValues($active_id, $pass=null, bool $authorized=true)
Loads solutions of a given user from the database an returns it.
setNrOfTries(int $a_nr_of_tries)
duplicateImages($src_question_id, $src_object_id, $dest_question_id, $dest_object_id)
initOrderingElementAuthoringProperties(ilFormPropertyGUI $formField)
fetchSolutionListFromFormSubmissionData($userSolutionPost)
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
updateImageFile(string $existing_image_name)
getSolutionOrderingElementListForTestOutput(ilAssNestedOrderingElementsInputGUI $inputGUI, $lastPost, $activeId, $pass)
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
static _getPass($active_id)
Retrieves the actual pass of a given user for a given test.
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
$post_array
Definition: webdav.php:33
calculateReachedPointsForSolution(ilAssOrderingElementList $solutionOrderingElementList)
getSolutionOrderingElementList($indexedSolutionValues)
saveAdditionalQuestionDataToDb()
Saves a record to the question types additional data table.
setIsUnchangedAnswerPossible($isUnchangedAnswerPossible)
Set if the saving of an unchanged answer is supported with an additional checkbox.
repository for assOrderingQuestion (the answer elements within, at least...)
getRTETextWithMediaObjects()
Collects all text in the question which could contain media objects which were created with the Rich ...
fetchSolutionSubmit($formSubmissionDataStructure)
Abstract basic class which is to be extended by the concrete assessment question type classes...
isComplete()
Returns true, if a ordering question is complete for use.
Class ChatMainBarProvider .
setOwner(int $owner=-1)
const OQ_NESTED_TERMS
initOrderingElementFormFieldLabels(ilFormPropertyGUI $formField)
__construct( $title="", $comment="", $author="", $owner=-1, $question="", $ordering_type=self::OQ_TERMS)
assOrderingQuestion constructor
getColumnCoord(int $a_col)
Get column "name" from number.
ensureNonNegativePoints($points)
getQuestionType()
Returns the question type of the question.
getOrderElements()
Returns the answers array.
copyObject($target_questionpool_id, $title="")
Copies an assOrderingQuestion object.
afterSyncWithOriginal($origQuestionId, $dupQuestionId, $origParentObjId, $dupParentObjId)
{}
getImagePathWeb()
Returns the web image path for web accessable images of a question.
setThumbSize(int $a_size)
static buildInstance(int $question_id, array $elements=[])
setOrderingElementList(ilAssOrderingElementList $list)
savePreviewData(ilAssQuestionPreviewSession $previewSession)
getOrderingElementListForSolutionOutput($forceCorrectSolution, $activeId, $passIndex)
getAvailableAnswerOptions($index=null)
If index is null, the function returns an array with all anwser options Else it returns the specific ...
getAnswer($index=0)
Returns the ordering element from the given position.
getOperators($expression)
Get all available operations for a specific question.
setCell($a_row, $a_col, $a_value, $datatype=null)
getUserQuestionResult($active_id, $pass)
Get the user solution for a question by active_id and the test pass.
static makeDirParents(string $a_dir)
Create a new directory and all parent directories.
setComment(string $comment="")
float $points
The maximum available points for the question.
isImageReplaced(ilAssOrderingElement $newElement, ilAssOrderingElement $oldElement)
getSolutionValuePairBrandedOrderingElementBySolutionIdentifier($value1, $value2)
createNewOriginalFromThisDuplicate($targetParentId, $targetQuestionTitle="")
Base Exception for all Exceptions relating to Modules/Test.
fetchIndexedValuesFromValuePairs(array $valuePairs)
$path
Definition: ltiservices.php:32
global $DIC
Definition: feed.php:28
saveCurrentSolution(int $active_id, int $pass, $value1, $value2, bool $authorized=true, $tstamp=0)
setBold(string $a_coords)
Set cell(s) to bold.
__construct(VocabulariesInterface $vocabularies)
getImagePath($question_id=null, $object_id=null)
Returns the image path for web accessable images of a question.
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
getExpressionTypes()
Get all available expression types for a specific question.
buildHashedImageFilename(string $plain_image_filename, bool $unique=false)
const OQ_PICTURES
Ordering question constants.
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
getAnswerTableName()
Returns the name of the answer table in the database.
saveWorkingData($active_id, $pass=null, $authorized=true)
Saves the learners input of the question to the database.
deleteAnswer($randomIdentifier)
Deletes an answer with a given index.
static delDir(string $a_dir, bool $a_clean_only=false)
removes a dir and all its content (subdirs and files) recursively
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
toJSON()
Returns a JSON representation of the question.
saveToDb($original_id="")
Saves a assOrderingQuestion object to a database.
string $key
Consumer key/client ID value.
Definition: System.php:193
static getDir(string $a_dir, bool $a_rec=false, ?string $a_sub_dir="")
get directory
static moveUploadedFile(string $a_file, string $a_name, string $a_target, bool $a_raise_errors=true, string $a_mode="move_uploaded")
move uploaded file
setPoints(float $points)
setObjId(int $obj_id=0)
string $question
The question text.
static convertImage(string $a_from, string $a_to, string $a_target_format="", string $a_geometry="", string $a_background_color="")
calculateReachedPoints($active_id, $pass=null, $authorizedSolution=true, $returndetails=false)
Returns the points, a learner has reached answering the question.
log(int $active_id, string $langVar)
calculateReachedPointsFromPreviewSession(ilAssQuestionPreviewSession $previewSession)
static _getMobsOfObject(string $a_type, int $a_id, int $a_usage_hist_nr=0, string $a_lang="-")
$filename
Definition: buildRTE.php:78
deductHintPointsFromReachedPoints(ilAssQuestionPreviewSession $previewSession, $reachedPoints)
saveQuestionDataToDb(int $original_id=-1)
getSolutionMaxPass(int $active_id)
getSolutionValuePairBrandedOrderingElementByRandomIdentifier($value1, $value2)
const OQ_TERMS
removeCurrentSolution(int $active_id, int $pass, bool $authorized=true)
storeImageFile(string $upload_file, string $upload_name)
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
setId(int $id=-1)
const OQ_NESTED_PICTURES
setOriginalId(?int $original_id)
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
getTestOutputSolutions(int $activeId, int $pass)
setTitle(string $title="")
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
setOrderingType($ordering_type=self::OQ_TERMS)
setLifecycle(ilAssQuestionLifecycle $lifecycle)
buildTestPresentationConfig()
Get the test question configuration.
static rename(string $a_source, string $a_target)
getMaximumPoints()
Returns the maximum points, a learner can reach answering the question.
copyImages($question_id, $source_questionpool)
ILIAS DI LoggingServices $ilLog
lookupMaxStep(int $active_id, int $pass)
setAuthor(string $author="")
setAdditionalContentEditingMode(?string $additionalContentEditingMode)
loadFromDb($question_id)
Loads a assOrderingQuestion object from a database.
setExportDetailsXLSX(ilAssExcelFormatHelper $worksheet, int $startrow, int $col, int $active_id, int $pass)
{}
ensureValidIdentifiers(ilAssOrderingElement $element)
saveAnswerSpecificDataToDb()
Saves the answer specific records into a question types answer table.
getAdditionalTableName()
Returns the name of the additional question data table in the database.
setQuestion(string $question="")
getAnswerCount()
Returns the number of answers.
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...