ILIAS  release_5-3 Revision v5.3.23-19-g915713cf615
class.assMatchingQuestion.php
Go to the documentation of this file.
1<?php
2/* Copyright (c) 1998-2013 ILIAS open source, Extended GPL, see docs/LICENSE */
3
4require_once './Modules/TestQuestionPool/classes/class.assQuestion.php';
5require_once './Modules/Test/classes/inc.AssessmentConstants.php';
6require_once './Modules/TestQuestionPool/interfaces/interface.ilObjQuestionScoringAdjustable.php';
7require_once './Modules/TestQuestionPool/interfaces/interface.ilObjAnswerScoringAdjustable.php';
8require_once './Modules/TestQuestionPool/interfaces/interface.iQuestionCondition.php';
9require_once './Modules/TestQuestionPool/classes/class.ilUserQuestionResult.php';
10
25{
43
49 protected $terms;
50
51 protected $definitions;
57 public $thumb_geometry = 100;
58
65
66 const MATCHING_MODE_1_ON_1 = '1:1';
67 const MATCHING_MODE_N_ON_N = 'n:n';
68
70
85 public function __construct(
86 $title = "",
87 $comment = "",
88 $author = "",
89 $owner = -1,
90 $question = "",
92 ) {
93 parent::__construct($title, $comment, $author, $owner, $question);
94 $this->matchingpairs = array();
95 $this->matching_type = $matching_type;
96 $this->terms = array();
97 $this->definitions = array();
98 }
99
105 public function isComplete()
106 {
107 if (strlen($this->title)
108 && $this->author
109 && $this->question
110 && count($this->matchingpairs)
111 && $this->getMaximumPoints() > 0
112 ) {
113 return true;
114 }
115 return false;
116 }
117
124 public function saveToDb($original_id = "")
125 {
126 global $ilDB;
127
130 $this->saveAnswerSpecificDataToDb($ilDB);
131
132
133 parent::saveToDb($original_id);
134 }
135
137 {
138 global $ilDB;
139 // delete old terms
140 $ilDB->manipulateF(
141 "DELETE FROM qpl_a_mterm WHERE question_fi = %s",
142 array( 'integer' ),
143 array( $this->getId() )
144 );
145
146 // delete old definitions
147 $ilDB->manipulateF(
148 "DELETE FROM qpl_a_mdef WHERE question_fi = %s",
149 array( 'integer' ),
150 array( $this->getId() )
151 );
152
153 $termids = array();
154 // write terms
155 foreach ($this->terms as $key => $term) {
156 $next_id = $ilDB->nextId('qpl_a_mterm');
157 $ilDB->insert('qpl_a_mterm', array(
158 'term_id' => array('integer', $next_id),
159 'question_fi' => array('integer', $this->getId()),
160 'picture' => array('text', $term->picture),
161 'term' => array('text', $term->text),
162 'ident' => array('integer', $term->identifier)
163 ));
164 $termids[$term->identifier] = $next_id;
165 }
166
167 $definitionids = array();
168 // write definitions
169 foreach ($this->definitions as $key => $definition) {
170 $next_id = $ilDB->nextId('qpl_a_mdef');
171 $ilDB->insert('qpl_a_mdef', array(
172 'def_id' => array('integer', $next_id),
173 'question_fi' => array('integer', $this->getId()),
174 'picture' => array('text', $definition->picture),
175 'definition' => array('text', $definition->text),
176 'ident' => array('integer', $definition->identifier)
177 ));
178 $definitionids[$definition->identifier] = $next_id;
179 }
180
181 $ilDB->manipulateF(
182 "DELETE FROM qpl_a_matching WHERE question_fi = %s",
183 array( 'integer' ),
184 array( $this->getId() )
185 );
187 foreach ($matchingpairs as $key => $pair) {
188 $next_id = $ilDB->nextId('qpl_a_matching');
189 $ilDB->manipulateF(
190 "INSERT INTO qpl_a_matching (answer_id, question_fi, points, term_fi, definition_fi) VALUES (%s, %s, %s, %s, %s)",
191 array( 'integer', 'integer', 'float', 'integer', 'integer' ),
192 array(
193 $next_id,
194 $this->getId(),
195 $pair->points,
196 $termids[$pair->term->identifier],
197 $definitionids[$pair->definition->identifier]
198 )
199 );
200 }
201
202 $this->rebuildThumbnails();
203 }
204
206 {
207 global $ilDB;
208
209 // save additional data
210
211 $ilDB->manipulateF(
212 "DELETE FROM " . $this->getAdditionalTableName() . " WHERE question_fi = %s",
213 array( "integer" ),
214 array( $this->getId() )
215 );
216
217 $ilDB->insert($this->getAdditionalTableName(), array(
218 'question_fi' => array('integer', $this->getId()),
219 'shuffle' => array('text', $this->shuffle),
220 'matching_type' => array('text', $this->matching_type),
221 'thumb_geometry' => array('integer', $this->getThumbGeometry()),
222 'matching_mode' => array('text', $this->getMatchingMode())
223 ));
224 }
225
232 public function loadFromDb($question_id)
233 {
234 global $ilDB;
235
236 $query = "
237 SELECT qpl_questions.*,
238 {$this->getAdditionalTableName()}.*
239 FROM qpl_questions
240 LEFT JOIN {$this->getAdditionalTableName()}
241 ON {$this->getAdditionalTableName()}.question_fi = qpl_questions.question_id
242 WHERE qpl_questions.question_id = %s
243 ";
244
245 $result = $ilDB->queryF(
246 $query,
247 array('integer'),
248 array($question_id)
249 );
250
251 if ($result->numRows() == 1) {
252 $data = $ilDB->fetchAssoc($result);
253 $this->setId($question_id);
254 $this->setObjId($data["obj_fi"]);
255 $this->setTitle($data["title"]);
256 $this->setComment($data["description"]);
257 $this->setOriginalId($data["original_id"]);
258 $this->setNrOfTries($data['nr_of_tries']);
259 $this->setAuthor($data["author"]);
260 $this->setPoints($data["points"]);
261 $this->setOwner($data["owner"]);
262 include_once("./Services/RTE/classes/class.ilRTE.php");
263 $this->setQuestion(ilRTE::_replaceMediaObjectImageSrc($data["question_text"], 1));
264 $this->setThumbGeometry($data["thumb_geometry"]);
265 $this->setShuffle($data["shuffle"]);
266 $this->setMatchingMode($data['matching_mode'] === null ? self::MATCHING_MODE_1_ON_1 : $data['matching_mode']);
267 $this->setEstimatedWorkingTime(substr($data["working_time"], 0, 2), substr($data["working_time"], 3, 2), substr($data["working_time"], 6, 2));
268
269 try {
270 $this->setAdditionalContentEditingMode($data['add_cont_edit_mode']);
271 } catch (ilTestQuestionPoolException $e) {
272 }
273 }
274
275 $termids = array();
276 $result = $ilDB->queryF(
277 "SELECT * FROM qpl_a_mterm WHERE question_fi = %s ORDER BY term_id ASC",
278 array('integer'),
279 array($question_id)
280 );
281 include_once "./Modules/TestQuestionPool/classes/class.assAnswerMatchingTerm.php";
282 $this->terms = array();
283 if ($result->numRows() > 0) {
284 while ($data = $ilDB->fetchAssoc($result)) {
285 $term = new assAnswerMatchingTerm($data['term'], $data['picture'], $data['ident']);
286 array_push($this->terms, $term);
287 $termids[$data['term_id']] = $term;
288 }
289 }
290
291 $definitionids = array();
292 $result = $ilDB->queryF(
293 "SELECT * FROM qpl_a_mdef WHERE question_fi = %s ORDER BY def_id ASC",
294 array('integer'),
295 array($question_id)
296 );
297 include_once "./Modules/TestQuestionPool/classes/class.assAnswerMatchingDefinition.php";
298 $this->definitions = array();
299 if ($result->numRows() > 0) {
300 while ($data = $ilDB->fetchAssoc($result)) {
301 $definition = new assAnswerMatchingDefinition($data['definition'], $data['picture'], $data['ident']);
302 array_push($this->definitions, $definition);
303 $definitionids[$data['def_id']] = $definition;
304 }
305 }
306
307 $this->matchingpairs = array();
308 $result = $ilDB->queryF(
309 "SELECT * FROM qpl_a_matching WHERE question_fi = %s ORDER BY answer_id",
310 array('integer'),
311 array($question_id)
312 );
313 include_once "./Modules/TestQuestionPool/classes/class.assAnswerMatchingPair.php";
314 if ($result->numRows() > 0) {
315 while ($data = $ilDB->fetchAssoc($result)) {
316 array_push($this->matchingpairs, new assAnswerMatchingPair($termids[$data['term_fi']], $definitionids[$data['definition_fi']], $data['points']));
317 }
318 }
319 parent::loadFromDb($question_id);
320 }
321
322
326 public function duplicate($for_test = true, $title = "", $author = "", $owner = "", $testObjId = null)
327 {
328 if ($this->id <= 0) {
329 // The question has not been saved. It cannot be duplicated
330 return;
331 }
332 // duplicate the question in database
333 $this_id = $this->getId();
334 $thisObjId = $this->getObjId();
335
336 $clone = $this;
337 include_once("./Modules/TestQuestionPool/classes/class.assQuestion.php");
339 $clone->id = -1;
340
341 if ((int) $testObjId > 0) {
342 $clone->setObjId($testObjId);
343 }
344
345 if ($title) {
346 $clone->setTitle($title);
347 }
348 if ($author) {
349 $clone->setAuthor($author);
350 }
351 if ($owner) {
352 $clone->setOwner($owner);
353 }
354 if ($for_test) {
355 $clone->saveToDb($original_id);
356 } else {
357 $clone->saveToDb();
358 }
359
360 // copy question page content
361 $clone->copyPageOfQuestion($this_id);
362 // copy XHTML media objects
363 $clone->copyXHTMLMediaObjectsOfQuestion($this_id);
364 // duplicate the image
365 $clone->duplicateImages($this_id, $thisObjId, $clone->getId(), $testObjId);
366
367 $clone->onDuplicate($thisObjId, $this_id, $clone->getObjId(), $clone->getId());
368
369 return $clone->id;
370 }
371
375 public function copyObject($target_questionpool_id, $title = "")
376 {
377 if ($this->id <= 0) {
378 // The question has not been saved. It cannot be duplicated
379 return;
380 }
381 // duplicate the question in database
382 $clone = $this;
383 include_once("./Modules/TestQuestionPool/classes/class.assQuestion.php");
385 $clone->id = -1;
386 $source_questionpool_id = $this->getObjId();
387 $clone->setObjId($target_questionpool_id);
388 if ($title) {
389 $clone->setTitle($title);
390 }
391 $clone->saveToDb();
392 // copy question page content
393 $clone->copyPageOfQuestion($original_id);
394 // copy XHTML media objects
395 $clone->copyXHTMLMediaObjectsOfQuestion($original_id);
396 // duplicate the image
397 $clone->copyImages($original_id, $source_questionpool_id);
398
399 $clone->onCopy($source_questionpool_id, $original_id, $clone->getObjId(), $clone->getId());
400
401 return $clone->id;
402 }
403
404 public function createNewOriginalFromThisDuplicate($targetParentId, $targetQuestionTitle = "")
405 {
406 if ($this->id <= 0) {
407 // The question has not been saved. It cannot be duplicated
408 return;
409 }
410
411 include_once("./Modules/TestQuestionPool/classes/class.assQuestion.php");
412
413 $sourceQuestionId = $this->id;
414 $sourceParentId = $this->getObjId();
415
416 // duplicate the question in database
417 $clone = $this;
418 $clone->id = -1;
419
420 $clone->setObjId($targetParentId);
421
422 if ($targetQuestionTitle) {
423 $clone->setTitle($targetQuestionTitle);
424 }
425
426 $clone->saveToDb();
427 // copy question page content
428 $clone->copyPageOfQuestion($sourceQuestionId);
429 // copy XHTML media objects
430 $clone->copyXHTMLMediaObjectsOfQuestion($sourceQuestionId);
431 // duplicate the image
432 $clone->copyImages($sourceQuestionId, $sourceParentId);
433
434 $clone->onCopy($sourceParentId, $sourceQuestionId, $clone->getObjId(), $clone->getId());
435
436 return $clone->id;
437 }
438
439 public function duplicateImages($question_id, $objectId = null)
440 {
441 global $ilLog;
442 $imagepath = $this->getImagePath();
443 $imagepath_original = str_replace("/$this->id/images", "/$question_id/images", $imagepath);
444
445 if ((int) $objectId > 0) {
446 $imagepath_original = str_replace("/$this->obj_id/", "/$objectId/", $imagepath_original);
447 }
448
449 foreach ($this->terms as $term) {
450 if (strlen($term->picture)) {
451 $filename = $term->picture;
452 if (!file_exists($imagepath)) {
453 ilUtil::makeDirParents($imagepath);
454 }
455 if (!@copy($imagepath_original . $filename, $imagepath . $filename)) {
456 $ilLog->write("matching question image could not be duplicated: $imagepath_original$filename");
457 }
458 if (@file_exists($imagepath_original . $this->getThumbPrefix() . $filename)) {
459 if (!@copy($imagepath_original . $this->getThumbPrefix() . $filename, $imagepath . $this->getThumbPrefix() . $filename)) {
460 $ilLog->write("matching question image thumbnail could not be duplicated: $imagepath_original" . $this->getThumbPrefix() . $filename);
461 }
462 }
463 }
464 }
465 foreach ($this->definitions as $definition) {
466 if (strlen($definition->picture)) {
467 $filename = $definition->picture;
468 if (!file_exists($imagepath)) {
469 ilUtil::makeDirParents($imagepath);
470 }
471 if (!@copy($imagepath_original . $filename, $imagepath . $filename)) {
472 $ilLog->write("matching question image could not be duplicated: $imagepath_original$filename");
473 }
474 if (@file_exists($imagepath_original . $this->getThumbPrefix() . $filename)) {
475 if (!@copy($imagepath_original . $this->getThumbPrefix() . $filename, $imagepath . $this->getThumbPrefix() . $filename)) {
476 $ilLog->write("matching question image thumbnail could not be duplicated: $imagepath_original" . $this->getThumbPrefix() . $filename);
477 }
478 }
479 }
480 }
481 }
482
483 public function copyImages($question_id, $source_questionpool)
484 {
485 global $ilLog;
486
487 $imagepath = $this->getImagePath();
488 $imagepath_original = str_replace("/$this->id/images", "/$question_id/images", $imagepath);
489 $imagepath_original = str_replace("/$this->obj_id/", "/$source_questionpool/", $imagepath_original);
490 foreach ($this->terms as $term) {
491 if (strlen($term->picture)) {
492 if (!file_exists($imagepath)) {
493 ilUtil::makeDirParents($imagepath);
494 }
495 $filename = $term->picture;
496 if (!@copy($imagepath_original . $filename, $imagepath . $filename)) {
497 $ilLog->write("matching question image could not be copied: $imagepath_original$filename");
498 }
499 if (!@copy($imagepath_original . $this->getThumbPrefix() . $filename, $imagepath . $this->getThumbPrefix() . $filename)) {
500 $ilLog->write("matching question image thumbnail could not be copied: $imagepath_original" . $this->getThumbPrefix() . $filename);
501 }
502 }
503 }
504 foreach ($this->definitions as $definition) {
505 if (strlen($definition->picture)) {
506 $filename = $definition->picture;
507 if (!file_exists($imagepath)) {
508 ilUtil::makeDirParents($imagepath);
509 }
510
511 if (assQuestion::isFileAvailable($imagepath_original . $filename)) {
512 copy($imagepath_original . $filename, $imagepath . $filename);
513 } else {
514 $ilLog->write("matching question image could not be copied: $imagepath_original$filename");
515 }
516
517 if (assQuestion::isFileAvailable($imagepath_original . $this->getThumbPrefix() . $filename)) {
518 copy($imagepath_original . $this->getThumbPrefix() . $filename, $imagepath . $this->getThumbPrefix() . $filename);
519 } else {
520 $ilLog->write("matching question image thumbnail could not be copied: $imagepath_original" . $this->getThumbPrefix() . $filename);
521 }
522 }
523 }
524 }
525
536 public function insertMatchingPair($position, $term = null, $definition = null, $points = 0.0)
537 {
538 include_once "./Modules/TestQuestionPool/classes/class.assAnswerMatchingPair.php";
539 include_once "./Modules/TestQuestionPool/classes/class.assAnswerMatchingTerm.php";
540 include_once "./Modules/TestQuestionPool/classes/class.assAnswerMatchingDefinition.php";
541 if (is_null($term)) {
542 $term = new assAnswerMatchingTerm();
543 }
544 if (is_null($definition)) {
545 $definition = new assAnswerMatchingDefinition();
546 }
547 $pair = new assAnswerMatchingPair($term, $definition, $points);
548 if ($position < count($this->matchingpairs)) {
549 $part1 = array_slice($this->matchingpairs, 0, $position);
550 $part2 = array_slice($this->matchingpairs, $position);
551 $this->matchingpairs = array_merge($part1, array($pair), $part2);
552 } else {
553 array_push($this->matchingpairs, $pair);
554 }
555 }
556
568 public function addMatchingPair($term = null, $definition = null, $points = 0.0)
569 {
570 require_once './Modules/TestQuestionPool/classes/class.assAnswerMatchingPair.php';
571 require_once './Modules/TestQuestionPool/classes/class.assAnswerMatchingTerm.php';
572 require_once './Modules/TestQuestionPool/classes/class.assAnswerMatchingDefinition.php';
573 if (is_null($term)) {
574 $term = new assAnswerMatchingTerm();
575 }
576 if (is_null($definition)) {
577 $definition = new assAnswerMatchingDefinition();
578 }
579 $pair = new assAnswerMatchingPair($term, $definition, $points);
580 array_push($this->matchingpairs, $pair);
581 }
582
586 public function getTermWithIdentifier($a_identifier)
587 {
588 foreach ($this->terms as $term) {
589 if ($term->identifier == $a_identifier) {
590 return $term;
591 }
592 }
593 return null;
594 }
595
599 public function getDefinitionWithIdentifier($a_identifier)
600 {
601 foreach ($this->definitions as $definition) {
602 if ($definition->identifier == $a_identifier) {
603 return $definition;
604 }
605 }
606 return null;
607 }
608
617 public function getMatchingPair($index = 0)
618 {
619 if ($index < 0) {
620 return null;
621 }
622 if (count($this->matchingpairs) < 1) {
623 return null;
624 }
625 if ($index >= count($this->matchingpairs)) {
626 return null;
627 }
628 return $this->matchingpairs[$index];
629 }
630
638 public function deleteMatchingPair($index = 0)
639 {
640 if ($index < 0) {
641 return;
642 }
643 if (count($this->matchingpairs) < 1) {
644 return;
645 }
646 if ($index >= count($this->matchingpairs)) {
647 return;
648 }
649 unset($this->matchingpairs[$index]);
650 $this->matchingpairs = array_values($this->matchingpairs);
651 }
652
657 public function flushMatchingPairs()
658 {
659 $this->matchingpairs = array();
660 }
661
668 public function getMatchingPairCount()
669 {
670 return count($this->matchingpairs);
671 }
672
679 public function getTerms()
680 {
681 return $this->terms;
682 }
683
690 public function getDefinitions()
691 {
692 return $this->definitions;
693 }
694
701 public function getTermCount()
702 {
703 return count($this->terms);
704 }
705
712 public function getDefinitionCount()
713 {
714 return count($this->definitions);
715 }
716
723 public function addTerm($term)
724 {
725 array_push($this->terms, $term);
726 }
727
734 public function addDefinition($definition)
735 {
736 array_push($this->definitions, $definition);
737 }
738
745 public function insertTerm($position, $term = null)
746 {
747 if (is_null($term)) {
748 include_once "./Modules/TestQuestionPool/classes/class.assAnswerMatchingTerm.php";
749 $term = new assAnswerMatchingTerm();
750 }
751 if ($position < count($this->terms)) {
752 $part1 = array_slice($this->terms, 0, $position);
753 $part2 = array_slice($this->terms, $position);
754 $this->terms = array_merge($part1, array($term), $part2);
755 } else {
756 array_push($this->terms, $term);
757 }
758 }
759
766 public function insertDefinition($position, $definition = null)
767 {
768 if (is_null($definition)) {
769 include_once "./Modules/TestQuestionPool/classes/class.assAnswerMatchingDefinition.php";
770 $definition = new assAnswerMatchingDefinition();
771 }
772 if ($position < count($this->definitions)) {
773 $part1 = array_slice($this->definitions, 0, $position);
774 $part2 = array_slice($this->definitions, $position);
775 $this->definitions = array_merge($part1, array($definition), $part2);
776 } else {
777 array_push($this->definitions, $definition);
778 }
779 }
780
785 public function flushTerms()
786 {
787 $this->terms = array();
788 }
789
794 public function flushDefinitions()
795 {
796 $this->definitions = array();
797 }
798
805 public function deleteTerm($position)
806 {
807 unset($this->terms[$position]);
808 $this->terms = array_values($this->terms);
809 }
810
817 public function deleteDefinition($position)
818 {
819 unset($this->definitions[$position]);
820 $this->definitions = array_values($this->definitions);
821 }
822
830 public function setTerm($term, $index)
831 {
832 $this->terms[$index] = $term;
833 }
834
845 public function calculateReachedPoints($active_id, $pass = null, $authorizedSolution = true, $returndetails = false)
846 {
847 if ($returndetails) {
848 throw new ilTestException('return details not implemented for ' . __METHOD__);
849 }
850
851 global $ilDB;
852
853 $found_values = array();
854 if (is_null($pass)) {
855 $pass = $this->getSolutionMaxPass($active_id);
856 }
857 $result = $this->getCurrentSolutionResultSet($active_id, $pass, $authorizedSolution);
858 while ($data = $ilDB->fetchAssoc($result)) {
859 if (strcmp($data["value1"], "") != 0) {
860 if (!isset($found_values[$data['value2']])) {
861 $found_values[$data['value2']] = array();
862 }
863
864 $found_values[$data['value2']][] = $data['value1'];
865 }
866 }
867
868 $points = $this->calculateReachedPointsForSolution($found_values);
869
870 return $points;
871 }
872
876 public function getMaximumPoints()
877 {
878 $points = 0;
879
880 foreach ($this->getMaximumScoringMatchingPairs() as $pair) {
881 $points += $pair->points;
882 }
883
884 return $points;
885 }
886
888 {
889 if ($this->getMatchingMode() == self::MATCHING_MODE_N_ON_N) {
890 return $this->getPositiveScoredMatchingPairs();
891 } elseif ($this->getMatchingMode() == self::MATCHING_MODE_1_ON_1) {
893 }
894
895 return array();
896 }
897
899 {
900 $matchingPairs = array();
901
902 foreach ($this->matchingpairs as $pair) {
903 if ($pair->points <= 0) {
904 continue;
905 }
906
907 $matchingPairs[] = $pair;
908 }
909
910 return $matchingPairs;
911 }
912
914 {
915 $matchingPairsByDefinition = array();
916
917 foreach ($this->matchingpairs as $pair) {
918 if ($pair->points <= 0) {
919 continue;
920 }
921
922 $defId = $pair->definition->identifier;
923
924 if (!isset($matchingPairsByDefinition[$defId])) {
925 $matchingPairsByDefinition[$defId] = $pair;
926 } elseif ($pair->points > $matchingPairsByDefinition[$defId]->points) {
927 $matchingPairsByDefinition[$defId] = $pair;
928 }
929 }
930
931 return $matchingPairsByDefinition;
932 }
933
938 public function fetchIndexedValuesFromValuePairs(array $valuePairs)
939 {
940 $indexedValues = array();
941
942 foreach ($valuePairs as $valuePair) {
943 if (!isset($indexedValues[$valuePair['value2']])) {
944 $indexedValues[$valuePair['value2']] = array();
945 }
946
947 $indexedValues[$valuePair['value2']][] = $valuePair['value1'];
948 }
949
950 return $indexedValues;
951 }
952
962 {
963 $extension = "";
964 if (preg_match("/.*\\.(\\w+)$/", $filename, $matches)) {
965 $extension = $matches[1];
966 }
967 return md5($filename) . "." . $extension;
968 }
969
970 public function removeTermImage($index)
971 {
972 $term = $this->terms[$index];
973 if (is_object($term)) {
974 $this->deleteImagefile($term->picture);
975 $term->picture = null;
976 }
977 }
978
980 {
981 $definition = $this->definitions[$index];
982 if (is_object($definition)) {
983 $this->deleteImagefile($definition->picture);
984 $definition->picture = null;
985 }
986 }
987
988
995 public function deleteImagefile($filename)
996 {
997 $deletename = $filename;
998 $result = @unlink($this->getImagePath() . $deletename);
999 $result = $result & @unlink($this->getImagePath() . $this->getThumbPrefix() . $deletename);
1000 return $result;
1001 }
1002
1011 public function setImageFile($image_tempfilename, $image_filename, $previous_filename = '')
1012 {
1013 $result = true;
1014 if (strlen($image_tempfilename)) {
1015 $image_filename = str_replace(" ", "_", $image_filename);
1016 $imagepath = $this->getImagePath();
1017 if (!file_exists($imagepath)) {
1018 ilUtil::makeDirParents($imagepath);
1019 }
1020 $savename = $image_filename;
1021 if (!ilUtil::moveUploadedFile($image_tempfilename, $savename, $imagepath . $savename)) {
1022 $result = false;
1023 } else {
1024 // create thumbnail file
1025 $thumbpath = $imagepath . $this->getThumbPrefix() . $savename;
1026 ilUtil::convertImage($imagepath . $savename, $thumbpath, "JPEG", $this->getThumbGeometry());
1027 }
1028 if ($result && (strcmp($image_filename, $previous_filename) != 0) && (strlen($previous_filename))) {
1029 $this->deleteImagefile($previous_filename);
1030 }
1031 }
1032 return $result;
1033 }
1034
1036 {
1037 $postData = $_POST['matching'][$this->getId()];
1038
1039 $matchings = array();
1040
1041 foreach ($this->getDefinitions() as $definition) {
1042 if (isset($postData[$definition->identifier])) {
1043 foreach ($this->getTerms() as $term) {
1044 if (isset($postData[$definition->identifier][$term->identifier])) {
1045 if (!is_array($postData[$definition->identifier])) {
1046 $postData[$definition->identifier] = array();
1047 }
1048
1049 $matchings[$definition->identifier][] = $term->identifier;
1050 }
1051 }
1052 }
1053 }
1054
1055 return $matchings;
1056 }
1057
1058 private function checkSubmittedMatchings($submittedMatchings)
1059 {
1060 if ($this->getMatchingMode() == self::MATCHING_MODE_N_ON_N) {
1061 return true;
1062 }
1063
1064 $handledTerms = array();
1065
1066 foreach ($submittedMatchings as $definition => $terms) {
1067 if (count($terms) > 1) {
1068 ilUtil::sendFailure($this->lng->txt("multiple_matching_values_selected"), true);
1069 return false;
1070 }
1071
1072 foreach ($terms as $i => $term) {
1073 if (isset($handledTerms[$term])) {
1074 ilUtil::sendFailure($this->lng->txt("duplicate_matching_values_selected"), true);
1075 return false;
1076 }
1077
1078 $handledTerms[$term] = $term;
1079 }
1080 }
1081
1082 return true;
1083 }
1084
1093 public function saveWorkingData($active_id, $pass = null, $authorized = true)
1094 {
1095 global $ilDB;
1096
1097 $submittedMatchings = $this->fetchSubmittedMatchingsFromPost();
1098 $submittedMatchingsValid = $this->checkSubmittedMatchings($submittedMatchings);
1099
1100 $matchingsExist = false;
1101
1102 if ($submittedMatchingsValid) {
1103 if (is_null($pass)) {
1104 include_once "./Modules/Test/classes/class.ilObjTest.php";
1105 $pass = ilObjTest::_getPass($active_id);
1106 }
1107
1108 $this->getProcessLocker()->executeUserSolutionUpdateLockOperation(function () use (&$matchingsExist, $submittedMatchings, $active_id, $pass, $authorized) {
1109 $this->removeCurrentSolution($active_id, $pass, $authorized);
1110
1111 foreach ($submittedMatchings as $definition => $terms) {
1112 foreach ($terms as $i => $term) {
1113 $this->saveCurrentSolution($active_id, $pass, $term, $definition, $authorized);
1114 $matchingsExist = true;
1115 }
1116 }
1117 });
1118
1119 $saveWorkingDataResult = true;
1120 } else {
1121 $saveWorkingDataResult = false;
1122 }
1123
1124 include_once("./Modules/Test/classes/class.ilObjAssessmentFolder.php");
1126 if ($matchingsExist) {
1127 assQuestion::logAction($this->lng->txtlng("assessment", "log_user_entered_values", ilObjAssessmentFolder::_getLogLanguage()), $active_id, $this->getId());
1128 } else {
1129 assQuestion::logAction($this->lng->txtlng("assessment", "log_user_not_entered_values", ilObjAssessmentFolder::_getLogLanguage()), $active_id, $this->getId());
1130 }
1131 }
1132
1133 return $saveWorkingDataResult;
1134 }
1135
1136 protected function savePreviewData(ilAssQuestionPreviewSession $previewSession)
1137 {
1138 $submittedMatchings = $this->fetchSubmittedMatchingsFromPost();
1139
1140 if ($this->checkSubmittedMatchings($submittedMatchings)) {
1141 $previewSession->setParticipantsSolution($submittedMatchings);
1142 }
1143 }
1144
1148 protected function reworkWorkingData($active_id, $pass, $obligationsAnswered, $authorized)
1149 {
1150 // nothing to rework!
1151 }
1152
1153 public function getRandomId()
1154 {
1155 mt_srand((double) microtime()*1000000);
1156 $random_number = mt_rand(1, 100000);
1157 $found = false;
1158 while ($found) {
1159 $found = false;
1160 foreach ($this->matchingpairs as $key => $pair) {
1161 if (($pair->term->identifier == $random_number) || ($pair->definition->identifier == $random_number)) {
1162 $found = true;
1163 $random_number++;
1164 }
1165 }
1166 }
1167 return $random_number;
1168 }
1169
1176 public function setShuffle($shuffle = true)
1177 {
1178 switch ($shuffle) {
1179 case 0:
1180 case 1:
1181 case 2:
1182 case 3:
1183 $this->shuffle = $shuffle;
1184 break;
1185 default:
1186 $this->shuffle = 1;
1187 break;
1188 }
1189 }
1190
1196 public function getQuestionType()
1197 {
1198 return "assMatchingQuestion";
1199 }
1200
1206 public function getAdditionalTableName()
1207 {
1208 return "qpl_qst_matching";
1209 }
1210
1216 public function getAnswerTableName()
1217 {
1218 return array("qpl_a_matching", "qpl_a_mterm");
1219 }
1220
1226 {
1227 return parent::getRTETextWithMediaObjects();
1228 }
1229
1233 public function &getMatchingPairs()
1234 {
1235 return $this->matchingpairs;
1236 }
1237
1241 public function setExportDetailsXLS($worksheet, $startrow, $active_id, $pass)
1242 {
1243 parent::setExportDetailsXLS($worksheet, $startrow, $active_id, $pass);
1244
1245 $solutions = $this->getSolutionValues($active_id, $pass);
1246
1247 $imagepath = $this->getImagePath();
1248 $i = 1;
1249 foreach ($solutions as $solution) {
1250 $matches_written = false;
1251 foreach ($this->getMatchingPairs() as $idx => $pair) {
1252 if (!$matches_written) {
1253 $worksheet->setCell($startrow + $i, 1, $this->lng->txt("matches"));
1254 }
1255 $matches_written = true;
1256 if ($pair->definition->identifier == $solution["value2"]) {
1257 if (strlen($pair->definition->text)) {
1258 $worksheet->setCell($startrow + $i, 0, $pair->definition->text);
1259 } else {
1260 $worksheet->setCell($startrow + $i, 0, $pair->definition->picture);
1261 }
1262 }
1263 if ($pair->term->identifier == $solution["value1"]) {
1264 if (strlen($pair->term->text)) {
1265 $worksheet->setCell($startrow + $i, 2, $pair->term->text);
1266 } else {
1267 $worksheet->setCell($startrow + $i, 2, $pair->term->picture);
1268 }
1269 }
1270 }
1271 $i++;
1272 }
1273
1274 return $startrow + $i + 1;
1275 }
1276
1282 public function getThumbGeometry()
1283 {
1284 return $this->thumb_geometry;
1285 }
1286
1292 public function getThumbSize()
1293 {
1294 return $this->getThumbGeometry();
1295 }
1296
1302 public function setThumbGeometry($a_geometry)
1303 {
1304 $this->thumb_geometry = ($a_geometry < 1) ? 100 : $a_geometry;
1305 }
1306
1310 public function rebuildThumbnails()
1311 {
1312 foreach ($this->terms as $term) {
1313 if (strlen($term->picture)) {
1314 $this->generateThumbForFile($this->getImagePath(), $term->picture);
1315 }
1316 }
1317 foreach ($this->definitions as $definition) {
1318 if (strlen($definition->picture)) {
1319 $this->generateThumbForFile($this->getImagePath(), $definition->picture);
1320 }
1321 }
1322 }
1323
1324 public function getThumbPrefix()
1325 {
1326 return "thumb.";
1327 }
1328
1329 protected function generateThumbForFile($path, $file)
1330 {
1331 $filename = $path . $file;
1332 if (@file_exists($filename)) {
1333 $thumbpath = $path . $this->getThumbPrefix() . $file;
1334 $path_info = @pathinfo($filename);
1335 $ext = "";
1336 switch (strtoupper($path_info['extension'])) {
1337 case 'PNG':
1338 $ext = 'PNG';
1339 break;
1340 case 'GIF':
1341 $ext = 'GIF';
1342 break;
1343 default:
1344 $ext = 'JPEG';
1345 break;
1346 }
1347 ilUtil::convertImage($filename, $thumbpath, $ext, $this->getThumbGeometry());
1348 }
1349 }
1350
1355 public function toJSON()
1356 {
1357 $result = array();
1358
1359 $result['id'] = (int) $this->getId();
1360 $result['type'] = (string) $this->getQuestionType();
1361 $result['title'] = (string) $this->getTitle();
1362 $result['question'] = $this->formatSAQuestion($this->getQuestion());
1363 $result['nr_of_tries'] = (int) $this->getNrOfTries();
1364 $result['matching_mode'] = $this->getMatchingMode();
1365 $result['shuffle'] = true;
1366 $result['feedback'] = array(
1367 'onenotcorrect' => $this->formatSAQuestion($this->feedbackOBJ->getGenericFeedbackTestPresentation($this->getId(), false)),
1368 'allcorrect' => $this->formatSAQuestion($this->feedbackOBJ->getGenericFeedbackTestPresentation($this->getId(), true))
1369 );
1370
1371 require_once 'Services/Randomization/classes/class.ilArrayElementShuffler.php';
1372 $this->setShuffler(new ilArrayElementShuffler());
1373 $seed = $this->getShuffler()->getSeed();
1374
1375 $terms = array();
1376 $this->getShuffler()->setSeed($this->getShuffler()->buildSeedFromString($seed . 'terms'));
1377 foreach ($this->getShuffler()->shuffle($this->getTerms()) as $term) {
1378 $terms[] = array(
1379 "text" => $this->formatSAQuestion($term->text),
1380 "id" =>(int) $this->getId() . $term->identifier
1381 );
1382 }
1383 $result['terms'] = $terms;
1384
1385 // alex 9.9.2010 as a fix for bug 6513 I added the question id
1386 // to the "def_id" in the array. The $pair->definition->identifier is not
1387 // unique, since it gets it value from the morder table field
1388 // this value is not changed, when a question is copied.
1389 // thus copying the same question on a page results in problems
1390 // when the second one (the copy) is answered.
1391
1392 $definitions = array();
1393 $this->getShuffler()->setSeed($this->getShuffler()->buildSeedFromString($seed . 'definitions'));
1394 foreach ($this->getShuffler()->shuffle($this->getDefinitions()) as $def) {
1395 $definitions[] = array(
1396 "text" => $this->formatSAQuestion((string) $def->text),
1397 "id" => (int) $this->getId() . $def->identifier
1398 );
1399 }
1400 $result['definitions'] = $definitions;
1401
1402 // #10353
1403 $matchings = array();
1404 foreach ($this->getMatchingPairs() as $pair) {
1405 // fau: fixLmMatchingPoints - ignore matching pairs with 0 or negative points
1406 if ($pair->points <= 0) {
1407 continue;
1408 }
1409 // fau.
1410
1411 $pid = $pair->definition->identifier;
1412 if ($this->getMatchingMode() == self::MATCHING_MODE_N_ON_N) {
1413 $pid .= '::' . $pair->term->identifier;
1414 }
1415
1416 if (!isset($matchings[$pid]) || $matchings[$pid]["points"] < $pair->points) {
1417 $matchings[$pid] = array(
1418 "term_id" => (int) $this->getId() . $pair->term->identifier,
1419 "def_id" => (int) $this->getId() . $pair->definition->identifier,
1420 "points" => (int) $pair->points
1421 );
1422 }
1423 }
1424
1425 $result['matchingPairs'] = array_values($matchings);
1426
1427 $mobs = ilObjMediaObject::_getMobsOfObject("qpl:html", $this->getId());
1428 $result['mobs'] = $mobs;
1429
1430 global $lng;
1431 $lng->loadLanguageModule('assessment');
1432 $result['reset_button_label'] = $lng->txt("reset_terms");
1433
1434 return json_encode($result);
1435 }
1436
1438 {
1439 return true;
1440 }
1441
1442 public function supportsNonJsOutput()
1443 {
1444 return false;
1445 }
1446
1448 {
1449 $this->matchingMode = $matchingMode;
1450 }
1451
1452 public function getMatchingMode()
1453 {
1454 return $this->matchingMode;
1455 }
1456
1461 protected function calculateReachedPointsForSolution($found_values)
1462 {
1463 $points = 0;
1464 foreach ($found_values as $definition => $terms) {
1465 foreach ($terms as $term) {
1466 foreach ($this->matchingpairs as $pair) {
1467 if ($pair->definition->identifier == $definition && $pair->term->identifier == $term) {
1468 $points += $pair->points;
1469 }
1470 }
1471 }
1472 }
1473 return $points;
1474 }
1475
1484 public function getOperators($expression)
1485 {
1486 require_once "./Modules/TestQuestionPool/classes/class.ilOperatorsExpressionMapping.php";
1488 }
1489
1494 public function getExpressionTypes()
1495 {
1496 return array(
1501 );
1502 }
1511 public function getUserQuestionResult($active_id, $pass)
1512 {
1514 global $ilDB;
1515 $result = new ilUserQuestionResult($this, $active_id, $pass);
1516
1517 $data = $ilDB->queryF(
1518 "SELECT ident FROM qpl_a_mdef WHERE question_fi = %s ORDER BY def_id",
1519 array("integer"),
1520 array($this->getId())
1521 );
1522
1523 $definitions = array();
1524 for ($index=1; $index <= $ilDB->numRows($data); ++$index) {
1525 $row = $ilDB->fetchAssoc($data);
1526 $definitions[$row["ident"]] = $index;
1527 }
1528
1529 $data = $ilDB->queryF(
1530 "SELECT ident FROM qpl_a_mterm WHERE question_fi = %s ORDER BY term_id",
1531 array("integer"),
1532 array($this->getId())
1533 );
1534
1535 $terms = array();
1536 for ($index=1; $index <= $ilDB->numRows($data); ++$index) {
1537 $row = $ilDB->fetchAssoc($data);
1538 $terms[$row["ident"]] = $index;
1539 }
1540
1541 $maxStep = $this->lookupMaxStep($active_id, $pass);
1542
1543 if ($maxStep !== null) {
1544 $data = $ilDB->queryF(
1545 "SELECT value1, value2 FROM tst_solutions WHERE active_fi = %s AND pass = %s AND question_fi = %s AND step = %s",
1546 array("integer", "integer", "integer","integer"),
1547 array($active_id, $pass, $this->getId(), $maxStep)
1548 );
1549 } else {
1550 $data = $ilDB->queryF(
1551 "SELECT value1, value2 FROM tst_solutions WHERE active_fi = %s AND pass = %s AND question_fi = %s",
1552 array("integer", "integer", "integer"),
1553 array($active_id, $pass, $this->getId())
1554 );
1555 }
1556
1557 while ($row = $ilDB->fetchAssoc($data)) {
1558 if ($row["value1"] > 0) {
1559 $result->addKeyValue($definitions[$row["value2"]], $terms[$row["value1"]]);
1560 }
1561 }
1562
1563 $points = $this->calculateReachedPoints($active_id, $pass);
1564 $max_points = $this->getMaximumPoints();
1565
1566 $result->setReachedPercentage(($points/$max_points) * 100);
1567
1568 return $result;
1569 }
1570
1579 public function getAvailableAnswerOptions($index = null)
1580 {
1581 if ($index !== null) {
1582 return $this->getMatchingPair($index);
1583 } else {
1584 return $this->getMatchingPairs();
1585 }
1586 }
1587
1591 protected function afterSyncWithOriginal($origQuestionId, $dupQuestionId, $origParentObjId, $dupParentObjId)
1592 {
1593 parent::afterSyncWithOriginal($origQuestionId, $dupQuestionId, $origParentObjId, $dupParentObjId);
1594
1595 $origImagePath = $this->buildImagePath($origQuestionId, $origParentObjId);
1596 $dupImagePath = $this->buildImagePath($dupQuestionId, $dupParentObjId);
1597
1598 ilUtil::delDir($origImagePath);
1599 if (is_dir($dupImagePath)) {
1600 ilUtil::makeDirParents($origImagePath);
1601 ilUtil::rCopy($dupImagePath, $origImagePath);
1602 }
1603 }
1604}
$worksheet
$result
$_POST["username"]
An exception for terminatinating execution or to throw for unit testing.
Class for matching question definitions.
Class for matching question pairs.
Class for matching question terms.
Class for matching questions.
supportsJavascriptOutput()
Returns true if the question type supports JavaScript output.
setThumbGeometry($a_geometry)
Set the thumbnail geometry.
deleteDefinition($position)
Deletes a definition.
getEncryptedFilename($filename)
Returns the encrypted save filename of a matching picture Images are saved with an encrypted filename...
reworkWorkingData($active_id, $pass, $obligationsAnswered, $authorized)
{Reworks the allready saved working data if neccessary.}
__construct( $title="", $comment="", $author="", $owner=-1, $question="", $matching_type=MT_TERMS_DEFINITIONS)
assMatchingQuestion constructor
getMatchingPairCount()
Returns the number of matching pairs.
calculateReachedPointsForSolution($found_values)
addDefinition($definition)
Adds a definition.
getMaximumPoints()
Calculates and Returns the maximum points, a learner can reach answering the question.
savePreviewData(ilAssQuestionPreviewSession $previewSession)
copyObject($target_questionpool_id, $title="")
Copies an assMatchingQuestion.
toJSON()
Returns a JSON representation of the question TODO.
getOperators($expression)
Get all available operations for a specific question.
setExportDetailsXLS($worksheet, $startrow, $active_id, $pass)
{Creates an Excel worksheet for the detailed cumulated results of this question.object}
getDefinitionCount()
Returns the number of definitions.
getDefinitions()
Returns the definitions of the matching question.
getMatchingPair($index=0)
Returns a matching pair with a given index.
createNewOriginalFromThisDuplicate($targetParentId, $targetQuestionTitle="")
duplicate($for_test=true, $title="", $author="", $owner="", $testObjId=null)
Duplicates an assMatchingQuestion.
getQuestionType()
Returns the question type of the question.
isComplete()
Returns true, if a matching question is complete for use.
calculateReachedPoints($active_id, $pass=null, $authorizedSolution=true, $returndetails=false)
Returns the points, a learner has reached answering the question.
insertDefinition($position, $definition=null)
Inserts a definition.
& getMatchingPairs()
Returns the matchingpairs array.
saveWorkingData($active_id, $pass=null, $authorized=true)
Saves the learners input of the question to the database.
rebuildThumbnails()
Rebuild the thumbnail images with a new thumbnail size.
duplicateImages($question_id, $objectId=null)
getTermCount()
Returns the number of terms.
getThumbGeometry()
Get the thumbnail geometry.
deleteTerm($position)
Deletes a term.
checkSubmittedMatchings($submittedMatchings)
getTerms()
Returns the terms of the matching question.
addMatchingPair($term=null, $definition=null, $points=0.0)
Adds an matching pair for an matching choice question.
flushDefinitions()
Deletes all definitions.
fetchIndexedValuesFromValuePairs(array $valuePairs)
loadFromDb($question_id)
Loads a assMatchingQuestion object from a database.
getAnswerTableName()
Returns the name of the answer table in the database.
getDefinitionWithIdentifier($a_identifier)
Returns a definition with a given identifier.
getAdditionalTableName()
Returns the name of the additional question data table in the database.
flushTerms()
Deletes all terms.
copyImages($question_id, $source_questionpool)
flushMatchingPairs()
Deletes all matching pairs.
saveToDb($original_id="")
Saves a assMatchingQuestion object to a database.
getAvailableAnswerOptions($index=null)
If index is null, the function returns an array with all anwser options Else it returns the specific ...
setImageFile($image_tempfilename, $image_filename, $previous_filename='')
Sets the image file and uploads the image to the object's image directory.
setShuffle($shuffle=true)
Sets the shuffle flag.
getThumbSize()
Get the thumbnail geometry.
getTermWithIdentifier($a_identifier)
Returns a term with a given identifier.
setTerm($term, $index)
Sets a specific term.
getRTETextWithMediaObjects()
Collects all text in the question which could contain media objects which were created with the Rich ...
saveAnswerSpecificDataToDb()
Saves the answer specific records into a question types answer table.
afterSyncWithOriginal($origQuestionId, $dupQuestionId, $origParentObjId, $dupParentObjId)
{}
getExpressionTypes()
Get all available expression types for a specific question.
deleteImagefile($filename)
Deletes an imagefile from the system if the file is deleted manually.
deleteMatchingPair($index=0)
Deletes a matching pair with a given index.
insertMatchingPair($position, $term=null, $definition=null, $points=0.0)
Inserts a matching pair for an matching choice question.
insertTerm($position, $term=null)
Inserts a term.
saveAdditionalQuestionDataToDb()
Saves a record to the question types additional data table.
Abstract basic class which is to be extended by the concrete assessment question type classes.
getCurrentSolutionResultSet($active_id, $pass, $authorized=true)
Get a restulset for the current user solution for a this question by active_id and pass.
getSolutionValues($active_id, $pass=null, $authorized=true)
Loads solutions of a given user from the database an returns it.
static _getOriginalId($question_id)
Returns the original id of a question.
formatSAQuestion($a_q)
Format self assessment question.
setId($id=-1)
Sets the id of the assQuestion object.
setOriginalId($original_id)
setObjId($obj_id=0)
Set the object id of the container object.
getSolutionMaxPass($active_id)
Returns the maximum pass a users question solution.
saveQuestionDataToDb($original_id="")
getId()
Gets the id of the assQuestion object.
saveCurrentSolution($active_id, $pass, $value1, $value2, $authorized=true, $tstamp=null)
getObjId()
Get the object id of the container object.
setTitle($title="")
Sets the title string of the assQuestion object.
setOwner($owner="")
Sets the creator/owner ID of the assQuestion object.
setEstimatedWorkingTime($hour=0, $min=0, $sec=0)
Sets the estimated working time of a question from given hour, minute and second.
buildImagePath($questionId, $parentObjectId)
static logAction($logtext="", $active_id="", $question_id="")
Logs an action into the Test&Assessment log.
getImagePath($question_id=null, $object_id=null)
Returns the image path for web accessable images of a question.
removeCurrentSolution($active_id, $pass, $authorized=true)
setAuthor($author="")
Sets the authors name of the assQuestion object.
static isFileAvailable($file)
setShuffler(ilArrayElementShuffler $shuffler)
getTitle()
Gets the title string of the assQuestion object.
setPoints($a_points)
Sets the maximum available points for the question.
setComment($comment="")
Sets the comment string of the assQuestion object.
setNrOfTries($a_nr_of_tries)
getQuestion()
Gets the question string of the question object.
setAdditionalContentEditingMode($additinalContentEditingMode)
setter for additional content editing mode for this question
setQuestion($question="")
Sets the question string of the question object.
static _getLogLanguage()
retrieve the log language for assessment logging
static _enabledAssessmentLogging()
check wether assessment logging is enabled or not
static _getMobsOfObject($a_type, $a_id, $a_usage_hist_nr=0, $a_lang="-")
get mobs of object
static _getPass($active_id)
Retrieves the actual pass of a given user for a given test.
static _replaceMediaObjectImageSrc($a_text, $a_direction=0, $nic=IL_INST_ID)
Replaces image source from mob image urls with the mob id or replaces mob id with the correct image s...
Base Exception for all Exceptions relating to Modules/Test.
Class ilUserQuestionResult.
static delDir($a_dir, $a_clean_only=false)
removes a dir and all its content (subdirs and files) recursively
static convertImage( $a_from, $a_to, $a_target_format="", $a_geometry="", $a_background_color="")
convert image
static rCopy($a_sdir, $a_tdir, $preserveTimeAttributes=false)
Copies content of a directory $a_sdir recursively to a directory $a_tdir.
static sendFailure($a_info="", $a_keep=false)
Send Failure Message to Screen.
static makeDirParents($a_dir)
Create a new directory and all parent directories.
$def
Definition: croninfo.php:21
$key
Definition: croninfo.php:18
$i
Definition: disco.tpl.php:19
const MT_TERMS_DEFINITIONS
Class iQuestionCondition.
getUserQuestionResult($active_id, $pass)
Get the user solution for a question by active_id and the test pass.
Interface ilObjAnswerScoringAdjustable.
Interface ilObjQuestionScoringAdjustable.
$index
Definition: metadata.php:60
if($session===NULL) $postData
$query
if(!file_exists("$old.txt")) if( $old===$new) if(file_exists("$new.txt")) $file
global $ilDB
$mobs