ILIAS  release_8 Revision v8.19
All Data Structures Namespaces Files Functions Variables Modules Pages
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  include_once("./Services/RTE/classes/class.ilRTE.php");
185  $this->setQuestion(ilRTE::_replaceMediaObjectImageSrc((string) $data["question_text"], 1));
186  $this->ordering_type = $data["ordering_type"] !== null ? (int) $data["ordering_type"] : OQ_TERMS;
187  if ($data['thumb_geometry'] !== null && $data['thumb_geometry'] >= $this->getMinimumThumbSize()) {
188  $this->setThumbSize($data['thumb_geometry']);
189  }
190  $this->element_height = $data["element_height"] ? (int) $data['element_height'] : null;
191 
192  try {
193  $this->setLifecycle(ilAssQuestionLifecycle::getInstance($data['lifecycle']));
196  }
197 
198  try {
199  $this->setAdditionalContentEditingMode($data['add_cont_edit_mode']);
200  } catch (ilTestQuestionPoolException $e) {
201  }
202  }
203 
204  parent::loadFromDb($question_id);
205  }
206 
207  public function duplicate(
208  bool $for_test = true,
209  ?string $title = "",
210  ?string $author = "",
211  ?string $owner = "",
212  $testObjId = null
213  ): int {
214  if ($this->id <= 0) {
215  // The question has not been saved. It cannot be duplicated
216  return -1;
217  }
218  // duplicate the question in database
219  $this_id = $this->getId();
220  $thisObjId = $this->getObjId();
221 
222  $clone = clone $this;
224  $clone->id = -1;
225 
226  if ((int) $testObjId > 0) {
227  $clone->setObjId($testObjId);
228  }
229 
230  if ($title) {
231  $clone->setTitle($title);
232  }
233  if ($author) {
234  $clone->setAuthor($author);
235  }
236  if ($owner) {
237  $clone->setOwner($owner);
238  }
239  if ($for_test) {
240  $clone->saveToDb($original_id);
241  } else {
242  $clone->saveToDb();
243  }
244 
245  //$list = $this->getRepository()->getOrderingList($original_id)
246  $list = $this->getRepository()->getOrderingList($this_id)
247  ->withQuestionId($clone->getId());
248  $list->distributeNewRandomIdentifiers();
249  $clone->setOrderingElementList($list);
250  $clone->saveToDb();
251 
252  $clone->copyPageOfQuestion($this_id);
253  $clone->copyXHTMLMediaObjectsOfQuestion($this_id);
254  $clone->duplicateImages($this_id, $thisObjId, $clone->getId(), $testObjId);
255 
256  $clone->onDuplicate($thisObjId, $this_id, $clone->getObjId(), $clone->getId());
257  return $clone->getId();
258  }
259 
265  public function copyObject($target_questionpool_id, $title = ""): int
266  {
267  if ($this->getId() <= 0) {
268  throw new RuntimeException('The question has not been saved. It cannot be duplicated');
269  }
270  // duplicate the question in database
271  $clone = clone $this;
272  $this_id = $this->getId();
274  $clone->id = -1;
275  $source_questionpool_id = $this->getObjId();
276  $clone->setObjId($target_questionpool_id);
277  if ($title) {
278  $clone->setTitle($title);
279  }
280  $clone->saveToDb();
281 
282  $list = $this->getRepository()->getOrderingList($this_id)
283  ->withQuestionId($clone->getId());
284  $list->distributeNewRandomIdentifiers();
285  $clone->setOrderingElementList($list);
286  $clone->saveToDb();
287 
288  $clone->copyPageOfQuestion($original_id);
289  $clone->copyXHTMLMediaObjectsOfQuestion($original_id);
290  $clone->duplicateImages($original_id, $source_questionpool_id, $clone->getId(), $target_questionpool_id);
291 
292  $clone->onCopy($source_questionpool_id, $original_id, $clone->getObjId(), $clone->getId());
293 
294  return $clone->getId();
295  }
296 
297  public function createNewOriginalFromThisDuplicate($targetParentId, $targetQuestionTitle = ""): int
298  {
299  if ($this->getId() <= 0) {
300  throw new RuntimeException('The question has not been saved. It cannot be duplicated');
301  }
302 
303  include_once("./Modules/TestQuestionPool/classes/class.assQuestion.php");
304 
305  $sourceQuestionId = $this->id;
306  $sourceParentId = $this->getObjId();
307 
308  // duplicate the question in database
309  $clone = clone $this;
310  $clone->id = -1;
311 
312  $clone->setObjId($targetParentId);
313 
314  if ($targetQuestionTitle) {
315  $clone->setTitle($targetQuestionTitle);
316  }
317 
318  $clone->saveToDb();
319 
320  $list = $this->getRepository()->getOrderingList($this->getId())
321  ->withQuestionId($clone->getId());
322  $list->distributeNewRandomIdentifiers();
323  $clone->setOrderingElementList($list);
324  $clone->saveToDb();
325 
326  // copy question page content
327  $clone->copyPageOfQuestion($sourceQuestionId);
328  // copy XHTML media objects
329  $clone->copyXHTMLMediaObjectsOfQuestion($sourceQuestionId);
330  // duplicate the image
331  $clone->duplicateImages($sourceQuestionId, $sourceParentId, $clone->getId(), $clone->getObjId());
332 
333  $clone->onCopy($sourceParentId, $sourceQuestionId, $clone->getObjId(), $clone->getId());
334 
335  return $clone->id;
336  }
337 
338  public function duplicateImages($src_question_id, $src_object_id, $dest_question_id, $dest_object_id): void
339  {
340  global $DIC;
341  $ilLog = $DIC['ilLog'];
342  if ($this->isImageOrderingType()) {
343  $imagepath_original = $this->getImagePath($src_question_id, $src_object_id);
344  $imagepath = $this->getImagePath($dest_question_id, $dest_object_id);
345 
346  if (!file_exists($imagepath)) {
347  ilFileUtils::makeDirParents($imagepath);
348  }
349  foreach ($this->getOrderingElementList() as $element) {
350  $filename = $element->getContent();
351 
352  if ($filename === '') {
353  continue;
354  }
355 
356  if (!file_exists($imagepath_original . $filename)
357  || !copy($imagepath_original . $filename, $imagepath . $filename)) {
358  $ilLog->write("image could not be duplicated!!!!");
359  $ilLog->write($imagepath_original . $filename);
360  $ilLog->write($imagepath . $filename);
361  }
362  if (file_exists($imagepath_original . $this->getThumbPrefix() . $filename)
363  && !copy($imagepath_original . $this->getThumbPrefix() . $filename, $imagepath . $this->getThumbPrefix() . $filename)) {
364  $ilLog->write("image thumbnail could not be duplicated!!!!");
365  }
366  }
367  }
368  }
369 
375  public function copyImages($question_id, $source_questionpool): void
376  {
377  global $DIC;
378  $ilLog = $DIC['ilLog'];
379  if ($this->getOrderingType() == OQ_PICTURES) {
380  $imagepath = $this->getImagePath();
381  $imagepath_original = str_replace("/$this->id/images", "/$question_id/images", $imagepath);
382  $imagepath_original = str_replace("/$this->obj_id/", "/$source_questionpool/", $imagepath_original);
383  if (!file_exists($imagepath)) {
384  ilFileUtils::makeDirParents($imagepath);
385  }
386  foreach ($this->getOrderingElementList() as $element) {
387  $filename = $element->getContent();
388  if (!@copy($imagepath_original . $filename, $imagepath . $filename)) {
389  $ilLog->write("Ordering Question image could not be copied: ${imagepath_original}${filename}");
390  }
391  if (@file_exists($imagepath_original . $this->getThumbPrefix() . $filename)) {
392  if (!@copy($imagepath_original . $this->getThumbPrefix() . $filename, $imagepath . $this->getThumbPrefix() . $filename)) {
393  $ilLog->write("Ordering Question image thumbnail could not be copied: $imagepath_original" . $this->getThumbPrefix() . $filename);
394  }
395  }
396  }
397  }
398  }
399 
400  protected function getValidOrderingTypes(): array
401  {
402  return [
407  ];
408  }
409 
411  {
412  if (!in_array($ordering_type, $this->getValidOrderingTypes())) {
413  throw new \InvalidArgumentException('Must be valid ordering type.');
414  }
415  $this->ordering_type = $ordering_type;
416  }
417 
418  public function getOrderingType(): int
419  {
420  return $this->ordering_type;
421  }
422 
423  public function isOrderingTypeNested(): bool
424  {
425  $nested = [
428  ];
429  return in_array($this->getOrderingType(), $nested);
430  }
431 
432  public function isImageOrderingType(): bool
433  {
434  $with_images = [
437  ];
438  return in_array($this->getOrderingType(), $with_images);
439  }
440 
441  public function setContentType($ct)
442  {
443  if (!in_array($ct, [
444  self::OQ_CT_PICTURES,
445  self::OQ_CT_TERMS
446  ])) {
447  throw new \InvalidArgumentException("use OQ content-type", 1);
448  }
449  if ($ct == self::OQ_CT_PICTURES) {
450  if ($this->isOrderingTypeNested()) {
452  } else {
454  }
455  $this->setThumbSize($this->getThumbSize());
456  }
457  if ($ct == self::OQ_CT_TERMS) {
458  if ($this->isOrderingTypeNested()) {
460  } else {
462  }
463  }
464  }
465 
466  public function setNestingType(bool $nesting)
467  {
468  if ($nesting) {
469  if ($this->isImageOrderingType()) {
471  } else {
473  }
474  } else {
475  if ($this->isImageOrderingType()) {
477  } else {
479  }
480  }
481  }
482 
483  public function hasOrderingTypeUploadSupport(): bool
484  {
485  return $this->isImageOrderingType();
486  }
487 
494  public function getOrderingElementListForSolutionOutput($forceCorrectSolution, $activeId, $passIndex): ilAssOrderingElementList
495  {
496  if ($forceCorrectSolution || !$activeId || $passIndex === null) {
497  return $this->getOrderingElementList();
498  }
499 
500  $solutionValues = $this->getSolutionValues($activeId, $passIndex);
501 
502  if (!count($solutionValues)) {
503  return $this->getShuffledOrderingElementList();
504  }
505 
506  return $this->getSolutionOrderingElementList($this->fetchIndexedValuesFromValuePairs($solutionValues));
507  }
508 
519  {
520  if ($inputGUI->isPostSubmit($lastPost)) {
521  return $this->fetchSolutionListFromFormSubmissionData($lastPost);
522  }
523  $indexedSolutionValues = $this->fetchIndexedValuesFromValuePairs(
524  // hey: prevPassSolutions - obsolete due to central check
525  $this->getTestOutputSolutions($activeId, $pass)
526  // hey.
527  );
528 
529  if (count($indexedSolutionValues)) {
530  return $this->getSolutionOrderingElementList($indexedSolutionValues);
531  }
532 
533  return $this->getShuffledOrderingElementList();
534  }
535 
541  {
542  $value2 = explode(':', $value2);
543 
544  $randomIdentifier = $value2[0];
545  $selectedPosition = $value1;
546  $selectedIndentation = $value2[1];
547 
548  $element = $this->getOrderingElementList()->getElementByRandomIdentifier($randomIdentifier)->getClone();
549 
550  $element->setPosition($selectedPosition);
551  $element->setIndentation($selectedIndentation);
552 
553  return $element;
554  }
555 
561  {
562  $solutionIdentifier = $value1;
563  $selectedPosition = ($value2 - 1);
564  $selectedIndentation = 0;
565 
566  $element = $this->getOrderingElementList()->getElementBySolutionIdentifier($solutionIdentifier)->getClone();
567 
568  $element->setPosition($selectedPosition);
569  $element->setIndentation($selectedIndentation);
570 
571  return $element;
572  }
573 
579  public function getSolutionOrderingElementList($indexedSolutionValues): ilAssOrderingElementList
580  {
581  $solutionOrderingList = new ilAssOrderingElementList();
582  $solutionOrderingList->setQuestionId($this->getId());
583 
584  foreach ($indexedSolutionValues as $value1 => $value2) {
585  if ($this->isOrderingTypeNested()) {
586  $element = $this->getSolutionValuePairBrandedOrderingElementByRandomIdentifier($value1, $value2);
587  } else {
588  $element = $this->getSolutionValuePairBrandedOrderingElementBySolutionIdentifier($value1, $value2);
589  }
590 
591  $solutionOrderingList->addElement($element);
592  }
593 
594  if (!$this->getOrderingElementList()->hasSameElementSetByRandomIdentifiers($solutionOrderingList)) {
595  throw new ilTestQuestionPoolException('inconsistent solution values given');
596  }
597 
598  return $solutionOrderingList;
599  }
600 
602  {
603  $shuffledRandomIdentifierIndex = $this->getShuffler()->transform(
604  $this->getOrderingElementList()->getRandomIdentifierIndex()
605  );
606 
607  $shuffledElementList = $this->getOrderingElementList()->getClone();
608  $shuffledElementList->reorderByRandomIdentifiers($shuffledRandomIdentifierIndex);
609  $shuffledElementList->resetElementsIndentations();
610 
611  return $shuffledElementList;
612  }
613 
615  {
616  return $this->getRepository()->getOrderingList($this->getId());
617  }
618 
620  {
621  $list = $list->withQuestionId($this->getId());
622  $elements = $list->getElements();
623  $nu = [];
624  foreach ($elements as $e) {
625  $nu[] = $list->ensureValidIdentifiers($e);
626  }
627  $list = $list->withElements($nu);
628  $this->getRepository()->updateOrderingList($list);
629  }
630 
637  public function getAnswer($index = 0): ?ilAssOrderingElement
638  {
639  if (!$this->getOrderingElementList()->elementExistByPosition($index)) {
640  return null;
641  }
642 
643  return $this->getOrderingElementList()->getElementByPosition($index);
644  }
645 
654  public function deleteAnswer($randomIdentifier): void
655  {
656  $this->getOrderingElementList()->removeElement(
657  $this->getOrderingElementList()->getElementByRandomIdentifier($randomIdentifier)
658  );
659  $this->getOrderingElementList()->saveToDb();
660  }
661 
662  public function getAnswerCount(): int
663  {
664  return $this->getOrderingElementList()->countElements();
665  }
666 
677  public function calculateReachedPoints($active_id, $pass = null, $authorizedSolution = true, $returndetails = false)
678  {
679  if ($returndetails) {
680  throw new ilTestException('return details not implemented for ' . __METHOD__);
681  }
682 
683  if (is_null($pass)) {
684  $pass = $this->getSolutionMaxPass($active_id);
685  }
686 
687  $solutionValuePairs = $this->getSolutionValues($active_id, $pass, $authorizedSolution);
688 
689  if (!count($solutionValuePairs)) {
690  return 0;
691  }
692 
693  $indexedSolutionValues = $this->fetchIndexedValuesFromValuePairs($solutionValuePairs);
694  $solutionOrderingElementList = $this->getSolutionOrderingElementList($indexedSolutionValues);
695 
696  return $this->calculateReachedPointsForSolution($solutionOrderingElementList);
697  }
698 
700  {
701  if (!$previewSession->hasParticipantSolution()) {
702  return 0;
703  }
704 
705  $solutionOrderingElementList = unserialize(
706  $previewSession->getParticipantsSolution(),
707  ["allowed_classes" => true]
708  );
709 
710  $reachedPoints = $this->calculateReachedPointsForSolution($solutionOrderingElementList);
711  $reachedPoints = $this->deductHintPointsFromReachedPoints($previewSession, $reachedPoints);
712 
713  return $this->ensureNonNegativePoints($reachedPoints);
714  }
715 
720  public function getMaximumPoints(): float
721  {
722  return $this->getPoints();
723  }
724 
725  /*
726  * Returns the encrypted save filename of a matching picture
727  * Images are saved with an encrypted filename to prevent users from
728  * cheating by guessing the solution from the image filename
729  *
730  * @param string $filename Original filename
731  * @return string Encrypted filename
732  */
733  public function getEncryptedFilename($filename): string
734  {
735  $extension = "";
736  if (preg_match("/.*\\.(\\w+)$/", $filename, $matches)) {
737  $extension = $matches[1];
738  }
739  return md5($filename) . "." . $extension;
740  }
741 
742  protected function cleanImagefiles(): void
743  {
744  if ($this->getOrderingType() == self::OQ_PICTURES) {
745  if (@file_exists($this->getImagePath())) {
746  $contents = ilFileUtils::getDir($this->getImagePath());
747  foreach ($contents as $f) {
748  if (strcmp($f['type'], 'file') == 0) {
749  $found = false;
750  foreach ($this->getOrderingElementList() as $orderElement) {
751  if (strcmp($f['entry'], $orderElement->getContent()) == 0) {
752  $found = true;
753  }
754  if (strcmp($f['entry'], $this->getThumbPrefix() . $orderElement->getContent()) == 0) {
755  $found = true;
756  }
757  }
758  if (!$found) {
759  if (@file_exists($this->getImagePath() . $f['entry'])) {
760  @unlink($this->getImagePath() . $f['entry']);
761  }
762  }
763  }
764  }
765  }
766  } else {
767  if (@file_exists($this->getImagePath())) {
769  }
770  }
771  }
772 
773  /*
774  * Deletes an imagefile from the system if the file is deleted manually
775  * @return boolean Success
776  */
777  public function dropImageFile($imageFilename)
778  {
779  if (!strlen($imageFilename)) {
780  return false;
781  }
782 
783  $result = @unlink($this->getImagePath() . $imageFilename);
784  $result = $result && @unlink($this->getImagePath() . $this->getThumbPrefix() . $imageFilename);
785 
786  return $result;
787  }
788 
789  public function isImageFileStored($imageFilename): bool
790  {
791  if (!strlen($imageFilename)) {
792  return false;
793  }
794 
795  if (!file_exists($this->getImagePath() . $imageFilename)) {
796  return false;
797  }
798 
799  return is_file($this->getImagePath() . $imageFilename);
800  }
801 
802  public function isImageReplaced(ilAssOrderingElement $newElement, ilAssOrderingElement $oldElement): bool
803  {
804  if (!$this->hasOrderingTypeUploadSupport()) {
805  return false;
806  }
807 
808  if (!$newElement->getContent()) {
809  return false;
810  }
811 
812  return $newElement->getContent() != $oldElement->getContent();
813  }
814 
815  public function storeImageFile(string $upload_file, string $upload_name): ?string
816  {
817  $name_parts = explode(".", $upload_name);
818  $suffix = strtolower(array_pop($name_parts));
819  if (!in_array($suffix, self::VALID_UPLOAD_SUFFIXES)) {
820  return null;
821  }
822 
823  $this->ensureImagePathExists();
824  $target_filename = $this->buildHashedImageFilename($upload_name, true);
825  $target_filepath = $this->getImagePath() . $target_filename;
826  if (ilFileUtils::moveUploadedFile($upload_file, $target_filename, $target_filepath)) {
827  $thumb_path = $this->getImagePath() . $this->getThumbPrefix() . $target_filename;
828  ilShellUtil::convertImage($target_filepath, $thumb_path, "JPEG", (string) $this->getThumbSize());
829 
830  return $target_filename;
831  }
832 
833  return null;
834  }
835 
836  public function updateImageFile(string $existing_image_name): ?string
837  {
838  $existing_image_path = $this->getImagePath() . $existing_image_name;
839  $target_filename = $this->buildHashedImageFilename($existing_image_name, true);
840  $target_filepath = $this->getImagePath() . $target_filename;
841  if (ilFileUtils::rename($existing_image_path, $target_filepath)) {
842  unlink($this->getImagePath() . $this->getThumbPrefix() . $existing_image_name);
843  $thumb_path = $this->getImagePath() . $this->getThumbPrefix() . $target_filename;
844  ilShellUtil::convertImage($target_filepath, $thumb_path, "JPEG", (string) $this->getThumbSize());
845 
846  return $target_filename;
847  }
848 
849  return $existing_image_name;
850  }
851 
852  public function validateSolutionSubmit(): bool
853  {
854  $submittedSolutionList = $this->getSolutionListFromPostSubmit();
855 
856  if (!$submittedSolutionList->hasElements()) {
857  return true;
858  }
859 
860  return $this->getOrderingElementList()->hasSameElementSetByRandomIdentifiers($submittedSolutionList);
861  }
862 
871  public function saveWorkingData($active_id, $pass = null, $authorized = true): bool
872  {
873  global $DIC;
874  if ($DIC->testQuestionPool()->internal()->request()->raw('test_answer_changed') === null) {
875  return true;
876  }
877 
878  $entered_values = 0;
879 
880  if (is_null($pass)) {
881  $pass = ilObjTest::_getPass($active_id);
882  }
883 
884  $this->getProcessLocker()->executeUserSolutionUpdateLockOperation(
885  function () use (&$entered_values, $active_id, $pass, $authorized) {
886  $this->removeCurrentSolution($active_id, $pass, $authorized);
887 
888  foreach ($this->getSolutionListFromPostSubmit() as $orderingElement) {
889  $value1 = $orderingElement->getStorageValue1($this->getOrderingType());
890  $value2 = $orderingElement->getStorageValue2($this->getOrderingType());
891 
892  $this->saveCurrentSolution($active_id, $pass, $value1, trim($value2), $authorized);
893 
894  $entered_values++;
895  }
896  }
897  );
898 
899  if ($entered_values) {
900  $this->log($active_id, 'log_user_entered_values');
901  } else {
902  $this->log($active_id, 'log_user_not_entered_values');
903  }
904 
905  return true;
906  }
907 
908  protected function savePreviewData(ilAssQuestionPreviewSession $previewSession): void
909  {
910  if ($this->validateSolutionSubmit()) {
911  $previewSession->setParticipantsSolution(serialize($this->getSolutionListFromPostSubmit()));
912  }
913  }
914 
915  public function saveAdditionalQuestionDataToDb()
916  {
918  global $DIC;
919  $ilDB = $DIC['ilDB'];
920 
921  // save additional data
922  $ilDB->manipulateF(
923  "DELETE FROM " . $this->getAdditionalTableName() . " WHERE question_fi = %s",
924  ["integer"],
925  [$this->getId()]
926  );
927 
928  $ilDB->manipulateF(
929  "INSERT INTO " . $this->getAdditionalTableName() . " (question_fi, ordering_type, thumb_geometry, element_height)
930  VALUES (%s, %s, %s, %s)",
931  ["integer", "text", "integer", "integer"],
932  [
933  $this->getId(),
934  $this->ordering_type,
935  $this->getThumbSize(),
936  ($this->getElementHeight() > 20) ? $this->getElementHeight() : null
937  ]
938  );
939  }
940 
941  protected function getQuestionRepository(): ILIAS\TA\Questions\Ordering\assOrderingQuestionDatabaseRepository
942  {
943  global $DIC;
944  $ilDB = $DIC['ilDB'];
945  return new \ILIAS\TA\Questions\Ordering\assOrderingQuestionDatabaseRepository($ilDB);
946  }
947 
948  public function saveAnswerSpecificDataToDb()
949  {
950  }
951 
952  public function getQuestionType(): string
953  {
954  return "assOrderingQuestion";
955  }
956 
957  public function getAdditionalTableName(): string
958  {
959  return "qpl_qst_ordering";
960  }
961 
968  public function getAnswerTableName(): string
969  {
970  return "qpl_a_ordering";
971  }
972 
977  public function getRTETextWithMediaObjects(): string
978  {
979  $text = parent::getRTETextWithMediaObjects();
980 
981  foreach ($this->getOrderingElementList() as $orderingElement) {
982  $text .= $orderingElement->getContent();
983  }
984 
985  return $text;
986  }
987 
992  public function getOrderElements(): array
993  {
994  return $this->getOrderingElementList()->getRandomIdentifierIndexedElements();
995  }
996 
1003  public function supportsJavascriptOutput(): bool
1004  {
1005  return true;
1006  }
1007 
1008  public function supportsNonJsOutput(): bool
1009  {
1010  return false;
1011  }
1012 
1016  public function setExportDetailsXLS(ilAssExcelFormatHelper $worksheet, int $startrow, int $active_id, int $pass): int
1017  {
1018  parent::setExportDetailsXLS($worksheet, $startrow, $active_id, $pass);
1019 
1020  $solutions = $this->getSolutionValues($active_id, $pass);
1021  $sol = array();
1022  foreach ($solutions as $solution) {
1023  $sol[$solution["value1"]] = $solution["value2"];
1024  }
1025  asort($sol);
1026  $sol = array_keys($sol);
1027 
1028  $i = 1;
1029  foreach ($sol as $idx) {
1030  foreach ($solutions as $solution) {
1031  if ($solution["value1"] == $idx) {
1032  $worksheet->setCell($startrow + $i, 0, $solution["value2"]);
1033  $worksheet->setBold($worksheet->getColumnCoord(0) . ($startrow + $i));
1034  }
1035  }
1036  $element = $this->getOrderingElementList()->getElementBySolutionIdentifier($idx);
1037  $worksheet->setCell($startrow + $i, 2, $element->getContent());
1038  $i++;
1039  }
1040 
1041  return $startrow + $i + 1;
1042  }
1043 
1044  public function getElementHeight(): ?int
1045  {
1046  return $this->element_height;
1047  }
1048 
1049  public function setElementHeight(?int $a_height): void
1050  {
1051  $this->element_height = ($a_height < 20) ? null : $a_height;
1052  }
1053 
1054  /*
1055  * Rebuild the thumbnail images with a new thumbnail size
1056  */
1057  public function rebuildThumbnails(): void
1058  {
1059  if ($this->isImageOrderingType()) {
1060  foreach ($this->getOrderElements() as $orderingElement) {
1061  if ($orderingElement->getContent() !== '') {
1062  $this->generateThumbForFile($this->getImagePath(), $orderingElement->getContent());
1063  }
1064  }
1065  }
1066  }
1067 
1068  public function getThumbPrefix(): string
1069  {
1070  return "thumb.";
1071  }
1072 
1073  protected function generateThumbForFile($path, $file): void
1074  {
1075  $filename = $path . $file;
1076  if (@file_exists($filename)) {
1077  $thumbpath = $path . $this->getThumbPrefix() . $file;
1078  $path_info = @pathinfo($filename);
1079  $ext = "";
1080  switch (strtoupper($path_info['extension'])) {
1081  case 'PNG':
1082  $ext = 'PNG';
1083  break;
1084  case 'GIF':
1085  $ext = 'GIF';
1086  break;
1087  default:
1088  $ext = 'JPEG';
1089  break;
1090  }
1091  ilShellUtil::convertImage($filename, $thumbpath, $ext, (string) $this->getThumbSize());
1092  }
1093  }
1094 
1098  public function toJSON(): string
1099  {
1100  include_once("./Services/RTE/classes/class.ilRTE.php");
1101  $result = array();
1102  $result['id'] = $this->getId();
1103  $result['type'] = (string) $this->getQuestionType();
1104  $result['title'] = $this->getTitleForHTMLOutput();
1105  $result['question'] = $this->formatSAQuestion($this->getQuestion());
1106  $result['nr_of_tries'] = $this->getNrOfTries();
1107  $result['shuffle'] = true;
1108  $result['points'] = $this->getPoints();
1109  $result['feedback'] = array(
1110  'onenotcorrect' => $this->formatSAQuestion($this->feedbackOBJ->getGenericFeedbackTestPresentation($this->getId(), false)),
1111  'allcorrect' => $this->formatSAQuestion($this->feedbackOBJ->getGenericFeedbackTestPresentation($this->getId(), true))
1112  );
1113  if ($this->getOrderingType() == self::OQ_PICTURES) {
1114  $result['path'] = $this->getImagePathWeb();
1115  }
1116 
1117  $counter = 1;
1118  $answers = array();
1119  foreach ($this->getOrderingElementList() as $orderingElement) {
1120  $answers[$counter] = $orderingElement->getContent();
1121  $counter++;
1122  }
1123  $answers = $this->getShuffler()->transform($answers);
1124  $arr = array();
1125  foreach ($answers as $order => $answer) {
1126  array_push($arr, array(
1127  "answertext" => (string) $answer,
1128  "order" => (int) $order
1129  ));
1130  }
1131  $result['answers'] = $arr;
1132 
1133  $mobs = ilObjMediaObject::_getMobsOfObject("qpl:html", $this->getId());
1134  $result['mobs'] = $mobs;
1135 
1136  return json_encode($result);
1137  }
1138 
1144  {
1145  if ($this->isImageOrderingType()) {
1146  return $this->buildOrderingImagesInputGui();
1147  }
1148  return $this->buildOrderingTextsInputGui();
1149  }
1150 
1152  {
1153  switch (true) {
1154  case $formField instanceof ilAssNestedOrderingElementsInputGUI:
1155  $formField->setInteractionEnabled(true);
1156  $formField->setNestingEnabled($this->isOrderingTypeNested());
1157  break;
1158 
1159  case $formField instanceof ilAssOrderingTextsInputGUI:
1160  case $formField instanceof ilAssOrderingImagesInputGUI:
1161  default:
1162 
1163  $formField->setEditElementOccuranceEnabled(true);
1164  $formField->setEditElementOrderEnabled(true);
1165  }
1166  }
1167 
1168  public function initOrderingElementFormFieldLabels(ilFormPropertyGUI $formField): void
1169  {
1170  $formField->setInfo($this->lng->txt('ordering_answer_sequence_info'));
1171  $formField->setTitle($this->lng->txt('answers'));
1172  }
1173 
1175  {
1176  $formDataConverter = $this->buildOrderingTextsFormDataConverter();
1177 
1178  $orderingElementInput = new ilAssOrderingTextsInputGUI(
1179  $formDataConverter,
1180  self::ORDERING_ELEMENT_FORM_FIELD_POSTVAR
1181  );
1182 
1183  $this->initOrderingElementFormFieldLabels($orderingElementInput);
1184 
1185  return $orderingElementInput;
1186  }
1187 
1189  {
1190  $formDataConverter = $this->buildOrderingImagesFormDataConverter();
1191 
1192  $orderingElementInput = new ilAssOrderingImagesInputGUI(
1193  $formDataConverter,
1194  self::ORDERING_ELEMENT_FORM_FIELD_POSTVAR
1195  );
1196 
1197  $orderingElementInput->setImageUploadCommand(self::ORDERING_ELEMENT_FORM_CMD_UPLOAD_IMG);
1198  $orderingElementInput->setImageRemovalCommand(self::ORDERING_ELEMENT_FORM_CMD_REMOVE_IMG);
1199 
1200  $this->initOrderingElementFormFieldLabels($orderingElementInput);
1201 
1202  return $orderingElementInput;
1203  }
1204 
1209  {
1210  $formDataConverter = $this->buildNestedOrderingFormDataConverter();
1211 
1212  $orderingElementInput = new ilAssNestedOrderingElementsInputGUI(
1213  $formDataConverter,
1214  self::ORDERING_ELEMENT_FORM_FIELD_POSTVAR
1215  );
1216 
1217  $orderingElementInput->setUniquePrefix($this->getId());
1218  $orderingElementInput->setOrderingType($this->getOrderingType());
1219  $orderingElementInput->setElementImagePath($this->getImagePathWeb());
1220  $orderingElementInput->setThumbPrefix($this->getThumbPrefix());
1221 
1222  $this->initOrderingElementFormFieldLabels($orderingElementInput);
1223 
1224  return $orderingElementInput;
1225  }
1226 
1227 
1232  {
1233  $orderingGUI = $this->buildNestedOrderingElementInputGui();
1235  $orderingGUI->setValueByArray($userSolutionPost);
1236 
1237  if (!$orderingGUI->checkInput()) {
1238  throw new ilTestException('error on validating user solution post');
1239  }
1240 
1241  $solutionOrderingElementList = ilAssOrderingElementList::buildInstance($this->getId());
1242 
1243  $storedElementList = $this->getOrderingElementList();
1244 
1245  foreach ($orderingGUI->getElementList($this->getId()) as $submittedElement) {
1246  $solutionElement = $storedElementList->getElementByRandomIdentifier(
1247  $submittedElement->getRandomIdentifier()
1248  )->getClone();
1249 
1250  $solutionElement->setPosition($submittedElement->getPosition());
1251 
1252  if ($this->isOrderingTypeNested()) {
1253  $solutionElement->setIndentation($submittedElement->getIndentation());
1254  }
1255 
1256  $solutionOrderingElementList->addElement($solutionElement);
1257  }
1258 
1259  return $solutionOrderingElementList;
1260  }
1261 
1266 
1268  {
1269  if ($this->postSolutionOrderingElementList === null) {
1270  $post_array = $_POST;
1271  if (!is_array($post_array)) {
1272  global $DIC;
1273  $request = $DIC->http()->request();
1274  $post_array = $request->getParsedBody();
1275  }
1277  $this->postSolutionOrderingElementList = $list;
1278  }
1279 
1281  }
1282 
1283  public function getSolutionPostSubmit(): array
1284  {
1285  return $this->fetchSolutionSubmit($_POST);
1286  }
1287 
1288  protected function calculateReachedPointsForSolution(ilAssOrderingElementList $solutionOrderingElementList): float
1289  {
1290  $reachedPoints = $this->getPoints();
1291 
1292  foreach ($this->getOrderingElementList() as $correctElement) {
1293  $userElement = $solutionOrderingElementList->getElementByPosition($correctElement->getPosition());
1294 
1295  if (!$correctElement->isSameElement($userElement)) {
1296  $reachedPoints = 0;
1297  break;
1298  }
1299  }
1300 
1301  return $reachedPoints;
1302  }
1303 
1309  public function getOperators($expression): array
1310  {
1312  }
1313 
1314  public function getExpressionTypes(): array
1315  {
1316  return array(
1321  );
1322  }
1323 
1330  public function getUserQuestionResult($active_id, $pass): ilUserQuestionResult
1331  {
1333  global $DIC;
1334  $ilDB = $DIC['ilDB'];
1335  $result = new ilUserQuestionResult($this, $active_id, $pass);
1336 
1337  $maxStep = $this->lookupMaxStep($active_id, $pass);
1338 
1339  if ($maxStep !== null) {
1340  $data = $ilDB->queryF(
1341  "SELECT value1, value2 FROM tst_solutions WHERE active_fi = %s AND pass = %s AND question_fi = %s AND step = %s ORDER BY value1 ASC ",
1342  array("integer", "integer", "integer","integer"),
1343  array($active_id, $pass, $this->getId(), $maxStep)
1344  );
1345  } else {
1346  $data = $ilDB->queryF(
1347  "SELECT value1, value2 FROM tst_solutions WHERE active_fi = %s AND pass = %s AND question_fi = %s ORDER BY value1 ASC ",
1348  array("integer", "integer", "integer"),
1349  array($active_id, $pass, $this->getId())
1350  );
1351  }
1352 
1353  $elements = array();
1354  while ($row = $ilDB->fetchAssoc($data)) {
1355  $newKey = explode(":", $row["value2"]);
1356 
1357  foreach ($this->getOrderingElementList() as $answer) {
1358  // Images nut supported
1359  if (!$this->isOrderingTypeNested()) {
1360  if ($answer->getSolutionIdentifier() == $row["value1"]) {
1361  $elements[$row["value2"]] = $answer->getSolutionIdentifier() + 1;
1362  break;
1363  }
1364  } else {
1365  if ($answer->getRandomIdentifier() == $newKey[0]) {
1366  $elements[$row["value1"]] = $answer->getSolutionIdentifier() + 1;
1367  break;
1368  }
1369  }
1370  }
1371  }
1372 
1373  ksort($elements);
1374 
1375  foreach (array_values($elements) as $element) {
1376  $result->addKeyValue($element, $element);
1377  }
1378 
1379  $points = $this->calculateReachedPoints($active_id, $pass);
1380  $max_points = $this->getMaximumPoints();
1381 
1382  $result->setReachedPercentage(($points / $max_points) * 100);
1383 
1384  return $result;
1385  }
1386 
1394  public function getAvailableAnswerOptions($index = null)
1395  {
1396  if ($index !== null) {
1397  return $this->getOrderingElementList()->getElementByPosition($index);
1398  }
1399 
1400  return $this->getOrderingElementList()->getElements();
1401  }
1402 
1406  protected function afterSyncWithOriginal($origQuestionId, $dupQuestionId, $origParentObjId, $dupParentObjId): void
1407  {
1408  parent::afterSyncWithOriginal($origQuestionId, $dupQuestionId, $origParentObjId, $dupParentObjId);
1409  $this->duplicateImages($dupQuestionId, $dupParentObjId, $origQuestionId, $origParentObjId);
1410  }
1411 
1413  {
1414  return parent::buildTestPresentationConfig()
1416  ->setUseUnchangedAnswerLabel($this->lng->txt('tst_unchanged_order_is_correct'));
1417  }
1418 
1419  protected function ensureImagePathExists(): void
1420  {
1421  if (!file_exists($this->getImagePath())) {
1423  }
1424  }
1425 
1426  public function fetchSolutionSubmit($formSubmissionDataStructure): array
1427  {
1428  $solutionSubmit = array();
1429 
1430  if (isset($formSubmissionDataStructure['orderresult'])) {
1431  $orderresult = $formSubmissionDataStructure['orderresult'];
1432 
1433  if (strlen($orderresult)) {
1434  $orderarray = explode(":", $orderresult);
1435  $ordervalue = 1;
1436  foreach ($orderarray as $index) {
1437  $idmatch = null;
1438  if (preg_match("/id_(\\d+)/", $index, $idmatch)) {
1439  $randomid = $idmatch[1];
1440  foreach ($this->getOrderingElementList() as $answeridx => $answer) {
1441  if ($answer->getRandomIdentifier() == $randomid) {
1442  $solutionSubmit[$answeridx] = $ordervalue;
1443  $ordervalue++;
1444  }
1445  }
1446  }
1447  }
1448  }
1449  } elseif ($this->getOrderingType() == OQ_NESTED_TERMS || $this->getOrderingType() == OQ_NESTED_PICTURES) {
1450  $index = 0;
1451  foreach ($formSubmissionDataStructure['content'] as $randomId => $content) {
1452  $indentation = $formSubmissionDataStructure['indentation'];
1453 
1454  $value1 = $index++;
1455  $value2 = implode(':', array($randomId, $indentation));
1456 
1457  $solutionSubmit[$value1] = $value2;
1458  }
1459  } else {
1460  foreach ($formSubmissionDataStructure as $key => $value) {
1461  $matches = null;
1462  if (preg_match("/^order_(\d+)/", $key, $matches)) {
1463  if (!(preg_match("/initial_value_\d+/", $value))) {
1464  if (strlen($value)) {
1465  foreach ($this->getOrderingElementList() as $answeridx => $answer) {
1466  if ($answer->getRandomIdentifier() == $matches[1]) {
1467  $solutionSubmit[$answeridx] = $value;
1468  }
1469  }
1470  }
1471  }
1472  }
1473  }
1474  }
1475 
1476  return $solutionSubmit;
1477  }
1478 
1480  {
1481  require_once 'Modules/TestQuestionPool/classes/forms/class.ilAssOrderingFormValuesObjectsConverter.php';
1482  $converter = new ilAssOrderingFormValuesObjectsConverter();
1483  $converter->setPostVar(self::ORDERING_ELEMENT_FORM_FIELD_POSTVAR);
1484 
1485  return $converter;
1486  }
1487 
1489  {
1490  $formDataConverter = $this->buildOrderingElementFormDataConverter();
1492 
1493  $formDataConverter->setImageRemovalCommand(self::ORDERING_ELEMENT_FORM_CMD_REMOVE_IMG);
1494  $formDataConverter->setImageUrlPath($this->getImagePathWeb());
1495  $formDataConverter->setImageFsPath($this->getImagePath());
1496 
1497  if ($this->getThumbPrefix()) {
1498  $formDataConverter->setThumbnailPrefix($this->getThumbPrefix());
1499  }
1500  return $formDataConverter;
1501  }
1502 
1504  {
1505  $formDataConverter = $this->buildOrderingElementFormDataConverter();
1507  return $formDataConverter;
1508  }
1509 
1511  {
1512  $formDataConverter = $this->buildOrderingElementFormDataConverter();
1514 
1515  if ($this->getOrderingType() == OQ_NESTED_PICTURES) {
1516  $formDataConverter->setImageRemovalCommand(self::ORDERING_ELEMENT_FORM_CMD_REMOVE_IMG);
1517  $formDataConverter->setImageUrlPath($this->getImagePathWeb());
1518  $formDataConverter->setThumbnailPrefix($this->getThumbPrefix());
1519  }
1520 
1521  return $formDataConverter;
1522  }
1523 }
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...
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.
$post_array
Definition: webdav.php:31
calculateReachedPointsForSolution(ilAssOrderingElementList $solutionOrderingElementList)
$mobs
Definition: imgupload.php:70
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)
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=[])
static _getOriginalId(int $question_id)
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.
duplicate(bool $for_test=true, ?string $title="", ?string $author="", ?string $owner="", $testObjId=null)
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="")
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
fetchIndexedValuesFromValuePairs(array $valuePairs)
$index
Definition: metadata.php:145
$path
Definition: ltiservices.php:32
global $DIC
Definition: feed.php:28
setExportDetailsXLS(ilAssExcelFormatHelper $worksheet, int $startrow, int $active_id, int $pass)
{}
saveCurrentSolution(int $active_id, int $pass, $value1, $value2, bool $authorized=true, $tstamp=0)
setBold(string $a_coords)
Set cell(s) to bold.
getImagePath($question_id=null, $object_id=null)
Returns the image path for web accessable images of a question.
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="")
convert image
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)
supportsJavascriptOutput()
Returns true if the question type supports JavaScript output.
This class represents a property in a property form.
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
setId(int $id=-1)
__construct(Container $dic, ilPlugin $plugin)
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)
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.
ensureValidIdentifiers(ilAssOrderingElement $element)
saveAnswerSpecificDataToDb()
Saves the answer specific records into a question types answer table.
$i
Definition: metadata.php:41
setQuestion(string $question="")
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...